ucas ucas - 3 months ago 31
reST (reStructuredText) Question

Taking advantage of GenericEntity in Jersey

I'm writing RESTful Web service in Java. The technologies that I use:


  • GlassFish 3 (based on Java 6)

  • JDK v7

  • Jersey (part of the application server)

  • Eclipse EE Kepler



The annotated POJO:

@XmlRootElement(name = "entity")
@XmlType(propOrder={"stValue", "dValue", "list"})
@XmlAccessorType(XmlAccessType.FIELD)
public final class EntityJAXBxml {

@XmlAttribute
private int id

= 0;
@XmlElement
private String stValue = "";
@XmlElement
private double dValue = 0.0;
@XmlElement
@XmlElementWrapper(name="elements")
private List<Integer> list = null;

public EntityJAXBxml(){}

public EntityJAXBxml(int id, String stValue, double dValue,
List<Integer> list) {
super();
this.id = id;
this.stValue = stValue;
this.dValue = dValue;
this.list = list;
}
... Getters, setters


That's my service method:

@GET
@Produces(MediaType.APPLICATION_XML)
@Path("/receiveXMLInGenericEntity")
public Response receiveXMLInGenericEntity(){
EntityJAXBxml entity = new EntityJAXBxml(1, "String_value", 193.7, util.generateIntList());
EntityJAXBxml entity_1 = new EntityJAXBxml(2, "New_string_value", 439.5, util.generateIntList());

List<EntityJAXBxml> list = new ArrayList<>(2);
list.add(entity);
list.add(entity_1);

GenericEntity<List<EntityJAXBxml>> generic = new GenericEntity<List<EntityJAXBxml>>(list){};
return Response.ok().entity(generic).build();
}


When I access the resource via URI on the Web browser, it prints the XML document. Thus, so far it works fine.
Problems come in when I want to get the response from the service via non-browser client.
For example, the following is my client implementation:

private void receiveXMLInGenericEntity(String strUrl, String method){
HttpURLConnection connect = null;
try {
URL url = new URL(strUrl);
connect = (HttpURLConnection)url.openConnection();

connect.setRequestProperty("Accept", MediaType.APPLICATION_XML);// Accept from server
connect.setRequestMethod(method);//GET

connect.connect();
Class cls = new GenericEntity<List<EntityJAXBxml>>(new ArrayList<EntityJAXBxml>()){}.getClass();

GenericEntity<List<EntityJAXBxml>> generic = (GenericEntity<List<EntityJAXBxml>>)JAXB.unmarshal(connect.getInputStream(), cls);
List<EntityJAXBxml> entity = generic.getEntity();

System.out.println("GenericEntity: "+entity.size());
}
catch(IOException e){ e.printStackTrace();}
}


And it gives me the following exception:

Exception in thread "main" javax.xml.bind.DataBindingException: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
drill.rest.client.ClientXmlV6$1 is a non-static inner class, and JAXB can't handle those.
this problem is related to the following location:
at drill.rest.client.ClientXmlV6$1

at javax.xml.bind.JAXB.unmarshal(JAXB.java:226)
at drill.rest.client.ClientXmlV6.receiveXMLInGenericEntity(ClientXmlV6.java:199)
at drill.rest.client.ClientXmlV6.main(ClientXmlV6.java:68)
Caused by: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
drill.rest.client.ClientXmlV6$1 is a non-static inner class, and JAXB can't handle those.
this problem is related to the following location:
at drill.rest.client.ClientXmlV6$1

at com.sun.xml.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:106)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:466)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:298)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:141)
at com.sun.xml.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1163)
at com.sun.xml.bind.v2.ContextFactory.createContext(ContextFactory.java:145)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:248)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:235)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:432)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:637)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584)
at javax.xml.bind.JAXB$Cache.<init>(JAXB.java:112)
at javax.xml.bind.JAXB.getContext(JAXB.java:139)
at javax.xml.bind.JAXB.unmarshal(JAXB.java:223)
... 2 more


That means that the following way of getting
Class
type value is wrong:

Class cls = new GenericEntity<List<EntityJAXBxml>>(new ArrayList<EntityJAXBxml>()){}.getClass();


