Как зарегистрировать провайдера Jackson с помощью клиента Wink?

Я пытаюсь настроить игрушечное приложение (которое может когда-нибудь превратиться в настоящее приложение). У меня проблема с Уинком и Джексоном. У меня есть два приложения: одно запускает wink-сервер на причале и, похоже, отлично предоставляет некоторые данные JSON; один запускает wink-client на причале и отлично получает данные JSON. Проблема заключается в автоматической десериализации данных JSON обратно в мой Java-бин.

Вот код, который я использую в своем клиентском действии подмигивания:

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

Вот ошибка, которую я получаю, когда пытаюсь запустить действие Struts:

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

Если я заменю последнюю строку в первом фрагменте кода следующей строкой, все будет работать нормально и отлично.

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

Понятно, что данные передаются нормально, но проблема, похоже, заключается в том, что класс JacksonJsonProvider не зарегистрирован в клиенте Wink. Я видел много способов зарегистрировать провайдера на Wink-сервере, но не на Wink-клиенте.

Можно ли сделать так, чтобы первый фрагмент кода работал правильно? Если да, то как?

(Кроме того, другая проблема может заключаться в том, что мне не хватает аннотаций в моем классе User. Сейчас их нет. Может быть, мне нужны некоторые...)


person jacobko    schedule 01.12.2010    source источник


Ответы (3)


Шаг 1: Создайте класс, который расширяет javax.ws.rs.core.Application и позволяет вам устанавливать синглтоны.

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

Шаг 2: В своем действии создайте org.apache.wink.client.ClientConfig для своего org.apache.wink.client.RestClient. Это позволит вам добавить org.codehaus.jackson.jaxrs.JacksonJsonProvider в список ваших провайдеров.

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

Шаг 3: Создайте org.apache.wink.client.Resource, используйте метод get(Class<T> responseEntity), и теперь все будет работать как положено.

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

Если вы хотите сделать это действительно ловко, вы можете использовать Spring для настройки bean-компонента ClientConfig и внедрить его в свои действия. Затем вы можете просто вызывать new RestClient(clientConfig) каждый раз и не беспокоиться о репликации всей установки.

person jacobko    schedule 07.12.2010
comment
Это не сработало для меня. В моих классах есть аннотации jaxb, и поставщик системных приложений, похоже, мешает поставщику json jackson. Решение состояло в том, чтобы вызвать setLoadWinkApplications(false) в ClientConfig перед настройкой приложений. - person kldavis4; 16.03.2013

я столкнулся с этой проблемой при попытке написать некоторые интеграционные тесты, которые отправляют объект для моего плагина для отдыха.

Вместо создания нового класса вы можете предоставить провайдеру Jackson встроенный класс.

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

}

Затем вы можете опубликовать и использовать свои аннотированные объекты.

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

}

Если вы используете maven, вы можете убедиться, что Джексон находится в тестовом пути к классам (проверьте наличие совместимых версий):

<!-- 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>
person Eddie    schedule 01.08.2014

Я хотел бы помочь с регистрацией; но что касается аннотаций, я не думаю, что они вам нужны, чтобы Джексон попытался десериализовать значение. Если вам не хватает чего-то, что вам нужно, вы получите другое исключение.

person StaxMan    schedule 03.12.2010