HTTP-клиент Micronaut - десериализация универсального типа - для тестирования API
Для тестирования API мне нужно проанализировать ответ на запрос с помощью io.micronaut.http.client.HttpClient
Я предпочитаю использовать формат, указанный ниже.
Response<User> response =
client.toBlocking().retrieve(HttpRequest.POST("/", user), Response.class);
Но это не работает. Я получаю ошибку приведения типа при попытке получить пользователя из ответа
User user = response.getUser();
В настоящее время я использую ObjectMapper (Jackson), как показано ниже,
String response = client.toBlocking().retrieve(HttpRequest.POST("/", user), String.class);
ObjectMapper objectMapper = new ObjectMapper();
Response<User> response = objectMapper.readValue(response, new TypeReference<Response<User>>() {});
Есть ли способ использовать TypeReference напрямую с методом получения HttpClient? Или любой другой способ использования универсального типа класса с HttpClient.
Другая полезная информация
// Response generic class
class Response<T> {
T data;
....
}
Образец ответа
{
"data": {
"name":"sample"
},
"message": "Success"
}
1 ответ
У вас есть несколько вариантов:
Если тебе нужно только это User
экземпляр объекта, вы можете сделать это retrieve()
метод, где вторым параметром является класс домена (User
в вашем случае), а затем вы можете использовать user
переменная по мере необходимости:
User user = client.toBlocking().retrieve(HttpRequest.POST("/", user), User.class);
assertThat(user)
.isNotNull()
.extracting(User::getName)
.isEqualTo("sample");
Если вам также нужен объект ответа (например, чтобы проверить код ответа), вы должны использовать exchange()
метод, а затем получить User
экземпляр, позвонив body()
метод этого ответа:
HttpResponse<User> response = client.toBlocking()
.exchange(HttpRequest.POST("/", user), User.class);
assertThat(response)
.isNotNull()
.extracting(HttpResponse::body)
.extracting(User::getName)
.isEqualTo("sample");
Обновление: когда вам нужно использовать общий класс в качестве ответа, вы должны использоватьArgument.of()
как второй параметр retrieve()
а также exchange()
методы, в которых вы можете указать универсальный класс ответа и его параметры типа. См. Пример:
Response<User> response = client.toBlocking()
.retrieve(HttpRequest.POST("/", user), Argument.of(Response.class, User.class));
assertThat(response)
.isNotNull()
.extracting(Response::getData)
.extracting(User::getName)
.isEqualTo("sample");
Если вы сделаете это без Argument.of()
тогда он преобразует data
собственность в LinkedHashMap
вместо того User
и это:
Response<User> response = client.toBlocking().retrieve(HttpRequest.POST("/", user), Response.class);
response.getData().getName();
... бросит ClassCastException
:
java.lang.ClassCastException: класс java.util.LinkedHashMap нельзя привести к классу my.app.domain.User (java.util.LinkedHashMap находится в модуле java.base загрузчика bootstrap; my.app.domain.User. Пользователь находится в безымянном модуле загрузчика app)
Как очень простая альтернатива: когда ваши ответы представляют собой JSON, вы всегда можете просто десериализовать их в
Map.class
. Быстро и легко. Конечно, тогда у вас нет безопасности типов.