Obter lista de objetos JSON com Spring RestTemplate

Respostas:

220

Talvez assim ...

ResponseEntity<Object[]> responseEntity = restTemplate.getForEntity(urlGETList, Object[].class);
Object[] objects = responseEntity.getBody();
MediaType contentType = responseEntity.getHeaders().getContentType();
HttpStatus statusCode = responseEntity.getStatusCode();

Código do controlador para o RequestMapping

@RequestMapping(value="/Object/getList/", method=RequestMethod.GET)
public @ResponseBody List<Object> findAllObjects() {

    List<Object> objects = new ArrayList<Object>();
    return objects;
}

ResponseEntityé uma extensão HttpEntityque adiciona um HttpStatuscódigo de status. Usado RestTemplatetambém em @Controllermétodos. Em RestTemplateesta classe é retornado por getForEntity()e exchange().

kamokaze
fonte
Isso funcionou como um encanto, obrigado. Talvez você possa me direcionar para outros tutoriais ou guias que eu possa ler sobre esse tópico?
Karudi 15/05
2
é melhor procurar aqui no stackoverflow alguns exemplos de trechos de código ou visitar o site oficial da primavera ...... TblGps [] a = responseEntity.getBody ();
Kamokaze 15/05
É possível isso usando genéricos? ou seja, meu método possui um parâmetro Classe <T estende Foo> e eu gostaria de obter uma coleção de T a partir do método getForEntity.
Diskutant
Sim, deve funcionar, mas pode não estar pronto para uso, dependendo da sua versão spring / jackson e do tipo de classe. É tudo sobre serialização / desserialização de genéricos - a Solicitação http não se importa com o que é transportado.
precisa saber é o seguinte
1
Consulte também forum.spring.io/forum/spring-projects/android/… .
Benny Bottema 11/03/16
335

Primeiro defina um objeto para manter a entidade retornando à matriz.

@JsonIgnoreProperties(ignoreUnknown = true)
public class Rate {
    private String name;
    private String code;
    private Double rate;
    // add getters and setters
}

Em seguida, você pode consumir o serviço e obter uma lista fortemente tipada via:

ResponseEntity<List<Rate>> rateResponse =
        restTemplate.exchange("https://bitpay.com/api/rates",
                    HttpMethod.GET, null, new ParameterizedTypeReference<List<Rate>>() {
            });
List<Rate> rates = rateResponse.getBody();

As outras soluções acima também funcionarão, mas eu gosto de obter uma lista fortemente tipada de volta em vez de um Object [].

Matt
fonte
6
Esta execução é suavemente com Spring 4.2.3 e - como disse Matt - tem a grande vantagem de evitar o objecto []
Marged
@ Matt - qual marshaller você está usando para organizar o json em objetos Rate? Suponho que é o que está acontecendo aqui, no momento em que restTemplate.exchangeum marshallar mapeia todos os valores json para os nomes de chaves correspondentes como propriedades no objeto Rate. Espero que meu processo de pensamento esteja correto.
Nirmal 28/03
Perfeito, funciona bem na Primavera Bota 1.4.0.RELEASE Graças
Anand
1
@Nirmal Spring usa Jackson por padrão, eu acredito.
Sohaib
1
@SarvarNishonboev o atual ParameterizedTypeReference de springframework.core ainda parece bom: docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
fspinnenhirn
75

Para mim isso funcionou

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

Onde Object é a classe que você deseja

yonia
fonte
16
Isso funciona mesmo se você usar uma classe e não um objeto como # Coupon[] coupons = restTemplate.getForObject( url, Coupon[].class)
lrkwz
1
Isso pode causar o NPE se o corpo da resposta HTTP estiver vazio (não []mas totalmente vazio). Portanto, tenha cuidado e verifique null( if (forNow != null)...).
Ruslan Stelmachenko
1
Salvei minha bunda :) Querendo saber que tipo é usado por Jackson, quando Object.classé especificado no método getForObject().
Eric Wang
5

Após vários testes, esta é a melhor maneira que encontrei :)

Set<User> test = httpService.get(url).toResponseSet(User[].class);

Tudo o que você precisa lá

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
fonte
Nota: isso requer goiaba
vphilipnyc
2

Meu grande problema aqui foi criar a estrutura de objetos necessária para corresponder o RestTemplate a uma classe compatível. Felizmente eu encontrei http://www.jsonschema2pojo.org/ (obtenha a resposta JSON em um navegador e use-a como entrada) e não posso recomendar isso o suficiente!

para o norte
fonte
2

Na verdade, eu desenvolvi algo funcional para um dos meus projetos antes e aqui está o 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 isso ajude alguém!

Hamza Jeljeli
fonte
1

Se você preferir uma lista de objetos, uma maneira de fazer isso é assim:

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;
}

E use-o assim:

 List<SomeObject> list = someService.getApi("http://localhost:8080/some/api",HttpMethod.GET);

A explicação para o acima pode ser encontrada aqui ( https://www.baeldung.com/spring-rest-template-list ) e é parafraseada abaixo.

"Há algumas coisas acontecendo no código acima. Primeiro, usamos ResponseEntity como nosso tipo de retorno, para envolvê-la na lista de objetos que realmente queremos. Segundo, estamos chamando RestTemplate.exchange () em vez de getForObject () .

Essa é a maneira mais genérica de usar o RestTemplate. Ele exige que especifiquemos o método HTTP, o corpo opcional da solicitação e um tipo de resposta. Nesse caso, usamos uma subclasse anônima de ParameterizedTypeReference para o tipo de resposta.

Esta última parte é o que nos permite converter a resposta JSON em uma lista de objetos do tipo apropriado. Quando criamos uma subclasse anônima de ParameterizedTypeReference, ele usa reflexão para capturar informações sobre o tipo de classe para o qual queremos converter nossa resposta.

Ele se apega a essas informações usando o objeto Type do Java e não precisamos mais nos preocupar com o apagamento do tipo ".

Toofy
fonte
1

Você pode criar POJO para cada entrada, como

class BitPay{
private String code;
private String name;
private double rate;
}

usando ParameterizedTypeReference of List of BitPay, você pode usar 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
fonte
-1

Encontrei uma solução alternativa para este post https://jira.spring.io/browse/SPR-8263 .

Com base nesta postagem, você pode retornar uma lista digitada assim:

ResponseEntity<? extends ArrayList<User>> responseEntity = restTemplate.getForEntity(restEndPointUrl, (Class<? extends ArrayList<User>>)ArrayList.class, userId);
Shravan Ramamurthy
fonte
4
Isso não funcionará porque, devido ao apagamento, nenhuma informação de parâmetro de tipo é passada para getForEntity. Também (Class<? extends ArrayList<User>>) ArrayList.classfornece um erro de compilação "tipos incompatíveis".
Esko Luontola