首页 > 解决方案 > 为什么我的 Jax-RS 客户端对象不反序列化此 HTTP 响应中的 JSON 列表,即使对象映射器可以反序列化?

问题描述

我开始为 REST API 编写客户端,并从一个简单的调用开始,该调用返回一个相对简单的 JSON 对象:一个resultCode字符串、一个message字符串和一个对象列表。当我首先将对象作为字符串检索并使用 解码时ObjectMapper,它会很好地解组,包括对象列表。但是,当我使用Client对象检索它时,它只检索字符串属性,而不是对象列表。我想对比这更复杂的 API 响应进行建模,但我认为在我克服这个障碍之前这是不明智的。

我尝试过使用注释,例如使用注释创建setResultItems方法@JsonSetter。我最初的示例使用了 getter 和 setter,但我发布的示例使用公共字段来节省空间——结果是一样的。我还尝试通过向对象注册 a来强制Client对象使用相同的。我注意到的一件事是调用立即设置所有内容的构造函数,但需要一个无参数构造函数,并在创建对象后设置属性。ObjectMapperJacksonJsonProviderObjectMapperClient

这是响应对象类的最简单版本:

class ResponseObject {

    public String resultCode;
    public String message;
    public List<Map<String,String>> resultItems;

    ResponseObject() {
        System.out.println("Blank constructor called");
    }
    ResponseObject(
        @JsonProperty("resultItems") List<Map<String,String>> resultItems, 
        @JsonProperty("message") String message, 
        @JsonProperty("resultCode") String resultCode ) {
        System.out.println("Good constructor called");
        this.resultCode = resultCode;
        this.message = message;
        this.resultItems = resultItems;
    }

    private void print() {
        System.out.println("resultCode: " + resultCode);
        System.out.println("message: " + message);
        System.out.println("resultItems: " + resultItems.toString());
    }
}

我的测试应用程序在 try-catch 中运行此方法:

    private static void doGetVariable() throws IOException {
        Client client = ClientBuilder.newClient();

        // hey this means the client should decode it the same way right?
        ObjectMapper mapper = new ObjectMapper();
        JacksonJsonProvider provider = new JacksonJsonProvider(mapper);
        client.register(provider);

        System.out.println("Getting string and deserializing it");
        String sresp = client.target(URL)
                .request(MediaType.APPLICATION_JSON)
                .get(String.class);
        System.out.println("string: "+sresp);
        ResponseObject resp1 = mapper.readValue(sresp, ResponseObject.class);
        resp1.print();
        System.out.flush();
        System.out.println("\nGetting object directly from the client");
        ResponseObject resp2 = client.target(URL)
                .request(MediaType.APPLICATION_JSON)
                .get(ResponseObject.class);
        resp2.print();
    }

由于这些事情似乎很重要,因此这是我pom.xml文件中的依赖项。我必须添加 Jersey 的,因为如果我不添加,我会得到 aClassNotFoundException因为它找不到JerseyClientBuilder. 我认为这是一个提示,但我不确定这意味着什么。

        <dependency>
            <groupId>javax.ws.rs</groupId>
            <artifactId>javax.ws.rs-api</artifactId>
            <version>2.1.1</version>
            <type>jar</type>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.ext.rx</groupId>
            <artifactId>jersey-rx-client</artifactId>
            <version>2.25.1</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.jersey.media</groupId>
            <artifactId>jersey-media-moxy</artifactId>
            <version>2.25.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.jaxrs</groupId>
            <artifactId>jackson-jaxrs-json-provider</artifactId>
            <version>2.9.9</version>
        </dependency>

当我运行它时,这是输出。您可以在以string:. 我希望resultItems这两个请求都是一样的,但它只在第一个请求中是正确的。请注意,它仍然设置resultCode并且message在两次尝试中,所以它至少在做一些事情。

Getting string and deserializing it
string: {"resultItems":[{"name":"MAX.PACKETSIZE","value":"64512"}],"message":"OK - the variables were successfully retrieved","resultCode":"0"}
Good constructor called
resultCode: 0
message: OK - the variables were successfully retrieved
resultItems: [{name=MAX.PACKETSIZE, value=64512}]

Getting object directly from the client
Blank constructor called
resultCode: 0
message: OK - the variables were successfully retrieved
resultItems: []

此外,我更愿意摆脱无参数构造函数,以便我可以制作所有字段private final并正确封装所有内容。

标签: javajsonjax-rsdeserialization

解决方案


推荐阅读