Десериализация WebClient
В своем приложении я делаю запросы к vk.com. Я использую spring 5 и webclient. Вот мой код:
private <R extends JsonMarker,
E extends RuntimeException> Mono<R> parseResponseToSingleObject(
final ClientResponse response,
final Class<R> responseClass,
final Class<E> errorClass) {
return Mono.fromCallable(
() -> {
val json = response
.bodyToMono(ByteArrayResource.class)
.map(ByteArrayResource::getByteArray)
.map(String::new)
.block();
System.out.println(json);
return json;
})
.subscribeOn(blockExec)
.flatMap(json -> {
if (isRespBody(json)) {
return Mono.fromCallable(
(Callable<SingleObject<R>>) () ->
jsonMapper.readValue(
json,
typeFactory.constructParametricType(SINGLE_OBJECT_CLASS, responseClass)
))
.subscribeOn(blockExec)
.flatMap(body -> body.getResponse() != null
? Mono.just(body.getResponse())
: Mono.empty());
} else {
if (isErrorBody(json)) {
return fromCallable(
(Callable<SingleError<E>>) () ->
jsonMapper.readValue(
json,
typeFactory.constructParametricType(SINGLE_ERROR_CLASS, errorClass)))
.subscribeOn(blockExec)
.flatMap(body -> Mono.error(body.getError()));
} else return Mono.error(InvalidJsonException::new);
}
});
}
Также я создал pojo классы:
// аннотации lombok
@JsonIgnoreProperties(ignoreUnknown = true)
public class SingleObject<R extends JsonMarker> {
@JsonProperty(value = "response")
private R response;
}
// аннотации lombok
@JsonIgnoreProperties(ignoreUnknown = true)
public class SingleError<R extends RuntimeException> {
@JsonProperty(value = "error")
private R error;
}
// аннотации lombok
@JsonIgnoreProperties(ignoreUnknown = true)
public class ApiException extends RuntimeException {
@JsonProperty(value = "error_code")
private int code;
@JsonProperty(value = "error_msg")
private String message;
@JsonProperty(value = "method")
private String method;
}
// аннотации lombok
@JsonIgnoreProperties(ignoreUnknown = true)
public class UserJson implements JsonMarker {
@JsonProperty(value = "id")
private Integer ID;
@JsonProperty(value = "first_name")
private String firstName;
@JsonProperty(value = "last_name")
private String lastName;
@JsonProperty(value = "is_closed")
private boolean closed;
@JsonProperty(value = "deactivated")
private String deactivated;
@JsonProperty(value = "sex")
private int sex;
}
Мне нужно, чтобы метод parseResponseToSingleObject возвращал объект либо бросал исключение ApiException. Поэтому я сперва преобразовываю ответ в String, а потом, в зависимости от начала строки, начинаю десериализовывать. Это решение работает корректно, но мне кажется это ужасный код. Мне бы хотелось сразу парсить ответ в объект, без преобразования в String. К тому же, тут 3 блокирующих вызова, а эти методы я вызываю из контроллера. Я обошел блокировку через scheduler, но мне кажется так делать нежелательно.
Я только начинаю изучать reactive стек и хочу знать как мне сделать это правильно.