Tengo dos preguntas:
- Cómo mapear una lista de objetos JSON usando Spring RestTemplate.
- Cómo mapear objetos JSON anidados.
Estoy tratando de consumir https://bitpay.com/api/rates , siguiendo el tutorial de http://spring.io/guides/gs/consuming-rest/ .
Tengo dos preguntas:
Estoy tratando de consumir https://bitpay.com/api/rates , siguiendo el tutorial de http://spring.io/guides/gs/consuming-rest/ .
Respuestas:
Quizás de esta manera ...
ResponseEntity<Object[]> responseEntity = restTemplate.getForEntity(urlGETList, Object[].class);
Object[] objects = responseEntity.getBody();
MediaType contentType = responseEntity.getHeaders().getContentType();
HttpStatus statusCode = responseEntity.getStatusCode();
Código de controlador para el RequestMapping
@RequestMapping(value="/Object/getList/", method=RequestMethod.GET)
public @ResponseBody List<Object> findAllObjects() {
List<Object> objects = new ArrayList<Object>();
return objects;
}
ResponseEntityes una extensión de HttpEntityque agrega un HttpStatuscódigo de estado. Utilizado RestTemplatetambién en @Controllermétodos. En RestTemplateesta clase es devuelto por getForEntity()y exchange().
Primero defina un objeto para contener la entidad que regresa a la matriz. Ej.
@JsonIgnoreProperties(ignoreUnknown = true)
public class Rate {
private String name;
private String code;
private Double rate;
// add getters and setters
}
Entonces puede consumir el servicio y obtener una lista fuertemente tipada a través de:
ResponseEntity<List<Rate>> rateResponse =
restTemplate.exchange("https://bitpay.com/api/rates",
HttpMethod.GET, null, new ParameterizedTypeReference<List<Rate>>() {
});
List<Rate> rates = rateResponse.getBody();
Las otras soluciones anteriores también funcionarán, pero me gusta recuperar una lista fuertemente tipada en lugar de un Object [].
restTemplate.exchangeun marshallar asigna todos los valores json a los nombres de claves coincidentes como propiedades en el objeto Rate. Espero que mi proceso de pensamiento sea correcto.
Para mi esto funcionó
Object[] forNow = template.getForObject("URL", Object[].class);
searchList= Arrays.asList(forNow);
Donde Object es la clase que quieres
Coupon[] coupons = restTemplate.getForObject( url, Coupon[].class)
[]pero totalmente vacío). Así que tenga cuidado y verifique null( if (forNow != null)...).
Object.classse especifica en el método getForObject().
Después de múltiples pruebas, esta es la mejor manera que encontré :)
Set<User> test = httpService.get(url).toResponseSet(User[].class);
Todo lo que necesitas allí
public <T> Set<T> toResponseSet(Class<T[]> setType) {
HttpEntity<?> body = new HttpEntity<>(objectBody, headers);
ResponseEntity<T[]> response = template.exchange(url, method, body, setType);
return Sets.newHashSet(response.getBody());
}
Mi gran problema aquí fue construir la estructura de Objeto requerida para hacer coincidir RestTemplate con una Clase compatible. Afortunadamente encontré http://www.jsonschema2pojo.org/ (obtengo la respuesta JSON en un navegador y la uso como entrada) y no puedo recomendarlo lo suficiente.
De hecho, desarrollé algo funcional para uno de mis proyectos antes y aquí está el código:
/**
* @param url is the URI address of the WebService
* @param parameterObject the object where all parameters are passed.
* @param returnType the return type you are expecting. Exemple : someClass.class
*/
public static <T> T getObject(String url, Object parameterObject, Class<T> returnType) {
try {
ResponseEntity<T> res;
ObjectMapper mapper = new ObjectMapper();
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
((SimpleClientHttpRequestFactory) restTemplate.getRequestFactory()).setConnectTimeout(2000);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<T> entity = new HttpEntity<T>((T) parameterObject, headers);
String json = mapper.writeValueAsString(restTemplate.exchange(url, org.springframework.http.HttpMethod.POST, entity, returnType).getBody());
return new Gson().fromJson(json, returnType);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
/**
* @param url is the URI address of the WebService
* @param parameterObject the object where all parameters are passed.
* @param returnType the type of the returned object. Must be an array. Exemple : someClass[].class
*/
public static <T> List<T> getListOfObjects(String url, Object parameterObject, Class<T[]> returnType) {
try {
ObjectMapper mapper = new ObjectMapper();
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8")));
((SimpleClientHttpRequestFactory) restTemplate.getRequestFactory()).setConnectTimeout(2000);
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<T> entity = new HttpEntity<T>((T) parameterObject, headers);
ResponseEntity<Object[]> results = restTemplate.exchange(url, org.springframework.http.HttpMethod.POST, entity, Object[].class);
String json = mapper.writeValueAsString(results.getBody());
T[] arr = new Gson().fromJson(json, returnType);
return Arrays.asList(arr);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
¡Espero que esto ayude a alguien!
Si prefiere una Lista de objetos, una forma de hacerlo es así:
public <T> List<T> getApi(final String path, final HttpMethod method) {
final RestTemplate restTemplate = new RestTemplate();
final ResponseEntity<List<T>> response = restTemplate.exchange(
path,
method,
null,
new ParameterizedTypeReference<List<T>>(){});
List<T> list = response.getBody();
return list;
}
Y úsalo así:
List<SomeObject> list = someService.getApi("http://localhost:8080/some/api",HttpMethod.GET);
La explicación de lo anterior se puede encontrar aquí ( https://www.baeldung.com/spring-rest-template-list ) y se parafrasea a continuación.
"Hay un par de cosas que suceden en el código anterior. Primero, usamos ResponseEntity como nuestro tipo de retorno, usándolo para ajustar la lista de objetos que realmente queremos. Segundo, estamos llamando a RestTemplate.exchange () en lugar de getForObject () .
Esta es la forma más genérica de usar RestTemplate. Requiere que especifiquemos el método HTTP, el cuerpo de solicitud opcional y un tipo de respuesta. En este caso, utilizamos una subclase anónima de ParameterizedTypeReference para el tipo de respuesta.
Esta última parte es lo que nos permite convertir la respuesta JSON en una lista de objetos que son del tipo apropiado. Cuando creamos una subclase anónima de ParameterizedTypeReference, utiliza la reflexión para capturar información sobre el tipo de clase al que queremos convertir nuestra respuesta.
Conserva esta información utilizando el objeto Type de Java, y ya no tenemos que preocuparnos por el borrado de tipo ".
Considere ver esta respuesta, especialmente si desea usar genéricos en List
Spring RestTemplate y tipos genéricos ParameterizedTypeReference colecciones como List <T>
Puede crear POJO para cada entrada como,
class BitPay{
private String code;
private String name;
private double rate;
}
luego usando ParameterizedTypeReference of List of BitPay puede usarlo como:
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<List<Employee>> response = restTemplate.exchange(
"https://bitpay.com/api/rates",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<BitPay>>(){});
List<Employee> employees = response.getBody();
Encontré trabajo en esta publicación https://jira.spring.io/browse/SPR-8263 .
Según esta publicación, puede devolver una lista escrita como esta:
ResponseEntity<? extends ArrayList<User>> responseEntity = restTemplate.getForEntity(restEndPointUrl, (Class<? extends ArrayList<User>>)ArrayList.class, userId);
getForEntity. También (Class<? extends ArrayList<User>>) ArrayList.classda un error de compilación de "tipos incompatibles".