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?