我所拥有的是一组表示消息类型的Java类(接近25个)。它们都继承自我想抽象的Message类。每种消息类型都会在Message超类提供的集合中添加一些其他字段。
我正在使用RESTeasy实现一些RESTful Web服务,并希望具有以下方法:
public Response persist(Message msg) { EntityTransaction tx = em.getTransaction(); tx.begin(); try { em.persist(msg); } catch (Exception e) { e.printStackTrace(); } tx.commit(); em.close(); return Response.created(URI.create("/message/" + msg.getId())).build(); }
而不是使用25种单独的persist方法,每种方法都针对特定的消息类型进行了量身定制。
目前,我已经为Message类添加了如下注释:
@MappedSuperclass @XmlRootElement(name = "message") public abstract class Message implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) Integer id; @Embedded Header header; @Embedded SubHeader subHeader;
然后,我的子类如下所示:
@Entity @XmlRootElement(name="regmessage") @XmlAccessorType(XmlAccessType.FIELD) public class REGMessage extends Message { @XmlElement(required = true) int statusUpdateRate; @XmlElement(required = true) int networkRegistrationFlag;
这样会创建一个 看起来 应该工作的架构,但是在持久化操作期间在服务器端看到的只是一个Message对象(该子类型已完全丢失,或者至少没有被整理回其正确的子类型)。在客户端,要调用该方法,我需要这样做:
REGMessage msg = new REGMessage(); // populate its fields Response r = client.createMessage(msg);
我正在尝试的可能吗?我需要使用什么JAXB魔术来使转换按应有的方式发生-即,将Java中的所有内容都视为一条消息,以减少方法数量,但仍保留所有特定于子类型的信息?
多亏了Blaise的博客提示,现在看来,它正在全面工作。这是我所拥有的,并且确实有效:
//JAXB annotations @XmlRootElement(name="message") @XmlAccessorType(XmlAccessType.FIELD) @XmlSeeAlso(REGMessage.class) //JPA annotations @MappedSuperclass public class Message { @Id @GeneratedValue(strategy = GenerationType.AUTO) @XmlAttribute private Integer id; private JICDHeader header; private int subheader; @XmlAnyElement @Transient private Object body;
今天早上我遇到的问题之一是Hibernate的一个不正确的错误,即列数不匹配。一旦我意识到“ body”已映射到表中,就将其标记为瞬态和瞧!
@XmlRootElement(name="regmessage") @XmlAccessorType(XmlAccessType.FIELD) @Entity public class REGMessage extends Message { private int field1; private int field2;
现在,从此代码生成的唯一表是regmessage表。在RESTeasy方面:
@Path("/messages") public class MessageResource implements IMessageResource { private EntityManagerFactory emf; private EntityManager em; Logger logger = LoggerFactory.getLogger(MessageResource.class); public MessageResource() { try { emf = Persistence.createEntityManagerFactory("shepherd"); em = emf.createEntityManager(); } catch (Exception e) { e.printStackTrace(); } } @Override @POST @Consumes("application/xml") public Response saveMessage(Message msg) { System.out.println(msg.toString()); logger.info("starting saveMessage"); EntityTransaction tx = em.getTransaction(); tx.begin(); try { em.persist(msg); } catch (Exception e) { e.printStackTrace(); } tx.commit(); em.close(); logger.info("ending saveMessage"); return Response.created(URI.create("/message/" + msg.getId())).build(); } }
这实现了一个接口:
@Path("/messages") public interface IMessageResource { @GET @Produces("application/xml") @Path("{id}") public Message getMessage(@PathParam("id") int id); @POST @Consumes("application/xml") public Response saveMessage(Message msg) throws URISyntaxException; }
编组和解组工作按预期进行,并且持久性属于子类的表(并且根本没有超类表)。
我确实看到了Blaise关于JTA的说明,在我完全充实了Message&REGMessage类后,我可能会尝试将其引入。
您是否尝试过将以下内容添加到您的消息类别中?@XmlSeeAlso批注将使JAXBContext知道子类。
import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlSeeAlso; @XmlRootElement @XmlSeeAlso(RegMessage.class) public abstract class Message { Integer id; }
替代策略:
这是我帮助人们使用的策略的链接:
本质上,您有一个消息对象和多个单独的消息有效负载。消息和有效负载之间的关系通过@XmlAnyElement批注处理。
交易处理注意事项
我注意到您正在处理自己的交易。您是否考虑过将JAX-RS服务实现为会话bean,并利用JTA进行事务处理?有关示例,请参见: