I have a problem with deserializing JSON to custom object directly using Java 11 HttpClient::send with custom HttpResponse.BodyHandler. I came across this issue while answering this SO question.
Versions that I am using :
- OpenJDK 11
- Jackson 2.9.9.3
I created a simple generic JsonBodyHandler class which implements 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);
}
}
the asJSON method is defined as :
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);
}
});
}
So it returns a custom HttpResponse.BodySubscriber which gets body as String and then applies mapping from JSON to given targetType
The code to test it :
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);
}
And the Model class :
public class Model {
private String userId;
private String id;
private String title;
private boolean completed;
//getters setters constructors toString
}
The output is as expected :
Model{userId='1', id='1', title='delectus aut autem', completed=false}
However when I change the asJSON method to read InputStream instead of String first :
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);
}
});
}
It hangs after invoking reading the value with ObjectMapper and it does not proceed (I have checked that it successfully gets the response from the endpoint, status code is 200) but then it just hangs. Does anyone know what might be the issue?