java.net.http.HttpClient Error Handling with different BodySubscribers

418 Views Asked by At

Currently, I have this JsonBodyHandler used to parse the response body if the response is successful. I also have a model defined if the request is not successful. So based on the status code, I need to map the response to either the expected or exception model classes.

  private static class JsonBodyHandler<R> implements HttpResponse.BodyHandler<Supplier<R>> {

    private final Class<R> returnClz;

    public JsonBodyHandler(Class<R> returnClz) {
      this.returnClz = returnClz;
    }

    private static <R> HttpResponse.BodySubscriber<Supplier<R>> asJson(Class<R> returnClz) {
      HttpResponse.BodySubscriber<InputStream> upstream =
          HttpResponse.BodySubscribers.ofInputStream();

      return HttpResponse.BodySubscribers.mapping(
          upstream, inputStream -> toSupplierOfType(inputStream, returnClz));
    }

    private static <R> Supplier<R> toSupplierOfType(InputStream inputStream, Class<R> returnClz) {
      return () -> {
        try (InputStream stream = inputStream) {
          ObjectMapper objectMapper = new ObjectMapper();
          return objectMapper.readValue(stream, returnClz);
        } catch (IOException e) {
          throw new UncheckedIOException(e);
        }
      };
    }

    @Override
    public HttpResponse.BodySubscriber<Supplier<R>> apply(HttpResponse.ResponseInfo responseInfo) {
      return asJson(returnClz);
    }
  }

I'm sending requests as follows:

  <B, R> R exchange(URI uri, String method, B body, Class<R> returnClz) {
    Builder httpRequestBuilder = HttpRequest.newBuilder().uri(uri);
    addHeaders(httpRequestBuilder);

    var httpRequest =
        "GET".equals(method)
            ? httpRequestBuilder.GET().build()
            : httpRequestBuilder.method(method, getBodyPublisher(body)).build();

    var httpClient = HttpClient.newHttpClient();
    JsonBodyHandler<R> bodyHandler = new JsonBodyHandler<>(returnClz);
    Supplier<R> responseSupplier = httpClient.send(httpRequest, bodyHandler).body();
    return responseSupplier.get();
  }

What I want to do is something as follows:

    BodySubscriber<Supplier<R>> successBodySubscriber = JsonBodyHandler.asJson(returnClz);
    BodySubscriber<Supplier<ExceptionModel>> failureBodySubscriber =
        JsonBodyHandler.asJson(ExceptionModel.class);
    BodyHandler<Supplier> jsonBodyHandler =
        (rspInfo) -> rspInfo.statusCode() == 200 ? successBodySubscriber : failureBodySubscriber;

    HttpResponse<Supplier> httpResponse = httpClient.send(httpRequest, jsonBodyHandler);
    if (httpResponse.statusCode() != 200) {
      Supplier<ExceptionModel> responseSupplier = httpResponse.body();
      throw ClientServiceError.invalidResponse(responseSupplier.get());
    }

    Supplier<R> responseSupplier = httpResponse.body();
    return responseSupplier.get();

This doesn't work, I get compile time error at line BodyHandler<Supplier> jsonBodyHandler = (rspInfo) -> rspInfo.statusCode() == 200 ? successBodySubscriber : failureBodySubscriber;:

Incompatible types. Found: 'java.net.http.HttpResponse.BodySubscriber<java.util.function.Supplier>', required: 'java.net.http.HttpResponse.BodySubscriber<java.util.function.Supplier>'

Incompatible types. Found: 'java.net.http.HttpResponse.BodySubscriber<java.util.function.Supplier<com.project.proxy.impl.ExceptionModel>>', required: 'java.net.http.HttpResponse.BodySubscriber<java.util.function.Supplier>'

I am using Java 11. Cannot upgrade the version. I believe there should be a better way to do this. Any suggestions will be appreciated.

0

There are 0 best solutions below