У меня есть набор классов Java (около 25), представляющих типы сообщений. Все они наследуются от класса Message, который я хотел бы назвать абстрактным. Каждый тип сообщения добавляет несколько дополнительных полей к набору, предоставляемому суперклассом Message.
Я реализую некоторые веб-сервисы RESTful с использованием RESTeasy и хотел бы иметь такие методы:
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 отдельных постоянных методов, каждый из которых предназначен для определенного типа сообщения.
В настоящее время я аннотировал свой класс сообщений следующим образом:
@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, как если бы это было Message, чтобы уменьшить количество методов и в то же время сохранить всю информацию, относящуюся к подтипу?
Благодаря указателям блога Блеза теперь похоже, что он находится на пути к полной работе. Вот что у меня есть, и оно работает:
//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 о несоответствии количества столбцов. Как только я поняла, что «тело» отображается на столе, я пометила его как временное и вуаля!
@XmlRootElement(name="regmessage")
@XmlAccessorType(XmlAccessType.FIELD)
@Entity
public class REGMessage extends Message {
private int field1;
private int field2;
Единственная таблица, сгенерированная из этого кода, теперь является таблицей регулярных сообщений. На стороне 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;
}
Маршаллинг и демаршаллинг работают должным образом, а постоянство - к таблице подкласса (а таблицы суперкласса вообще нет).
Я видел заметку Блейза о JTA, которую я могу попытаться внести в этот микс после того, как закончу полностью возвращать классы Message & REGMessage.