Jestem przyzwyczajony do JAX-RS i chciałbym mieć podobny komfort podczas wysyłania zapytań za pomocą Spring MVC i pracy z odpowiedziami, czyli po stronie klienta w moich testach.
Po stronie serwera (kontrolera) jestem całkiem zadowolony z automatycznej konwersji, tj. Wystarczy po prostu zwrócić instancję obiektu i mieć JSON w wynikowej odpowiedzi HTTP wysyłanej do klienta.
Czy możesz mi powiedzieć, jak obejść ręczny proces konwersji objectInstance
do jsonString
czy odwrotnie w tych fragmentach? Jeśli to możliwe, chciałbym również pominąć ręczne konfigurowanie typu zawartości.
String jsonStringRequest = objectMapper.writeValueAsString(objectInstance);
ResultActions resultActions = mockMvc.perform(post(PATH)
.contentType(MediaType.APPLICATION_JSON)
.content(jsonStringRequest)
)
String jsonStringResponse = resultActions.andReturn().getResponse().getContentAsString();
Some objectInstanceResponse = objectMapper.readValue(jsonStringResponse, Some.class);
Dla porównania, dzięki API klienta JAX-RS mogę w łatwy sposób wysłać obiekt za pomocą request.post(Entity.entity(objectInstance, MediaType.APPLICATION_JSON_TYPE)
i przeczytaj odpowiedź za pomocą response.readEntity(Some.class);
Odpowiedzi:
0 dla odpowiedzi № 1jeśli masz dużo obiektów odpowiedzi, możeszutwórz ogólną fabrykę mapperów JsonToObject. Można go następnie użyć do wykrycia typu obiektu z odpowiedzi ogólnej (wszystkie obiekty odpowiedzi dziedziczą z tej samej klasy ogólnej) i prawidłowo zareagować / zarejestrować w przypadku złej próby odwzorowania.
Nie mam pod ręką przykładu kodu, ale jako pseudokod:
public abstract GenericResponse {
public String responseClassName = null;
// get/set
}
W kodzie serwera dodaj nazwę rzeczywistego obiektu odpowiedzi do tej klasy.
Fabryka JsonToObject
public ConverterFactory<T> {
private T objectType;
public ConverterFactory(T type) {
objectType = type;
}
public T convert(String jsonString) {
// Type check
GenericResponse genResp = mapper.readValue(result.getResponse().getContentAsString(),
GenericResponse.class);
if (objectType.getClass().getSimpleName().equals(genResp.getResponseClassName())) {
// ObjectMapper code
return mapper.readValue(result.getResponse().getContentAsString(),
objectType.class);
} else {
// Error handling
}
}
}
Myślę, że można by to rozszerzyć, aby było używane z adnotacjami, aby uzyskać więcej magii automatyzacji z odpowiedzią. (zacznij sprawdzać za pomocą BeanPostProcessor)
@Component
public class AnnotationWorker implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(final Object bean, String name) throws BeansException {
ReflectionUtils.doWithFields(bean.getClass(), field -> {
// make the field accessible if defined private
ReflectionUtils.makeAccessible(field);
if (field.getAnnotation(MyAnnotation.class) != null) {
field.set(bean, log);
}
});
return bean;
}
}
Powyższy fragment kodu jest kopiowany z mojego obecnego projektu i wstrzykuje do pól, trzeba to zmienić tak, żeby działał dla metod np ... tam, gdzie jest to potrzebne.
Wdrożenie tego wszystkiego może być trudne i nie można powiedzieć, że to zawsze działa, ale warto spróbować, jeśli nie masz nic przeciwko odrobinie pracy edukacyjnej.