在泽西岛利用 GenericEntity

Taking advantage of GenericEntity in Jersey

我正在 Java 中编写 RESTful Web 服务。我使用的技术:

带注释的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

这是我的服务方式:

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

当我在 Web 浏览器上通过 URI 访问资源时,它会打印 XML 文档。因此,到目前为止它工作正常。 当我想通过非浏览器客户端从服务获取响应时,问题就来了。 比如下面是我的客户端实现:

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

它给了我以下异常:

 Exception in thread "main" javax.xml.bind.DataBindingException: com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
drill.rest.client.ClientXmlV6 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

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

    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

这意味着下面获取Class类型值的方式是错误的:

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

但是我需要那个类型的值,因为需要在下面的方法中输入:

JAXB.unmarshal()

现在,我的第二版客户端来了,现在利用 Jersey 客户端 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);
}

它有这个例外:

    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)

最后,我想要的只是在我的客户端读取服务的输出。我想使用 GenericEntity 对象以便更好地理解 Jersey/Java EE 的来龙去脉。 有什么想法可以解决这个问题吗?

给你,这是一个解决方案,至少在球衣方面-client.jar API。 我需要添加以下行:

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

然后就可以在客户端读取通用实体了。