Obtenga una lista de objetos JSON con Spring RestTemplate

Respuestas:

220

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().

kamokaze
fuente
Eso funcionó de maravilla, gracias. ¿Quizás pueda dirigirme a otros tutoriales o guías que pueda leer sobre este tema?
Karudi
2
es mejor mirar aquí en stackoverflow para ver algunos fragmentos de código y ejemplos, o visitar el sitio web oficial de Spring ...... TblGps [] a = responseEntity.getBody ();
kamokaze
¿Es posible esto usando genéricos? es decir, mi método tiene un parámetro Clase <T extiende Foo> y me gustaría obtener una colección de T del método getForEntity.
Diskutant
Sí, debería funcionar, pero puede que no esté listo para usar, dependiendo de su versión Spring / Jackson y sus tipos de clase. Se trata de serializar / deserializar genéricos: a la Solicitud http no le importa lo que se transporta.
kamokaze
1
Ver también forum.spring.io/forum/spring-projects/android/… .
Benny Bottema
335

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 [].

Mate
fuente
66
Esta ejecución es fluida con Spring 4.2.3 y, como dijo Matt, tiene la gran ventaja de evitar el Objeto []
Marcado el
@Matt: ¿qué mariscal estás utilizando para ordenar el json en los objetos Rate? Supongo que eso es lo que está sucediendo aquí, en el momento en que 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.
Nirmal
Perfecto, funciona bien en Spring Boot 1.4.0. LIBERACIÓN Gracias
Anand
1
@Nirmal Spring usa Jackson por defecto, creo.
Sohaib
1
@SarvarNishonboev, la referencia actual ParameterizedType de springframework.core todavía parece estar bien: docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
fspinnenhirn
75

Para mi esto funcionó

Object[] forNow = template.getForObject("URL", Object[].class);
    searchList= Arrays.asList(forNow);

Donde Object es la clase que quieres

Yonia
fuente
16
Esto funciona incluso si usa una clase y no un objeto comoCoupon[] coupons = restTemplate.getForObject( url, Coupon[].class)
lrkwz
1
Esto puede causar NPE si el cuerpo de respuesta HTTP estaba vacío (no []pero totalmente vacío). Así que tenga cuidado y verifique null( if (forNow != null)...).
Ruslan Stelmachenko
1
Salvó mi trasero :) Me pregunto qué tipo es utilizado por Jackson, cuando Object.classse especifica en el método getForObject().
Eric Wang
5

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());
}
Romain-p
fuente
Nota: esto requiere guayaba
vphilipnyc
2

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.

en el norte
fuente
2

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!

Hamza Jeljeli
fuente
1

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 ".

Toofy
fuente
1

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();
Nitin Pawar
fuente
-1

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);
Shravan Ramamurthy
fuente
44
Esto no funcionará porque, debido a la eliminación, no se pasa información de parámetros de tipo getForEntity. También (Class<? extends ArrayList<User>>) ArrayList.classda un error de compilación de "tipos incompatibles".
Esko Luontola