如何向 Wink 客户端注册 Jackson 提供程序?

发布于 2024-10-05 22:09:30 字数 1698 浏览 0 评论 0原文

我正在尝试设置一个玩具应用程序(有一天可能会变成一个真正的应用程序)。我遇到了温克和杰克逊的问题。我有两个应用程序:一个在 jetty 上运行 wink-server,并且似乎可以很好地提供一些 JSON 数据;另一个在 jetty 上运行 wink-server,并且似乎提供了一些 JSON 数据。在jetty上运行wink-client并接收JSON数据就可以了。问题在于自动将 JSON 数据反序列化回我的 Java bean。

下面是我在 wink 客户端操作中使用的代码:

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 类上缺少注释。现在没有。也许我需要一些......)

I'm trying to set up a toy application (which may turn in to a real application someday). I'm running into a problem with Wink and Jackson. I've got two applications: one runs wink-server on jetty and seems to be providing some JSON data just fine; one runs wink-client on jetty and receives the JSON data just fine. The problem lies in automagically deserializing the JSON data back into my Java bean.

Here's the code I use in my wink client action:

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

Here's the error I receive when I try to run the Struts action:

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

If I replace the last line in the first code snippet with the following line, everything works fine and dandy.

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

It's clear that the data is getting across just fine, but the problem seems to lie with the fact that the JacksonJsonProvider class is not registered with Wink client. I've seen a lot of ways to register the provider with the Wink server, but not the Wink client.

Is it possible to do make the first code snippet operate properly? If so, how?

(As an aside, the other problem may be that I'm missing annotations on my User class. Right now there aren't any. Maybe I need some...)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

寒尘 2024-10-12 22:09:30

第 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.RestClient 创建一个 org.apache.wink.client.ClientConfig。这允许您将 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(ClassresponseEntity) 方法,现在一切都将按预期工作。

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

如果您想真正做到这一点,您可以使用 Spring 设置一个 ClientConfig bean 并将其注入到您的操作中。然后,您每次只需调用 new RestClient(clientConfig) 即可,而不必担心复制整个设置。

Step 1: Create a class that extends javax.ws.rs.core.Application that allows you to set singletons.

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

Step 2: In your action, create a org.apache.wink.client.ClientConfig for your org.apache.wink.client.RestClient. This allows you add the org.codehaus.jackson.jaxrs.JacksonJsonProvider to your providers list.

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

Step 3: Create the org.apache.wink.client.Resource, use the get(Class<T> responseEntity) method and everything will now work as expected.

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

If you want to be really slick about it, you can use Spring to set up a ClientConfig bean and inject it in to your actions. Then, you can just call new RestClient(clientConfig) every time and not worry about replicating the entire setup.

悲凉≈ 2024-10-12 22:09:30

当我尝试编写一些为我的休息插件发布对象的集成测试时,我遇到了这个问题。

您可以为 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,您可以确保 Jackson 位于测试类路径上(检查兼容版本):

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

i ran into this issue when trying to write some integration tests that POST an object for my rest plugin.

Rather then spinning out a new class you can provide the Jackson provider with an inline class.

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

}

Then you can post and consume your annotated objects.

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

}

If you're using maven you can make sure Jackson is on the test classpath (check for compatible versions):

<!-- 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>
远山浅 2024-10-12 22:09:30

我希望我能帮忙注册;但关于注释,我认为杰克逊不需要任何注释来尝试反序列化值。如果你缺少你需要的东西,你会得到不同类型的异常。

I wish I could help with registration; but with respect to annotations, I don't think you should need any for Jackson to try to deserialize value. If you are missing something you need you would get different kind of exception.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文