views:

109

answers:

2

Here's my problem:

Say I have two entities annotated with JAX-RS annotations:

@XmlRootElement
@Entity
public Person {
  private String firstname;
  private String lastname;

  private Address address;
}

@XmlType
@Entity
public Address {
  private String street;
  private String city;
}

This will get rendered into:

<person>
  <firstname></firstname>
  <lastname></lastname>
  <address>
    <street></street>
   <city></city>
  </address>
</person>

My question therefore is:

Is it possible to annotate those entities so that the xml returned is:

<person>
  <firstname></firstname>
  <lastname></lastname>
  <street></street>
  <city></city>
</person>

i.e. properties of Address entity are treated as Person properties (without the enclosing tags)?

A: 

I'm not entirely sure why you would want to, but this might work (untested)

@XmlRootElement
@Entity
@XmlAccessorType(XmlAccessType.PROPERTY)
public Person {
   private String firstname;
   private String lastname;

   private Address address;

   // getter and setter for firstname/lastname

   @XmlTransient
   public Address getAddress() { return address; }

   public String getStreet() { return getAddress().getStreet(); }

   // more getters and setters
}

@XmlType
@Entity
public Address {
  private String street;
  private String city;

  // getters and setters
}

I personally would be using a DTO pattern at this point though. Mixing ORM and Serialization annotations is rarely a good thing.

Robert Wilson
Nope that didn't work. @XmlTransient makes the property be ignored when transformed to xml. I did initially create a set of classes annotated with just the jax-rs annotations, but then when I was fetching anything from the database, I had to copy all the properties from the @Entity annotated object to @Xml annotated object - seemed like an overkill, since all I wanted was to spit some xml. So in the end I ended up implementing a MessageBodyWriter which creates the xml I want - it is not as flexible as I wished, but it works. But thanks anyway.
Jakub
Well, the point of the code is that it makes 'Address' transient, and then includes the properties you want (perhaps you need an @XmlProperty).Seems to me that writing your own writer is more overkill than DTOs, but up to you.
Robert Wilson
A: 

You could do this using EclipseLink JAXB (MOXy). MOXy contains an annotation called @XmlPath, this is used to do XPath based mappings. The self XPath (".") will give you the desired effect:

@Entity 
@XmlAccessorType(XmlAccessType.PROPERTY) 
@XmlRootElement 
public Person { 
   private String firstname; 
   private String lastname; 
   private Address address; 

   // getter and setter for firstname/lastname 

   @XmlPath(".")
   public Address getAddress() { return address; } 

   public String getStreet() { return getAddress().getStreet(); } 

   // more getters and setters 
} 

For an example on using EclipseLink JAXB extensions see:

In order to use MOXy as your JAXB implementation you must add a jaxb.properties file in with your model classes with the following content:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

BTW, MOXy also has a number of extensions for handling JPA entities:

I have posted a series of examples to my blog on how to create a JPA based RESTful service using JAX-RS:

Blaise Doughan
Link to moxy at the top is dead.
Jakub
@Jakub - Thanks, I have corrected the link.
Blaise Doughan