Ruft eine Liste der JSON-Objekte mit Spring RestTemplate ab


199

Ich habe zwei Fragen:

  • So ordnen Sie eine Liste von JSON-Objekten mit Spring RestTemplate zu.
  • So ordnen Sie verschachtelte JSON-Objekte zu

Ich versuche, https://bitpay.com/api/rates zu konsumieren , indem ich dem Tutorial von http://spring.io/guides/gs/consuming-rest/ folge .


2
Betrachten Sie diese Antwort, insbesondere wenn Sie die Generika-Liste stackoverflow.com/questions/36915823/…
Moesio

Antworten:


220

Vielleicht so ...

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

Controller-Code für die RequestMapping

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

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

ResponseEntityist eine Erweiterung HttpEntity, die einen HttpStatusStatuscode hinzufügt . Verwendet in RestTemplateals auch @ControllerMethoden. In RestTemplatedieser Klasse wird von getForEntity()und zurückgegeben exchange().


Das hat wie ein Zauber funktioniert, danke. Vielleicht können Sie mich auf andere Tutorials oder Anleitungen verweisen, die ich zu diesem Thema lesen könnte?
Karudi

2
Am besten schauen Sie hier auf stackoverflow nach Code-Schnipsel und Beispielen oder besuchen Sie die Website von offial spring ...... TblGps [] a = responseEntity.getBody ();
Kamokaze

Ist dies mit Generika möglich? Das heißt, meine Methode hat einen Parameter der Klasse <T erweitert Foo> und ich möchte eine Sammlung von T von der Methode getForEntity erhalten.
Diskutant

Ja, es sollte funktionieren, ist aber abhängig von Ihrer Spring / Jackson-Version und Ihren Klassentypen möglicherweise nicht sofort einsatzbereit. Es geht nur um das Serialisieren / Deserialisieren von Generika - der http-Anfrage ist es egal, was transportiert wird.
Kamokaze


335

Definieren Sie zuerst ein Objekt, das die Entität enthält, die im Array zurückkommt. ZB

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

Dann können Sie den Dienst nutzen und eine stark typisierte Liste erhalten über:

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

Die anderen oben genannten Lösungen funktionieren ebenfalls, aber ich möchte eine stark typisierte Liste anstelle eines Objekts [] zurückerhalten.


6
Dieser Lauf läuft reibungslos mit Spring 4.2.3 und hat - wie Matt sagte - den großen Vorteil, das Objekt [] zu
meiden

@Matt - Mit welchem ​​Marshaller können Sie den JSON in Rate-Objekte umwandeln? Ich vermute, dass dies hier passiert. Zum Zeitpunkt des restTemplate.exchangeMarshalls werden alle JSON-Werte den übereinstimmenden Schlüsselnamen als Eigenschaften im Rate-Objekt zugeordnet. Hoffe mein Denkprozess ist richtig.
Nirmal

Perfekt, funktioniert gut in Spring Boot 1.4.0.RELEASE Danke
Anand

1
@Nirmal Spring verwendet standardmäßig Jackson, glaube ich.
Sohaib

1
@SarvarNishonboev die aktuelle ParameterizedTypeReference von springframework.core scheint immer noch in Ordnung zu sein: docs.spring.io/spring-framework/docs/current/javadoc-api/org/…
fspinnenhirn

75

Bei mir hat das geklappt

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

Wobei Objekt die gewünschte Klasse ist


16
Dies funktioniert auch, wenn Sie eine Klasse und kein Objekt wieCoupon[] coupons = restTemplate.getForObject( url, Coupon[].class)
lrkwz

1
Dies kann zu NPE führen, wenn der HTTP-Antworttext leer war (nicht, []aber vollständig leer). Seien Sie also vorsichtig und suchen Sie nach null( if (forNow != null)...).
Ruslan Stelmachenko

1
Ich habe meinen Arsch gerettet :) Ich frage mich, welcher Typ von Jackson verwendet wird, wann Object.classin der Methode angegeben getForObject().
Eric Wang

5

Nach mehreren Tests ist dies der beste Weg, den ich gefunden habe :)

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

Alles was Sie dort brauchen

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

Hinweis: Dies erfordert Guava
vphilipnyc

2

Mein großes Problem dabei war, die Objektstruktur zu erstellen, die erforderlich ist, um RestTemplate einer kompatiblen Klasse zuzuordnen. Zum Glück habe ich http://www.jsonschema2pojo.org/ gefunden (erhalte die JSON-Antwort in einem Browser und verwende sie als Eingabe) und kann dies nicht genug empfehlen!


2

Ich habe tatsächlich etwas Funktionales für eines meiner Projekte entwickelt und hier ist der Code:

/**
 * @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;
    }
}

Ich hoffe, dass dies jemandem helfen wird!


1

Wenn Sie eine Liste von Objekten bevorzugen, können Sie dies folgendermaßen tun:

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

Und benutze es so:

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

Erklärungen zu den oben genannten Themen finden Sie hier ( https://www.baeldung.com/spring-rest-template-list ) und werden im Folgenden umschrieben.

"Im obigen Code passieren einige Dinge. Erstens verwenden wir ResponseEntity als Rückgabetyp, um die Liste der Objekte zu umbrechen, die wir wirklich wollen. Zweitens rufen wir RestTemplate.exchange () anstelle von getForObject () auf. .

Dies ist die allgemeinste Methode zur Verwendung von RestTemplate. Dazu müssen wir die HTTP-Methode, den optionalen Anforderungshauptteil und einen Antworttyp angeben. In diesem Fall verwenden wir eine anonyme Unterklasse von ParameterizedTypeReference für den Antworttyp.

Dieser letzte Teil ermöglicht es uns, die JSON-Antwort in eine Liste von Objekten des entsprechenden Typs zu konvertieren. Wenn wir eine anonyme Unterklasse von ParameterizedTypeReference erstellen, werden mithilfe der Reflektion Informationen zum Klassentyp erfasst, in den unsere Antwort konvertiert werden soll.

Diese Informationen werden mithilfe des Type-Objekts von Java beibehalten, und wir müssen uns nicht mehr um das Löschen von Typen kümmern. "



1

Sie können POJO für jeden Eintrag erstellen, wie z.

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

Verwenden Sie dann ParameterizedTypeReference der Liste von BitPay, um Folgendes zu verwenden:

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

Ich habe in diesem Beitrag https://jira.spring.io/browse/SPR-8263 Arbeit gefunden .

Basierend auf diesem Beitrag können Sie eine typisierte Liste wie folgt zurückgeben:

ResponseEntity<? extends ArrayList<User>> responseEntity = restTemplate.getForEntity(restEndPointUrl, (Class<? extends ArrayList<User>>)ArrayList.class, userId);

4
Dies funktioniert nicht, da aufgrund des Löschens keine Typparameterinformationen an übergeben werden getForEntity. Auch (Class<? extends ArrayList<User>>) ArrayList.classgibt einen „inkompatible Typen“ Compiler - Fehler.
Esko Luontola
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.