Frage JAX-RS Jersey Client Marshaling JSON Antwort mit POJO MAPPING & Jackson


Ich habe ein Problem mit dem Jersey-Client (1.11), bei dem JSONConfiguration.FEATURE_POJO_MAPPING auf "true" gesetzt ist. Mein Testcode sieht so aus:

MyFooCollectionWrapper<MyFooDTO> resp
    = webResource.accept(MediaType.APPLICATION_JSON)
      .get(new GenericType<MyFooCollectionWrapper<MyFooDTO>>() {});

Auf dem Server:

1) Meine web.xml hat POJO Mapping auf True gesetzt.

2) MyFooDTO ist einfach ein POJO, das so aussieht:

public class MyFooDTO {

private long id;
private String propA;

pubic long getId() {
    return id;
}
public void setId(long id) {
    this.id = id;
}

pubic String getPropA() {
    return propA;
}
public void setPropA(String propA) {
    this.propA = propA;
}

public MyFooDTO(MyFoo aFoo) {
    this.id = aFoo.getId();
    this.propA = aFoo.getPropA();
}

    public MyFooDTO() {}

}

3) MyFooCollectionWrapper sieht folgendermaßen aus:

public class MyFooCollectionWrapper<T> extends MyFooCollectionWrapperBase {

    Collection<T> aCollection;

    public MyFooCollectionWrapper() {
        super();
    }

    public MyFooCollectionWrapper(boolean isOK, String msg, Collection<T> col) {
        super(isOK, msg);
        this.aCollection = col;
    }

    public void setCollection(Collection<T> collection) {
        this.aCollection = collection;
    }

    @JsonProperty("values")
    public Collection<T> getCollection() {
        return aCollection;
    }
}

public class MyFooCollectionWrapperBase {

    private boolean isOK;
    private String message;

    public MyFooCollectionWrapperBase() {
        this.message = "";
        this.isOK = false;
    }

    public MyFooCollectionWrapperBase(boolean ok, String msg) {
        this.isOK = ok;
        this.message = msg;
    }

    .. standard getter/setters ..

}

Ich habe überprüft, Server hat kein Problem beim Erstellen der JSON-Antwort. Ich kann mit meinem Jersey-Client-Code abrufen, wenn ich den Antworttyp auf String festlegen. Wenn ich benutze

MyFooCollectionWrapper<MyFooDTO> resp = webResource.accept(MediaType.APPLICATION_JSON).get(new GenericType<MyFooCollectionWrapper<MyFooDTO>>() {});

Ich würde erwarten, dass POJO-Mapping einfach funktioniert (marshall the response), ohne dass ein benutzerdefinierter Body Reader benötigt wird. Ich bekomme jedoch:

Jun 04, 2012 3:02:20 PM com.sun.jersey.api.client.ClientResponse getEntity
SEVERE: A message body reader for Java class com.foo.MyFooCollectionWrapper, and Java type     com.foo. MyFooCollectionWrapper<com.foo.MyFooDTO>, and MIME media type application/json was not found
Jun 04, 2012 3:02:20 PM com.sun.jersey.api.client.ClientResponse getEntity
SEVERE: The registered message body readers compatible with the MIME media type are:
application/json ->
com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$App
com.sun.jersey.json.impl.provider.entity.JSONArrayProvider$App
com.sun.jersey.json.impl.provider.entity.JSONObjectProvider$App
com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$App
com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$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.json.impl.provider.entity.JSONArrayProvider$General
com.sun.jersey.json.impl.provider.entity.JSONObjectProvider$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.json.impl.provider.entity.JacksonProviderProxy
com.sun.jersey.moxy.MoxyMessageBodyWorker
com.sun.jersey.moxy.MoxyListMessageBodyWorker


com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class com.foo.MyFooCollectionWrapper, and Java type com.foo. MyFooCollectionWrapper<com.foo. MyFooDTO>, and MIME media type application/json 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.access$300(WebResource.java:74)
  at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:508)

Der Klassenpfad auf dem clientseitigen Test enthält:

