2010-12-01 5 views
3

Ich versuche, eine Spielzeuganwendung einzurichten (die sich irgendwann in eine echte Anwendung verwandeln kann). Ich stoße auf ein Problem mit Wink und Jackson. Ich habe zwei Anwendungen: einer läuft wink-server auf dem Steg und scheint mir ein paar JSON-Daten zu liefern; man läuft wink-client an jetty und erhält die jSON-daten ganz gut. Das Problem liegt in der automatischen Deserialisierung der JSON-Daten in meine Java-Bean.Wie registriere ich den Jackson-Anbieter mit dem Wink-Client?

Hier ist der Code, den ich in meinem Zwinkern Client-Aktion verwenden:

RestClient client = new RestClient(); 
Resource resource = client.resource("http://localhost:8081/helloworld"); 
User user = resource.accept(MediaType.APPLICATION_JSON).get(User.class); 

Hier ist der Fehler, den ich erhalte, wenn ich versuche, die Struts Aktion auszuführen:

java.lang.RuntimeException: No javax.ws.rs.ext.MessageBodyReader found for type class my.package.structure.User and media type application/json. Verify that all entity providers are correctly registered. 
org.apache.wink.client.internal.handlers.ClientResponseImpl.readEntity(ClientResponseImpl.java:123) 
org.apache.wink.client.internal.handlers.ClientResponseImpl.getEntity(ClientResponseImpl.java:65) 
org.apache.wink.client.internal.handlers.ClientResponseImpl.getEntity(ClientResponseImpl.java:52) 
org.apache.wink.client.internal.ResourceImpl.invoke(ResourceImpl.java:186) 
org.apache.wink.client.internal.ResourceImpl.get(ResourceImpl.java:294) 
my.package.structure.action.HelloWorldAction.execute(HelloWorldAction.java:29) 
... 

Wenn ich die letzte Zeile ersetzen in das erste Code-Snippet mit der folgenden Zeile, alles funktioniert gut und Dandy.

String message = resource.accept(MediaType.APPLICATION_JSON).get(String.class); 
ObjectMapper mapper = new ObjectMapper(); 
User user = mapper.readValue(message, User.class); 

Es ist klar, dass die Daten über ganz gut bekommen, aber das Problem scheint darin zu liegen, dass die JacksonJsonProvider Klasse nicht mit Wink-Client registriert ist. Ich habe viele Möglichkeiten gesehen, den Provider mit dem Wink-Server zu registrieren, aber nicht mit dem Wink-Client.

Ist es möglich, dass das erste Code-Snippet ordnungsgemäß funktioniert? Wenn das so ist, wie?

(Nebenbei bemerkt, kann das andere Problem, dass ich auf meine Anmerkungen User-Klasse fehlt bin. Im Moment gibt keine sind. Vielleicht sind einige ich brauche ...)

Antwort

7

Schritt 1: Erstellen Sie eine Klasse, die javax.ws.rs.core.Application erweitert, mit der Sie Singletons festlegen können.

import java.util.Collections; 
import java.util.Set; 
import javax.ws.rs.core.Application; 

public class ClientApplication extends Application { 

    private Set<Object> singletons = Collections.emptySet(); 

    @Override 
    public Set<Object> getSingletons() { 
     return singletons; 
    } 

    public void setSingletons(final Set<Object> singletons) { 
     this.singletons = singletons; 
    } 
} 

Schritt 2: In Ihrer Aktion, ein org.apache.wink.client.ClientConfig für Ihre org.apache.wink.client.RestClient erstellen. Auf diese Weise können Sie die org.codehaus.jackson.jaxrs.JacksonJsonProvider Ihrer Providerliste hinzufügen.

ClientApplication clientApplication = new ClientApplication(); 
Set<Object> s = new HashSet<Object>(); 
s.add(new JacksonJsonProvider()); 
clientApplication.setSingletons(s); 
ClientConfig clientConfig = new ClientConfig().applications(clientApplication); 
RestClient restClient = new RestClient(clientConfig); 

