2

Good Morning. Today morning when I am going through Jersey Entity providers MessageBodyReaders and MessageBodyWriters I came across the following problem.

I want to write a resource method and client that returns a list of custom objects and media type is application/xml. So I would like to use JAXB (I am new to JAXB). I was able to achieve this by writing my own extended MessageBodyReader and MessageBodyWriter. But I am afraid of the way I am following. Just look at the way I implemented:

Resource method:

@Path("productlist/xml")
@GET
public RetObjects getProductsXml(){
    List<Product> pList = new ArrayList<Product>();
    pList.add(new Product("1","Dell latitude E6000",2900,500));
    pList.add(new Product("2","Xperia Z2",549,400));
    RetObjects obj = new RetObjects();
    obj.setObject(pList);
    return obj;
}

My custom objects:

@Entity
@Table (name="PRODUCT")
@XmlRootElement(name="product")
public class Product {

    @Id
    @Column(name = "CODE")
    private String code;
    ...
    // rest of the fields, constructors, getters and setters
 }

Object that wraps my list of custom object:

 @XmlRootElement(name = "products")
 @XmlAccessorType (XmlAccessType.FIELD)
 public class RetObjects {

     @XmlElement(name = "product")
     private List<Product> object = null;

     public List<Product> getObject() {
         return object;
     }

     public void setObject(List<Product> object) {
         this.object = object;
     }
 }

MessageBodyReader/Writer are straight forward just using Jaxb unmarshaller and marshaller over the RetObjects object.

With this implementation it is working fine as expected and i am able to fetch the RetObjects wrapping the list of Products perfectly fine at client.

Here my question is, instead of wrapping my List of Products into a intermediate object, RetObjects in my case, couldn't I marshal and unmarshal List of Products object directly. If I want to write another service that returns List of Orders, I need to wrap this with one more intermediate object. What is the right approach to achieve this? How could I do this without intermediate objects?

Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
HJK
  • 1,382
  • 2
  • 9
  • 19

1 Answers1

9

First

You don't need your own MessageBodyWriter/Reader. Jersey/JAX-RS alread has standard support for this. I would stick with the default, unless you have a really, really good reason for needed to whip up your own.

Second

We don't need the wrapper, you can simple return a GenericEntity. This will automatically wrap the elements in a "plural wrapper" element, i.e. <product> -> <products>.

List<Product> list = new ArrayList<>();
GenericEntity<List<String>> entity = new GenericEntity<List<Product>>(list) {};
Response response = Response.ok(entity).build();

For accepting a body in resource method, simply accepting List<Product> as an argument is enough. It will accept <products><product/><product/></products>


UPDATE

To retrieve the List<Product> on the client side, we should make use of GenericType. Se this post.

Jersey 1

WebResource resource = client.resource("...");
List<Product> products = resource.get(new GenericType<List<Product>>(){});

Jersey 2/JAX-RS 2

Response response = ...
List<Product> products = response.readEntity(new GenericType<List<Product>>(){});
Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • WRT second point, you are true @peeskillet. When i am doing this, as you said I am getting . In this case how could I consume at client side in Java POJO objects? – HJK Dec 25 '14 at 04:24
  • I am not able to do response.readEntity(new RetObject2>(){}); I am getting compilation error saying readEntity(Class) is not applicable for readEntity(RetObject2>(){}). Here RetObject2 is a new generic class like RetObject2 with one field of type T. Could you elaborate a bit. – HJK Dec 25 '14 at 05:14
  • Why Are you using `RepObject2`? It should be `GenericType` – Paul Samsotha Dec 25 '14 at 05:15
  • The whole point of your question is to get rid of the wrapper object isn't it? – Paul Samsotha Dec 25 '14 at 05:19
  • There is an overloaded [`readEntity`](http://docs.oracle.com/javaee/7/api/javax/ws/rs/core/Response.html#readEntity%28javax.ws.rs.core.GenericType%29) which takes a `GenericType` argument. – Paul Samsotha Dec 25 '14 at 05:20
  • See [`javax.ws.rs.core.GenericType`](http://docs.oracle.com/javaee/7/api/javax/ws/rs/core/GenericType.html). It's an actual class. You are not supposed to provide your own "Generic type" :-) Sorry if I did not make that clear initially. – Paul Samsotha Dec 25 '14 at 05:22
  • Thanks Peeskillet. Its working fine. I thought genericType is the abstract name you gave. – HJK Dec 25 '14 at 05:43
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/67653/discussion-between-user3694267-and-peeskillet). – HJK Dec 25 '14 at 05:47