Marshal/Un marshal List objects in Jersey JAX-RS using JAXB
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>>(){});
HJK
Updated on June 04, 2022Comments
-
HJK almost 2 years
Good Morning. Today morning when I am going through Jersey Entity providers
MessageBodyReader
s andMessageBodyWriter
s 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 extendedMessageBodyReader
andMessageBodyWriter
. 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 theRetObjects
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? -
HJK over 9 yearsWRT second point, you are true @peeskillet. When i am doing this, as you said I am getting <products><product></product></products>. In this case how could I consume at client side in Java POJO objects?
-
HJK over 9 yearsI am not able to do response.readEntity(new RetObject2<List<Product>>(){}); I am getting compilation error saying readEntity(Class<T>) is not applicable for readEntity(RetObject2<List<Product>>(){}). Here RetObject2 is a new generic class like RetObject2<T> with one field of type T. Could you elaborate a bit.
-
Paul Samsotha over 9 yearsWhy Are you using
RepObject2
? It should beGenericType
-
Paul Samsotha over 9 yearsThe whole point of your question is to get rid of the wrapper object isn't it?
-
Paul Samsotha over 9 yearsThere is an overloaded
readEntity
which takes aGenericType
argument. -
Paul Samsotha over 9 yearsSee
javax.ws.rs.core.GenericType
. It's an actual class. You are not supposed to provide your own "Generic type" :-) Sorry if I did not make that clear initially. -
HJK over 9 yearsThanks Peeskillet. Its working fine. I thought genericType is the abstract name you gave.
-
HJK over 9 yearsLet us continue this discussion in chat.