Schritt 3: Erstellen Sie die org.apache.wink.client.Resource, verwenden Sie die get(Class<T> responseEntity) Methode und alles wird jetzt wie erwartet.

Resource resource = client.resource("http://localhost:8081/helloworld"); 
User user = resource.accept(MediaType.APPLICATION_JSON).get(User.class); 

Wenn Sie wirklich glatt über sie sein wollen, können Sie Frühling verwenden, um eine ClientConfig Bohne einzurichten und zu injizieren sie in auf Ihre Aktionen. Dann können Sie einfach jedes Mal new RestClient(clientConfig) anrufen und sich nicht darum kümmern, das gesamte Setup zu replizieren.

+0

Das ist nicht für mich zu arbeiten. Meine Klassen haben Jaxb-Annotationen und der Systemanwendungsanbieter scheint sich mit dem jackson-json-Provider zu befassen. Die Lösung bestand darin, setLoadWinkApplications (false) in der ClientConfig aufzurufen, bevor die Anwendungen festgelegt wurden. – kldavis4

0

Ich wünschte, ich könnte helfen mit Registrierung; Aber in Bezug auf Anmerkungen, glaube ich nicht, dass Sie irgendjemand brauchen sollten, um zu versuchen, den Wert zu deserialisieren. Wenn Sie etwas verpassen, das Sie brauchen, würden Sie eine andere Art von Ausnahme bekommen.

2

Ich stieß auf dieses Problem beim Versuch, einige Integrationstests zu schreiben, die ein Objekt für mein Rest-Plugin POST.

Anstatt eine neue Klasse auszugeben, können Sie dem Jackson-Anbieter eine Inline-Klasse zur Verfügung stellen.

@Before 
public void setup(){ 

    javax.ws.rs.core.Application app = new javax.ws.rs.core.Application() { 
     public Set<Class<?>> getClasses() { 
      Set<Class<?>> classes = new HashSet<Class<?>>(); 
      classes.add(JacksonJaxbJsonProvider.class); 
      return classes; 
     } 

    }; 
    //create auth handler 
    clientConfig = new ClientConfig(); 
    clientConfig.applications(app); 
    BasicAuthSecurityHandler basicAuthSecurityHandler = new BasicAuthSecurityHandler(); 
    basicAuthSecurityHandler.setUserName(USERNAME); 
    basicAuthSecurityHandler.setPassword(PASSWORD); 
    clientConfig.handlers(basicAuthSecurityHandler); 
    //create client usin auth and provider 
    client = new RestClient(clientConfig); 

} 

Dann können Sie Ihre kommentierten Objekte veröffentlichen und konsumieren.

@Test 
public void aReadWriteTokenCanBeCreatedAsRequested(){ 
    ClientResponse response = client.resource(resourceUrlToken).contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON).post(readAndWriteToken); 
    assertEquals("Could not create token needed for test",200,response.getStatusCode()); 
    readAndWriteToken = response.getEntity(TokenResource.class); 
    assertNotNull("Returned token does not have UUID",readAndWriteToken.getUuid()); 

} 

Wenn Sie Maven verwenden Sie sicher, dass Jackson ist auf dem Test Classpath (Prüfung auf kompatible Versionen) machen:

<!-- TEST DEPENDENCIES --> 
    <dependency> 
    <groupId>org.codehaus.jackson</groupId> 
    <artifactId>jackson-core-asl</artifactId> 
    <version>1.9.1</version> 
    <scope>test</scope> 
    </dependency> 
    <dependency> 
    <groupId>org.codehaus.jackson</groupId> 
    <artifactId>jackson-jaxrs</artifactId> 
    <version>1.9.1</version> 
    <scope>test</scope> 
    </dependency> 
    <dependency> 
    <groupId>org.codehaus.jackson</groupId> 
    <artifactId>jackson-mapper-asl</artifactId> 
    <version>1.9.1</version> 
    <scope>test</scope> 
    </dependency> 
    <dependency> 
    <groupId>org.codehaus.jackson</groupId> 
    <artifactId>jackson-xc</artifactId> 
    <version>1.9.1</version> 
    <scope>test</scope> 
    </dependency> 
Verwandte Themen