jersey-test-framework-core-1.11.jar 
jersey-test-framework-embedded-glassfish-1.11.jar 
jersey-test-framework-grizzly-1.11.jar 
jersey-test-framework-http-1.11.jar 
jersey-test-framework-inmemory-1.11.jar 
jackson-core-asl.jar 
jackson-jaxrs.jar 
jackson-xc.jar 
jackson-client.jar 
jersey-client.jar 
jersey-core.jar 
jersey-json.jar 
jettison.jar

Sind meine Erwartungen falsch oder fehlt mir hier etwas Offensichtliches?

Als Nebenbemerkung, wenn ich JAXB-Annotationen zu meinen Entitäten hinzufügen (@ XmlRootElement auf MyFooCollectionWrapper und MyFooDTO) die Verwendung der gleichen WebResource Get-Aufruf, der Client bekomme ich keine Nachricht Body Reader-Ausnahme, jedoch wird die Antwort so gemarshallt, dass MyFooCollectionWrapper sieht gut aus, aber seine Sammlung enthält kein MyFooDTO, es enthält ein XML-Dokument mit den richtigen Werten in den Knoten / attrs - mit anderen Worten MyFooDTP wird nicht gemarshallt.

Wenn ich java.util.logging auf CONFIG setze, wie es in einer Antwort vorgeschlagen wurde, sehe ich folgendes, obwohl mir nichts in den Sinn kommt. Hier ist ein Verknüpfung zu der Ausgabe, die ich Pastebin wegen der Länge anlegte.

Vielen Dank,

-Noah

UPDATE - Gelöst

Ursprünglich wurde meine Client- und Client-Konfiguration wie folgt erstellt:

Client rootClient = new Client();
ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
Client client = new Client(rootClient, clientConfig);

Als ich das einfach geändert habe

    ClientConfig clientConfig = new DefaultClientConfig();
    clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
    Client client = Client.create(clientConfig);

Die Dinge haben funktioniert. Es scheint, dass der rootClient die clientConfig auf dem neuen Client überschrieben hat. Es ist seltsam, dass wenn Sie einen Konstruktor verwenden, der eine ClientConfig angibt, die ClientConfig von der rootClients-Konfiguration überschrieben wird.


5
2018-06-07 02:43


Ursprung


Antworten:


Um das POJO-Mapping auf der Client-Seite zu aktivieren, tun Sie Folgendes:

ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
Client client = Client.create(clientConfig);

6
2018-06-11 10:25



Ich glaube es ist weil MyFooDTO hat keinen no-arg-Konstruktor.

Wenn Sie die Ebene java.util.logging bis zu ändern CONFIGsollten Sie eine Reihe zusätzlicher Nachrichten sehen, die bei der Diagnose solcher Probleme helfen.


0
2018-06-19 14:03



Weißt du, was ich einfacher finde?

MyFooDTO[] resp = webResource.accept(MediaType.APPLICATION_JSON).get(MyFooDTO[].class);

Durch die Verwendung eines Array-Typs weiß der Marshaller genau, welchen Typ Sie verwenden möchten und weiß, dass es sich um eine Sammlung handelt. Sie erhalten nicht die gesamte Funktionalität einer Legit-Sammlung, aber Sie können sie sofort iterieren und streamen.


0
2018-02-12 18:48



Sie können das POJO-Mapping auf Client-Seite wie unten gezeigt aktivieren

            ClientConfig clientConfig = new DefaultClientConfig();
            clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
            Client client = Client.create(clientConfig);

            WebResource webResource = client
                    .resource("http://localhost:8080/api/url");

            ClientResponse response = webResource.accept("application/json")
                    .get(ClientResponse.class);

            if (response.getStatus() != 200) {
                throw new RuntimeException("Failed : HTTP error code : "
                        + response.getStatus());
            }

            POJOObject output = response.getEntity(POJOObject.class);

Falls Sie eine Liste von Objekten als Antwort haben, können Sie dies tun

            List<POJOObject> pojoList = webResource.get(new GenericType<List<POJOObject>>() { });

Sie müssen diese Abhängigkeiten verwenden

    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-client</artifactId>
        <version>1.18.1</version>
    </dependency>

    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>1.18.1</version>
    </dependency>

0
2017-07-10 10:44