- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在使用 Java 11 HttpClient::send
直接将 JSON 反序列化为自定义对象时遇到问题定制 HttpResponse.BodyHandler
.我在回答 this SO question 时遇到了这个问题.
我使用的版本:
JsonBodyHandler
实现
HttpResponse.BodyHandler
的类:
public class JsonBodyHandler<W> implements HttpResponse.BodyHandler<W> {
private final Class<W> wClass;
public JsonBodyHandler(Class<W> wClass) {
this.wClass = wClass;
}
@Override
public HttpResponse.BodySubscriber<W> apply(HttpResponse.ResponseInfo responseInfo) {
return asJSON(wClass);
}
}
asJSON
方法定义为:
public static <W> HttpResponse.BodySubscriber<W> asJSON(Class<W> 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);
}
});
}
HttpResponse.BodySubscriber
获取主体为
String
然后应用从 JSON 到给定
targetType
的映射
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
类(class) :
public class Model {
private String userId;
private String id;
private String title;
private boolean completed;
//getters setters constructors toString
}
Model{userId='1', id='1', title='delectus aut autem', completed=false}
asJSON
时阅读方法
InputStream
而不是
String
第一的 :
public static <W> HttpResponse.BodySubscriber<W> asJSON(Class<W> targetType) {
HttpResponse.BodySubscriber<InputStream> upstream = HttpResponse.BodySubscribers.ofInputStream();
return HttpResponse.BodySubscribers.mapping(
upstream,
(InputStream is) -> {
try (InputStream stream = is) {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(stream, targetType);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
});
}
ObjectMapper
调用读取值后挂起并且它没有继续(我已经检查它是否成功地从端点获得了响应,状态代码是 200)但是它只是挂起。有谁知道可能是什么问题?
最佳答案
我刚刚找到 this SO question有同样的问题,但 GZIPInputStream
.原来HttpResponse.BodySubscribers.mapping
有问题,无法按文档工作。这是link到官方 OpenJDK 错误站点。它已针对 OpenJDK 13 修复。因此,一种解决方法是使用 HttpResponse.BodySubscribers::ofString
而不是 HttpResponse.BodySubscribers::ofInputStream
作为 HttpResponse.BodySubscribers::mapping
的上游- 在我的问题中显示了如何做到这一点。
或者,正如@daniel 在评论中指出的那样,更好的解决方案是返回 Supplier
而不是模型类:
public static <W> HttpResponse.BodySubscriber<Supplier<W>> asJSON(Class<W> targetType) {
HttpResponse.BodySubscriber<InputStream> upstream = HttpResponse.BodySubscribers.ofInputStream();
return HttpResponse.BodySubscribers.mapping(
upstream,
inputStream -> toSupplierOfType(inputStream, targetType));
}
public static <W> Supplier<W> toSupplierOfType(InputStream inputStream, Class<W> targetType) {
return () -> {
try (InputStream stream = inputStream) {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(stream, targetType);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
};
}
JsonBodyHandler
也使用
Supplier
:
public class JsonBodyHandler<W> implements HttpResponse.BodyHandler<Supplier<W>> {
private final Class<W> wClass;
public JsonBodyHandler(Class<W> wClass) {
this.wClass = wClass;
}
@Override
public HttpResponse.BodySubscriber<Supplier<W>> apply(HttpResponse.ResponseInfo responseInfo) {
return asJSON(wClass);
}
}
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()
.get();
System.out.println(model);
}
OpenJDK 13 docs
中描述的推广方式。 ):
The mapping function is executed using the client's executor, and can therefore be used to map any response body type, including blocking
InputStream
. However, performing any blocking operation in the mapper function runs the risk of blocking the executor's thread for an unknown amount of time (at least until the blocking operation finishes), which may end up starving the executor of available threads. Therefore, in the case where mapping to the desired type might block (e.g. by reading on the InputStream), then mapping to aSupplier
of the desired type and deferring the blocking operation untilSupplier::get
is invoked by the caller's thread should be preferred.
关于java - 使用 Java 11 HttpClient 和带有 Jackson 的自定义 BodyHandler 反序列化 JSON 停止并且不会继续,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57629401/
我在使用 Java 11 HttpClient::send 直接将 JSON 反序列化为自定义对象时遇到问题定制 HttpResponse.BodyHandler .我在回答 this SO ques
我是一名优秀的程序员,十分优秀!