Ho due domande:
- Come mappare un elenco di oggetti JSON usando Spring RestTemplate.
- Come mappare oggetti JSON nidificati.
Sto cercando di consumare https://bitpay.com/api/rates , seguendo il tutorial da http://spring.io/guides/gs/consuming-rest/ .
Ho due domande:
Sto cercando di consumare https://bitpay.com/api/rates , seguendo il tutorial da http://spring.io/guides/gs/consuming-rest/ .
Risposte:
Forse in questo modo ...
ResponseEntity<Object[]> responseEntity = restTemplate.getForEntity(urlGETList, Object[].class);
Object[] objects = responseEntity.getBody();
MediaType contentType = responseEntity.getHeaders().getContentType();
HttpStatus statusCode = responseEntity.getStatusCode();
Codice controller per il RequestMapping
@RequestMapping(value="/Object/getList/", method=RequestMethod.GET)
public @ResponseBody List<Object> findAllObjects() {
List<Object> objects = new ArrayList<Object>();
return objects;
}
ResponseEntity
è un'estensione HttpEntity
che aggiunge un HttpStatus
codice di stato. Utilizzato in RestTemplate
oltre @Controller
metodi. In RestTemplate
questa classe viene restituito da getForEntity()
e exchange()
.
Definire innanzitutto un oggetto per trattenere l'entità che ritorna nell'array. Ad es
@JsonIgnoreProperties(ignoreUnknown = true)
public class Rate {
private String name;
private String code;
private Double rate;
// add getters and setters
}
Quindi è possibile utilizzare il servizio e ottenere un elenco fortemente tipizzato tramite:
ResponseEntity<List<Rate>> rateResponse =
restTemplate.exchange("https://bitpay.com/api/rates",
HttpMethod.GET, null, new ParameterizedTypeReference<List<Rate>>() {
});
List<Rate> rates = rateResponse.getBody();
Anche le altre soluzioni sopra funzioneranno, ma mi piace recuperare un elenco fortemente tipizzato anziché un oggetto [].
restTemplate.exchange
a marshallar mappa tutti i valori json con i nomi delle chiavi corrispondenti come proprietà nell'oggetto Rate. Spero che il mio processo di pensiero sia corretto.
Per me ha funzionato
Object[] forNow = template.getForObject("URL", Object[].class);
searchList= Arrays.asList(forNow);
Dove Object è la classe che desideri
Coupon[] coupons = restTemplate.getForObject( url, Coupon[].class)
[]
ma totalmente vuoto). Quindi fai attenzione e controlla null
( if (forNow != null)...
).
Object.class
è specificato nel metodo getForObject()
.
Dopo più test, questo è il modo migliore che ho trovato :)
Set<User> test = httpService.get(url).toResponseSet(User[].class);
Tutto ciò che serve 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());
}
Il mio grosso problema qui era quello di costruire la struttura degli oggetti richiesta per abbinare RestTemplate a una classe compatibile. Fortunatamente ho trovato http://www.jsonschema2pojo.org/ (ottenere la risposta JSON in un browser e usarla come input) e non posso raccomandarlo abbastanza!
in realtà ho sviluppato qualcosa di funzionale per uno dei miei progetti prima ed ecco il codice:
/**
* @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;
}
}
Spero che questo possa aiutare qualcuno!
Se preferisci un Elenco di oggetti, un modo per farlo è in questo modo:
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 usalo così:
List<SomeObject> list = someService.getApi("http://localhost:8080/some/api",HttpMethod.GET);
La spiegazione di quanto sopra è disponibile qui ( https://www.baeldung.com/spring-rest-template-list ) ed è parafrasata di seguito.
"Ci sono un paio di cose che accadono nel codice sopra. In primo luogo, utilizziamo ResponseEntity come nostro tipo di ritorno, usandolo per racchiudere l'elenco di oggetti che vogliamo davvero. In secondo luogo, stiamo chiamando RestTemplate.exchange () invece di getForObject () .
Questo è il modo più generico di usare RestTemplate. Ci richiede di specificare il metodo HTTP, il corpo della richiesta opzionale e un tipo di risposta. In questo caso, utilizziamo una sottoclasse anonima di ParameterizedTypeReference per il tipo di risposta.
Quest'ultima parte è ciò che ci consente di convertire la risposta JSON in un elenco di oggetti del tipo appropriato. Quando creiamo una sottoclasse anonima di ParameterizedTypeReference, utilizza la riflessione per acquisire informazioni sul tipo di classe in cui vogliamo convertire la nostra risposta.
Conserva queste informazioni utilizzando l'oggetto Type di Java e non dobbiamo più preoccuparci della cancellazione del tipo. "
Considera di vedere questa risposta, specialmente se vuoi usare generici in List
Spring RestTemplate e tipi generici ParameterizedTypeReference come List <T>
Puoi creare POJO per ogni voce come,
class BitPay{
private String code;
private String name;
private double rate;
}
quindi utilizzando ParameterizedTypeReference dell'elenco di BitPay è possibile utilizzare come:
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();
Ho trovato lavoro in questo post https://jira.spring.io/browse/SPR-8263 .
Sulla base di questo post è possibile restituire un elenco digitato come questo:
ResponseEntity<? extends ArrayList<User>> responseEntity = restTemplate.getForEntity(restEndPointUrl, (Class<? extends ArrayList<User>>)ArrayList.class, userId);
getForEntity
. (Class<? extends ArrayList<User>>) ArrayList.class
Fornisce inoltre un errore di compilazione "tipi incompatibili".