Я несколько дней go я пытался использовать restTemplate загрузки Spring, чтобы сделать вызов отдыха для собственного API. По некоторым причинам все ответы такого API имеют оболочку ResponseDTO с полями дерева (не спрашивайте меня, почему, но я не могу изменить этот объект, поэтому избегайте ответов и меняйте ResponseDTO).
githubCode:
https://github.com/Gaboxondo/RestTemplateBuilderTest
Здесь вы можете увидеть пример ответа:
{
"status": "success",
"error": null,
"data": [
{
"id": 0,
"name": "Person_0"
},
{
"id": 1,
"name": "Person_1"
}
]
}
Как вы В этом случае в Data можно увидеть список людей.
Объект-оболочка выглядит следующим образом
public class ResponseDTO<T> {
private String status;
private ArrayList<String> error;
private T data;
private static final String SuccessMessage = "success";
private static final String FailMessage = "fail";
public ResponseDTO() {
}
public ResponseDTO(String status, ArrayList<String> error, T data) {
this.status = status;
this.error = error;
this.data = data;
}
public ResponseDTO(String error) {
this.status = FailMessage;
ArrayList<String> oneException = new ArrayList<>();
oneException.add( error );
this.error = oneException;
this.data = null;
}
public ResponseDTO(T data) {
this.status = SuccessMessage;
this.error = null;
this.data = data;
}
public ResponseDTO(boolean statusResponse) {
if(statusResponse) {
this.status = SuccessMessage;
} else {
this.status = FailMessage;
}
this.data = null;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public ArrayList<String> getError() {
return error;
}
public void setError(ArrayList<String> error) {
this.error = error;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
Для выполнения запроса я создал оболочку для RestTemplate, чтобы упростить ResponseDTO wrapper:
Самый важный метод - метод build ()
public class RestRequestBuilderForResponseDTO<T> {
private static final Logger LOG = LoggerFactory.getLogger( RestRequestBuilderForResponseDTO.class );
private static final String SLASH = "/";
private static final String COLONS = ":";
private RestTemplate restTemplate;
private String uri;
private Map<String, String> headerValues;
private Object body = null;
private MultiValueMap<String, String> params;
private HttpMethod method;
private String token;
private Integer timeOut;
public RestRequestBuilderForResponseDTO(String serverUri) {
this.restTemplate = new RestTemplate();
this.uri = serverUri;
headerValues = new HashMap<>();
params = new HttpHeaders();
}
public RestRequestBuilderForResponseDTO<T> path(int path) {
this.uri = this.uri + SLASH + path;
return this;
}
public RestRequestBuilderForResponseDTO<T> path(String path) {
this.uri = this.uri + SLASH + path;
return this;
}
public RestRequestBuilderForResponseDTO<T> path(BigDecimal pathId) {
this.uri = this.uri + SLASH + pathId.toString();
return this;
}
public RestRequestBuilderForResponseDTO<T> param(String key, BigDecimal value) {
return param( key, value.toString() );
}
public RestRequestBuilderForResponseDTO<T> param(String key, Long value) {
return param( key, value.toString() );
}
public RestRequestBuilderForResponseDTO<T> param(String key, Integer value) {
return param( key, value.toString() );
}
public RestRequestBuilderForResponseDTO<T> header(String key, String value) {
this.headerValues.put( key, value );
return this;
}
public RestRequestBuilderForResponseDTO<T> bearerToken(String token) {
this.token = token;
return this;
}
public RestRequestBuilderForResponseDTO<T> body(Object body) {
this.body = body;
return this;
}
public RestRequestBuilderForResponseDTO<T> timeout(Integer timeOut) {
this.timeOut = timeOut;
return this;
}
public RestRequestBuilderForResponseDTO<T> post() {
this.method = HttpMethod.POST;
return this;
}
public RestRequestBuilderForResponseDTO<T> get() {
this.method = HttpMethod.GET;
return this;
}
public RestRequestBuilderForResponseDTO<T> put() {
this.method = HttpMethod.PUT;
return this;
}
public RestRequestBuilderForResponseDTO<T> patch() {
this.method = HttpMethod.PATCH;
return this;
}
public RestRequestBuilderForResponseDTO<T> delete() {
this.method = HttpMethod.DELETE;
return this;
}
public <T> ResponseEntity<ResponseDTO<T>> build() {
HttpEntity<Object> httpEntity;
if (body != null && !method.equals( HttpMethod.GET )) {
httpEntity = new HttpEntity<>( body, this.headers() );
} else {
httpEntity = new HttpEntity<>( this.headers() );
}
if (timeOut != null) {
this.restTemplate.setRequestFactory( setTimeOut( this.timeOut ) );
}
LOG.trace( "URL: " + this.uri );
LOG.trace( "METHOD: " + method.toString() );
LOG.trace( "HTTP ENTITY: " + httpEntity.toString() );
ResponseEntity<ResponseDTO<T>> response =
restTemplate.exchange( this.uri(), method, httpEntity, new ParameterizedTypeReference<ResponseDTO<T>>() {
} );
return response;
}
public void buildWithoutResponse() {
HttpEntity<Object> httpEntity;
if (body != null && !method.equals( HttpMethod.GET )) {
httpEntity = new HttpEntity<>( body, this.headers() );
} else {
httpEntity = new HttpEntity<>( this.headers() );
}
if (timeOut != null) {
this.restTemplate.setRequestFactory( setTimeOut( this.timeOut ) );
}
LOG.trace( "HTTP ENTITY: " + httpEntity.toString() );
restTemplate.exchange( this.uri(), method, httpEntity, Void.class );
}
public String getFullTrace() {
StringBuilder trace = new StringBuilder( "REQUEST, Url: " + uri );
if (method != null) {
trace.append( " Method: " ).append( method.toString() );
}
if (params != null && !params.isEmpty()) {
trace.append( " Params: [" );
for (Map.Entry<String, List<String>> stringListEntry : params.entrySet()) {
String key = ((Map.Entry) stringListEntry).getKey().toString();
String value = ((Map.Entry) stringListEntry).getValue().toString();
String param = "(" + key + "," + value + ")";
trace.append( param );
}
trace.append( "]" );
}
if (body != null) {
trace.append( " Body: [" ).append( body ).append( "]" );
}
if (headerValues != null && !headerValues.isEmpty()) {
trace.append( " Headers: [" );
for (Map.Entry<String, String> headerValues : headerValues.entrySet()) {
String key = ((Map.Entry) headerValues).getKey().toString();
String value = ((Map.Entry) headerValues).getValue().toString();
String param = "(" + key + "," + value + ")";
trace.append( param );
}
trace.append( "]" );
}
if (token != null) {
trace.append( " TOKEN: [" ).append( token ).append( "]" );
}
return trace.toString();
}
public String getSimpleTrace() {
StringBuilder trace = new StringBuilder( "REQUEST, Url: " + uri );
if (method != null) {
trace.append( " Method: " ).append( method.toString() );
}
if (params != null && !params.isEmpty()) {
trace.append( " Params: [" );
for (Map.Entry<String, List<String>> stringListEntry : params.entrySet()) {
String key = ((Map.Entry) stringListEntry).getKey().toString();
String value = ((Map.Entry) stringListEntry).getValue().toString();
String header = "(" + key + "," + value + ")";
trace.append( header );
}
trace.append( "]" );
}
return trace.toString();
}
private RestRequestBuilderForResponseDTO<T> param(String key, String value) {
this.params.add( key, value );
return this;
}
private HttpHeaders headers() {
HttpHeaders headers = new HttpHeaders();
for (Map.Entry<String, String> entry : headerValues.entrySet()) {
headers.set( entry.getKey(), entry.getValue() );
}
if (token != null) {
headers.setBearerAuth( token );
}
return headers;
}
private URI uri() {
UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromHttpUrl( uri );
if (!params.isEmpty()) {
uriComponentsBuilder.queryParams( params );
}
return uriComponentsBuilder.build().encode().toUri();
}
private ClientHttpRequestFactory setTimeOut(Integer timeout) {
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout( timeout );
return clientHttpRequestFactory;
}
}
Дело в том, что теперь, когда я делаю запрос:
RestRequestBuilderForResponseDTO<List<PersonDTO>> client =
new RestRequestBuilderForResponseDTO<List<PersonDTO>>( "http://localhost:8081" ).path( "person" ).path( "all" )
.get();
LOG.info( client.getFullTrace() );
ResponseEntity<ResponseDTO<List<PersonDTO>>> response = client.build();
ResponseDTO<List<PersonDTO>> body = response.getBody();
List<PersonDTO> data = body.getData();
data.get( 0 );
...
если теперь я вижу данные в теле, это означает, что они не были десириализированы в PersonDTO, а вместо этого были выделены LinkedHashMap
Есть ли способ правильно выполнить десериализацию?
тем временем я создал метод, в котором я конвертирую значения, но очень утомительно проверять, является ли какой-то объект экземпляром LinkedHashMap или не выполнять преобразование везде, где я его использую.
public static <V, klazz> V transformFromLinkedHaspMapToObject(Object linkedList, Class<V> klazz) {
ObjectMapper mapper = new ObjectMapper();
TypeFactory t = TypeFactory.defaultInstance();
return mapper.convertValue( linkedList, t.constructCollectionType( ArrayList.class, klazz ) );
}
Спасибо заранее