如何使用Java 11 HttpClient和Jackson将JSON响应映射到Java类? [英] How to map a JSON response to a Java class using Java 11 HttpClient and Jackson?

查看:512
本文介绍了如何使用Java 11 HttpClient和Jackson将JSON响应映射到Java类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Java 11 HttpClient的新手,想尝试一下.我有一个简单的GET请求,该请求返回JSON,我想将JSON响应映射到名为Questionnaire的Java类.

I'm new to the Java 11 HttpClient and would like to give it a try. I have a simple GET request that return JSON and I would like to map the JSON response to a Java class called Questionnaire.

我知道我可以将响应立即转换为String或类似这样的输入流

I understand that I can turn the response out of box into a String or an input stream like this

HttpRequest request = HttpRequest.newBuilder(new URI(String.format("%s%s", this.baseURI, "/state")))
          .header(ACCEPT, APPLICATION_JSON)
          .PUT(noBody()).build();

HttpResponse<String> response = this.client.send(request, HttpResponse.BodyHandlers.ofString());

我该如何编写将JSON字符串转换为我的Questionnaire类的东西?

How can I write something that converts the JSON string to my Questionnaire class like this?

HttpResponse<Questionnaire> response = this.client.send(request, HttpResponse.BodyHandlers./* what can I do here? */);

我使用Jackson将JSON转换为Java类实例.杰克逊是否支持新的Java标准HttpClient?

I use Jackson to transform JSON into Java class instances. Is there Jackson support for the new Java standard HttpClient yet?

更新1 我不够精确,对此感到抱歉.我正在寻找一个阻止获取示例.我知道 http://openjdk.java.net/groups/net/httpclient/recipes.html#jsonGet

UPDATE 1 I was not precise enough, sorry about that. I am looking for a blocking get example. I was aware of http://openjdk.java.net/groups/net/httpclient/recipes.html#jsonGet

推荐答案

仅Java 11 HttpClient::sendAsync的解决方案

基于此链接,您可以执行以下操作这个:

Solution for Java 11 HttpClient::sendAsync only

Based on this link you can do something like this :

public static void main(String[] args) throws IOException, URISyntaxException, ExecutionException, InterruptedException {
        UncheckedObjectMapper uncheckedObjectMapper = new UncheckedObjectMapper();

        HttpRequest request = HttpRequest.newBuilder(new URI("https://jsonplaceholder.typicode.com/todos/1"))
                .header("Accept", "application/json")
                .build();

        Model model = HttpClient.newHttpClient()
                .sendAsync(request, HttpResponse.BodyHandlers.ofString())
                .thenApply(HttpResponse::body)
                .thenApply(uncheckedObjectMapper::readValue)
                .get();

        System.out.println(model);

}

static class UncheckedObjectMapper extends com.fasterxml.jackson.databind.ObjectMapper {
        /**
         * Parses the given JSON string into a Map.
         */
        Model readValue(String content) {
            try {
                return this.readValue(content, new TypeReference<Model>() {
                });
            } catch (IOException ioe) {
                throw new CompletionException(ioe);
            }
        }

}

static class Model {
        private String userId;
        private String id;
        private String title;
        private boolean completed;


    //getters setters constructors toString
}

我使用了一些虚拟端点,该端点提供了示例JSON输入和示例模型类,以使用Jackson将响应直接映射到Model类.

I used some dummy endpoint which provides sample JSON input and sample model class to map the response directly to Model class using Jackson.

我找到了定义自定义HttpResponse.BodyHandler的方法:

I found a way by defining custom HttpResponse.BodyHandler :

public class JsonBodyHandler<W> implements HttpResponse.BodyHandler<W> {

    private Class<W> wClass;

    public JsonBodyHandler(Class<W> wClass) {
        this.wClass = wClass;
    }

    @Override
    public HttpResponse.BodySubscriber<W> apply(HttpResponse.ResponseInfo responseInfo) {
        return asJSON(wClass);
    }

    public static <T> HttpResponse.BodySubscriber<T> asJSON(Class<T> targetType) {
        HttpResponse.BodySubscriber<String> upstream = HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8);

        return HttpResponse.BodySubscribers.mapping(
                upstream,
                (String body) -> {
                    try {
                        ObjectMapper objectMapper = new ObjectMapper();
                        return objectMapper.readValue(body, targetType);
                    } catch (IOException e) {
                        throw new UncheckedIOException(e);
                    }
                });
    }
}

然后我称它为:

public static void main(String[] args) throws URISyntaxException, IOException, InterruptedException {

    HttpRequest request = HttpRequest.newBuilder(new URI("https://jsonplaceholder.typicode.com/todos/1"))
                .header("Accept", "application/json")
                .build();

    Model model = HttpClient.newHttpClient()
                .send(request, new JsonBodyHandler<>(Model.class))
                .body();

    System.out.println(model);

}

响应为:

Model{userId='1', id='1', title='delectus aut autem', completed=false}

HttpResponse.BodySubscribers::mapping的JavaDoc对于解决此问题特别有用.可以进一步改进,使用HttpResponse.BodySubscribers::ofInputStream代替HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8)JsonBodyHandler定义BodySubscriber.

The JavaDoc of HttpResponse.BodySubscribers::mapping was particulary useful to solve this. It can be further improved to use HttpResponse.BodySubscribers::ofInputStream instead of HttpResponse.BodySubscribers.ofString(StandardCharsets.UTF_8) to define the BodySubscriber for the JsonBodyHandler.

这篇关于如何使用Java 11 HttpClient和Jackson将JSON响应映射到Java类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