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


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


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


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


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

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!


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!


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



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

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

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
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.