Java – passing subclass instances as superclasses using JAXB

I have a set of Java classes representing message types (close to 25) They all inherit the message class that they want to abstract Each message type adds some additional fields to the collection provided by the message superclass

I am using resteasy to implement some restful web services and hope to have such a method:

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();
}

Instead of using 25 separate persistence methods

At present, I have annotated my message class as follows:

@MappedSuperclass
@XmlRootElement(name = "message")
public abstract class Message implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Integer id;
    @Embedded
    Header header;
    @Embedded
    SubHeader subHeader;

My subclass looks like this:

@Entity
@XmlRootElement(name="regmessage")
@XmlAccessorType(XmlAccessType.FIELD)
public class REGMessage extends Message {

    @XmlElement(required = true)
    int statusUpdateRate;
    @XmlElement(required = true)
    int networkRegistrationFlag;

This creates a pattern that looks like it should work, but all patterns seen on the server side during the persistence operation are a message object (subtypes are completely missing, or at least not grouped back to their correct subtypes) On the client side, call the method and I do this:

REGMessage msg = new REGMessage();
// populate its fields
Response r = client.createMessage(msg);

What JAXB magic do I need to use to make translation happen the way they should - that is, treat all content in Java as messages to maintain the number of methods and still retain all subtype specific information?

Thanks to Blaise's blog guide, it seems to be working in full swing now This is what I've got, its work:

//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;

A problem I encountered this morning was an implicit error in Hibernate about column number mismatch Once I realize that the "body" is mapping to the table, I mark it as transient, look!

@XmlRootElement(name="regmessage")
@XmlAccessorType(XmlAccessType.FIELD)
@Entity
public class REGMessage extends Message {

    private int field1;
    private int field2;

Now, the only table that this code generates is the regmessage table In terms of 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();
    }
}

This implements an interface:

@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;

}

Marshalling & unmarshalling works as expected. Persistence is a subclass table (there is no superclass table at all)

I did see Blaise's notes on JTA. I can try to exit completely after completing the "message & regmessage" class

Solution

Are you trying to add the following to the message class@ The xmlseealso annotation will let jaxbcontext know about subclasses

import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;

@XmlRootElement
@XmlSeeAlso(RegMessage.class)
public abstract class Message {

    Integer id;

}

Alternative strategy:

This is a link to the strategies I help people use:

> http://bdoughan.blogspot.com/2010/08/using-xmlanyelement-to-build-generic.html

Essentially, you have a message object and multiple individual message payloads The relationship between the message and the payload is handled through the @ xmlanyelement annotation

Transaction processing description

I noticed that you are dealing with your own transaction Do you consider implementing the jax-rs service as a session bean and using JTA for transaction processing? For example:

> http://bdoughan.blogspot.com/2010/08/creating-restful-web-service-part-45.html

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>