Java 无法读取 JSON:无法从 START_OBJECT 令牌中反序列化 hello.Country[] 的实例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24864489/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 15:17:13  来源:igfitidea点击:

Could not read JSON: Can not deserialize instance of hello.Country[] out of START_OBJECT token

javaspringresttemplatefasterxml

提问by Volodymyr Levytskyi

I have rest url that gives me all countries - http://api.geonames.org/countryInfoJSON?username=volodiaL.

我有给我所有国家/地区的休息 url - http://api.geonames.org/countryInfoJSON?username=volodiaL

I use RestTemplate from spring 3 to parse returned json into java objects:

我使用 Spring 3 中的 RestTemplate 将返回的 json 解析为 java 对象:

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

When I run this code I get an exception:

当我运行此代码时,出现异常:

Caused by: com.fasterxml.Hymanson.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.Hymanson.databind.JsonMappingException.from(JsonMappingException.java:164)
    at com.fasterxml.Hymanson.databind.DeserializationContext.mappingException(DeserializationContext.java:691)
    at com.fasterxml.Hymanson.databind.DeserializationContext.mappingException(DeserializationContext.java:685)
    at com.fasterxml.Hymanson.databind.deser.std.ObjectArrayDeserializer.handleNonArray(ObjectArrayDeserializer.java:222)
    at com.fasterxml.Hymanson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:133)
    at com.fasterxml.Hymanson.databind.deser.std.ObjectArrayDeserializer.deserialize(ObjectArrayDeserializer.java:18)
    at com.fasterxml.Hymanson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:2993)
    at com.fasterxml.Hymanson.databind.ObjectMapper.readValue(ObjectMapper.java:2158)
    at org.springframework.http.converter.json.MappingHymanson2HttpMessageConverter.readJavaType(MappingHymanson2HttpMessageConverter.java:225)
    ... 7 more

Finally my Country class:

最后我的乡村课:

import com.fasterxml.Hymanson.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;
    }
}

The problem is that returned json contains root element "geonames" which contains array of country elements like so:

问题是返回的 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"
    }
]
}

How to tell RestTemplateto convert each element of array into Countryobject?

如何告诉RestTemplate将数组的每个元素转换为Country对象?

采纳答案by geoand

You need to do the following:

您需要执行以下操作:

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

It would be great if you could use some kind of annotation to allow you to skip levels, but it's not yet possible (see thisand this)

如果您可以使用某种注释来允许您跳过级别,那就太好了,但目前还不可能(请参阅

回答by vonox7

Another solution:

另一种解决方案:

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

Usage of a generic Object-List solved my problem, as there were other Datatypes like Boolean too.

通用对象列表的使用解决了我的问题,因为还有其他数据类型,如布尔值。

回答by tyler

For Spring-boot 1.3.3 the method exchange() for List is working as in the related answer

对于 Spring-boot 1.3.3,List 的方法 exchange() 与相关答案一样工作

Spring Data Rest - _links

Spring Data Rest - _links

回答by Filip Savic

In my case, I was getting value of <input type="text">with JQuery and I did it like this:

就我而言,我<input type="text">使用 JQuery获得了价值,我是这样做的:

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

And I was constantly getting this exception

我不断收到这个例外

com.fasterxml.Hymanson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token at [Source: java.io.PushbackInputStream@39cb6c98; line: 1, column: 54] (through reference chain: com.springboot.domain.User["firstName"]).

com.fasterxml.Hymanson.databind.JsonMappingException:无法从 [来源:java.io.PushbackInputStream@39cb6c98; 的 START_OBJECT 令牌中反序列化 java.lang.String 的实例;行:1,列:54](通过参考链:com.springboot.domain.User["firstName"])。

And I banged my head for like an hour until I realised that I forgot to write .valueafter this"firstName": inputFirstName[0].

我敲了一个小时的头,直到我意识到我.value在这之后忘记写了"firstName": inputFirstName[0]

So, the correct solution was:

所以,正确的解决方案是:

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

I came here because I had this problem and I hope I save someone else hours of misery.

我来这里是因为我遇到了这个问题,我希望我能拯救别人几个小时的痛苦。

Cheers :)

干杯:)

回答by clD

If you want to avoid using an extra Classand List<Object> genomesyou could simply use a Map.

如果你想避免使用额外的ClassList<Object> genomes你可以简单地使用Map.

The data structure translates into Map<String, List<Country>>

数据结构转化为 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");