Не удалось прочитать JSON: невозможно десериализовать экземпляр hello.Country[] из маркера START_OBJECT
У меня есть URL для отдыха, который дает мне все страны - http://api.geonames.org/countryInfoJSON?username=volodiaL.
Я использую RestTemplate из весны 3, чтобы разобрать возвращенный JSON в Java-объекты:
RestTemplate restTemplate = new RestTemplate();
Country[] countries = restTemplate.getForObject("http://api.geonames.org/countryInfoJSON?username=volodiaL",Country[].class);
Когда я запускаю этот код, я получаю исключение:
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
Наконец-то мой кантри класс:
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;
}
}
Проблема в том, что возвращаемый json содержит корневой элемент "geonames", который содержит массив элементов страны, например:
{
"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"
}
]
}
Как сказать RestTemplate
преобразовать каждый элемент массива в Country
объект?
5 ответов
Вам нужно сделать следующее:
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();
Было бы здорово, если бы вы могли использовать какую-то аннотацию, чтобы пропустить уровни, но это пока невозможно (см. Это и это)
Другое решение:
public class CountryInfoResponse {
private List<Object> geonames;
}
Использование универсального Object-List решило мою проблему, так как были и другие типы данных, такие как Boolean.
В моем случае я получал значение <input type="text">
с JQuery, и я сделал это так:
var newUserInfo = { "lastName": inputLastName[0].value, "userName": inputUsername[0].value,
"firstName": inputFirstName[0] , "email": inputEmail[0].value}
И я постоянно получал это исключение
com.fasterxml.jackson.databind.JsonMappingException: Невозможно десериализовать экземпляр java.lang.String из токена START_OBJECT в [Source: java.io.PushbackInputStream@39cb6c98; строка: 1, столбец: 54] (через цепочку ссылок: com.springboot.domain.User["firstName"]).
И я бился в течение часа, пока не понял, что забыл написать .value
после этого"firstName": inputFirstName[0]
,
Итак, правильное решение было:
var newUserInfo = { "lastName": inputLastName[0].value, "userName": inputUsername[0].value,
"firstName": inputFirstName[0].value , "email": inputEmail[0].value}
Я пришел сюда, потому что у меня была эта проблема, и я надеюсь, что я спасу еще несколько часов страданий.
Ура:)
Если вы хотите избежать использования дополнительных Class
а также List<Object> genomes
Вы могли бы просто использовать Map
,
Структура данных переводится в 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");
Для Spring-boot 1.3.3 метод exchange() для List работает как в соответствующем ответе