java spring resttemplate fasterxml

java - No se pudo leer JSON: no se puede deserializar la instancia de hello.Country[] fuera del token START_OBJECT



spring resttemplate (5)

Tengo URL de reposo que me da todos los países: http://api.geonames.org/countryInfoJSON?username=volodiaL .

Uso RestTemplate desde la primavera 3 para analizar json devuelto en objetos java:

RestTemplate restTemplate = new RestTemplate(); Country[] countries = restTemplate.getForObject("http://api.geonames.org/countryInfoJSON?username=volodiaL",Country[].class);

Cuando ejecuto este código obtengo una excepción:

Caused by: com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of hello.Country[] out of START_OBJECT token at [Source: sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@1846149; line: 1, column: 1] at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:164) at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:691) at com.fasterxml.jackson.databind.DeserializationContext.mappingException(DeserializationContext.java:685) at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.handleNonArray(ObjectArrayDeserializer.java:222) at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:133) at com.fasterxml.jackson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:18) at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2993) at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2158) at org.springframework.http.converter.json.MappingJackson2HttpMessageConverter.readJavaType(MappingJackson2HttpMessageConverter.java:225) ... 7 more

Finalmente mi clase Country:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonIgnoreProperties(ignoreUnknown = true) public class Country { private String countryName; private long geonameId; public String getCountryName() { return countryName; } public long getGeonameId() { return geonameId; } @Override public String toString() { return countryName; } }

El problema es que json devuelto contiene el elemento raíz "geonames" que contiene un conjunto de elementos de país como los siguientes:

{ "geonames": [ { "continent": "EU", "capital": "Andorra la Vella", "languages": "ca", "geonameId": 3041565, "south": 42.42849259876837, "isoAlpha3": "AND", "north": 42.65604389629997, "fipsCode": "AN", "population": "84000", "east": 1.7865427778319827, "isoNumeric": "020", "areaInSqKm": "468.0", "countryCode": "AD", "west": 1.4071867141112762, "countryName": "Andorra", "continentName": "Europe", "currencyCode": "EUR" } ] }

¿Cómo decirle a RestTemplate que convierta cada elemento de la matriz en un objeto Country ?


Debes hacer lo siguiente:

public class CountryInfoResponse { @JsonProperty("geonames") private List<Country> countries; //getter - setter } RestTemplate restTemplate = new RestTemplate(); List<Country> countries = restTemplate.getForObject("http://api.geonames.org/countryInfoJSON?username=volodiaL",CountryInfoResponse.class).getCountries();

Sería genial si pudieras usar algún tipo de anotación para permitirte saltear niveles, pero aún no es posible (mira this y this )


En mi caso, obtuve el valor de <input type="text"> con JQuery y lo hice así:

var newUserInfo = { "lastName": inputLastName[0].value, "userName": inputUsername[0].value, "firstName": inputFirstName[0] , "email": inputEmail[0].value}

Y constantemente recibía esta excepción

com.fasterxml.jackson.databind.JsonMappingException: no se puede deserializar la instancia de java.lang.String del token START_OBJECT en [Origen: java.io.PushbackInputStream@39cb6c98; línea: 1, columna: 54] (a través de la cadena de referencia: com.springboot.domain.User ["firstName"]).

Y me golpeé la cabeza por una hora hasta que me di cuenta de que olvidé escribir .value después de este "firstName": inputFirstName[0] .

Entonces, la solución correcta fue:

var newUserInfo = { "lastName": inputLastName[0].value, "userName": inputUsername[0].value, "firstName": inputFirstName[0].value , "email": inputEmail[0].value}

Vine aquí porque tenía este problema y espero salvar a alguien más horas de miseria.

Saludos :)


Otra solución:

public class CountryInfoResponse { private List<Object> geonames; }

El uso de una lista de objetos genéricos resolvió mi problema, ya que también había otros tipos de datos como Boolean.


Para Spring-boot 1.3.3, el método exchange () para List funciona como en la respuesta relacionada

Spring Data Rest - _links


Si desea evitar el uso de List<Object> genomes adicionales de Class y List<Object> genomes , puede simplemente usar un Map .

La estructura de datos se traduce en Map<String, List<Country>>

String resourceEndpoint = "http://api.geonames.org/countryInfoJSON?username=volodiaL"; Map<String, List<Country>> geonames = restTemplate.getForObject(resourceEndpoint, Map.class); List<Country> countries = geonames.get("geonames");