But I need that type value, because it's needed input at the following method:

JAXB.unmarshal()


Now, here it comes my second version of client, and now taking advantage of Jersey client API:

private void receiveXMLInGenericEntityJerseyClient(String strUrl, String method){
Client client = Client.create();
WebResource resource = client.resource(strUrl);

resource.accept(MediaType.APPLICATION_XML);
resource.method(method);

GenericType type = new GenericType(new ArrayList<EntityJAXBxml>(Collections.EMPTY_LIST).getClass()){};
GenericEntity<List<EntityJAXBxml>> generic = resource.get(type);
}


It comes with this exception:

Aug 12, 2016 6:45:48 PM com.sun.jersey.api.client.ClientResponse getEntity
SEVERE: A message body reader for Java class java.util.ArrayList, and Java type class java.util.ArrayList, and MIME media type application/xml was not found
Aug 12, 2016 6:45:48 PM com.sun.jersey.api.client.ClientResponse getEntity
SEVERE: The registered message body readers compatible with the MIME media type are:
application/xml ->
com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$App
com.sun.jersey.core.impl.provider.entity.DocumentProvider
com.sun.jersey.core.impl.provider.entity.SourceProvider$StreamSourceReader
com.sun.jersey.core.impl.provider.entity.SourceProvider$SAXSourceReader
com.sun.jersey.core.impl.provider.entity.SourceProvider$DOMSourceReader
com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$App
com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$App
com.sun.jersey.core.impl.provider.entity.XMLRootObjectProvider$App
*/* ->
com.sun.jersey.core.impl.provider.entity.FormProvider
com.sun.jersey.core.impl.provider.entity.MimeMultipartProvider
com.sun.jersey.core.impl.provider.entity.StringProvider
com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
com.sun.jersey.core.impl.provider.entity.FileProvider
com.sun.jersey.core.impl.provider.entity.InputStreamProvider
com.sun.jersey.core.impl.provider.entity.DataSourceProvider
com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General
com.sun.jersey.core.impl.provider.entity.ReaderProvider
com.sun.jersey.core.impl.provider.entity.DocumentProvider
com.sun.jersey.core.impl.provider.entity.SourceProvider$StreamSourceReader
com.sun.jersey.core.impl.provider.entity.SourceProvider$SAXSourceReader
com.sun.jersey.core.impl.provider.entity.SourceProvider$DOMSourceReader
com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$General
com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General
com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General
com.sun.jersey.core.impl.provider.entity.XMLRootObjectProvider$General
com.sun.jersey.core.impl.provider.entity.EntityHolderReader
com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$General
com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$General
com.sun.jersey.moxy.MoxyMessageBodyWorker
com.sun.jersey.moxy.MoxyListMessageBodyWorker

Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class java.util.ArrayList, and Java type class java.util.ArrayList, and MIME media type application/xml was not found
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:550)
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:524)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:686)
at com.sun.jersey.api.client.WebResource.get(WebResource.java:196)
at drill.rest.client.ClientXmlV6.receiveXMLInGenericEntityJerseyClient(ClientXmlV6.java:216)
at drill.rest.client.ClientXmlV6.main(ClientXmlV6.java:69)


In the end, what I want is just to read the output from the service at my client-end-point. I want to use the
GenericEntity
object in order to have better understanding of Jersey/Java EE ins-and-outs.
Any ideas how to get around this problem?

Answer

Here you go, that is a solution, at least in terms of jersey-client.jar API. I needed to add the following lines:

List<EntityJAXBxml> g = resource.get(new GenericType<List<EntityJAXBxml>>(){});
    EntityJAXBxml entity = g.get(1);
    System.out.println(g.size()+" : "+entity.getdValue()+" : Element count: "+entity.getList().size());
    //Also valid
    //ClientResponse response = resource.get(ClientResponse.class);
    //List<EntityJAXBxml> entity = response.getEntity(new GenericType<List<EntityJAXBxml>>(){});

    //EntityJAXBxml g = entity.get(1);
    //System.out.println(entity.size()+" : "+g.getdValue()+" : Element count: "+g.getList().size());

And then you can read generic entity at the client side.