[英]Using JAXB to pass subclass instances as superclass
我所擁有的是一組表示消息類型的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進行事務處理? 有關示例,請參見:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.