Cannot deserialize instance of object out of START_ARRAY token in Spring Webservice

I'm currently having trouble connecting to my webservice on android. I use jackson-core/databind/annotation-2.2.4 and Spring RESTWebService. If I access the URL from the browser I can see the JSON response: (server return List\Shop\ looks like:)

[{"name":"shopqwe","mobiles":[],"address":{"town":"city",
"street":"streetqwe","streetNumber":"59","cordX":2.229997,"cordY":1.002539},
"shoe" [{"shoeName":"addidas","number":"631744030","producent":"nike","price":999.0,
"sizes":[30.0,35.0,38.0]}]

From a Client endpoint (Android application) I receive this error message:

08-26 17:43:07.406: E/AllShopsAsyc(28203): Could not read JSON: Can not deserialize
instance of com.auginzynier.data.ShopContainer out of START_ARRAY token
08-26 17:43:07.406: E/AllShopsAsyc(28203):  at [Source:
com.android.okhttp.internal.http.HttpTransport$ChunkedInputStream@41efbd48; line: 1,
column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException:
Can not deserialize instance of com.auginzynier.data.ShopContainer out of START_ARRAY
token
08-26 17:43:07.406: E/AllShopsAsyc(28203):  at [Source:
com.android.okhttp.internal.http.HttpTransport$ChunkedInputStream@41efbd48; line: 1,
column: 1]
08-26 17:43:07.406: E/AllShopsAsyc(28203):
org.springframework.http.converter.HttpMessageNotReadableException: Could not read
JSON: Can not deserialize instance of com.auginzynier.data.ShopContainer out of
START_ARRAY token

My server request

RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
ShopContainer response  = restTemplate.getForObject(url, ShopContainer.class);

where ShopContainer is:

public class ShopContainer {
private List<Shop> shops;

structure of Shop, Address and Shoe is : (I've omitted getters and setters):

public class Shop {
@JsonProperty("name")    private String name;
@JsonProperty("mobiles")   private List<String> mobiles = new ArrayList<String>();
@JsonProperty("address")   private Address address;
@JsonProperty("shoe") private List<Shoe> shoe = new ArrayList<Shoe>();


public class Address {
@JsonProperty("town") private String town;
@JsonProperty("street") private String street;
@JsonProperty("streetNumber") private String streetNumber;
@JsonProperty("cordX") private Double cordX;
@JsonProperty("cordY") private Double cordY;


public class Shoe {
@JsonProperty("shoeName") private String shoeName;
@JsonProperty("number") private String number;
@JsonProperty("producent") private String producent;
@JsonProperty("price") private Double price;
@JsonProperty("sizes") private List<Double> sizes = new ArrayList<Double>();

I've look here and on google but still can't figure out what I am missing at this point.

Any response would be greatly helpful.

Regards.

@UPDATE

I've fixed the JSON by using jackson's ObjectMapper with RequestMethod.GET. It now returns a String.

list is List<Shop>


ObjectMapper mapper = new ObjectMapper();
mapper.writeValue(new File("D:\\Android\\shop.json"), list);
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(list));
return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(list);

控制台中的JSON如下所示:

[ {
"name" : "shopqwe",
"mobiles" : [ ],
"address" : {
"town" : "city",
"street" : "streetqwe",
"streetNumber" : "59",
"cordX" : 2.229997,
"cordY" : 2.002539
},
"shoe" : [ {
"shoeName" : "addidas",
"number" : "631744033",
"producent" : "nike",
"price" : 10.0,
"sizes" : [ 30.0, 35.0, 38.0 ]
} ]
} ]

Request still doesn't work - error is the same.

231906 次浏览

Taking for granted that the JSON you posted is actually what you are seeing in the browser, then the problem is the JSON itself.

The JSON snippet you have posted is malformed.

You have posted:

[{
"name" : "shopqwe",
"mobiles" : [],
"address" : {
"town" : "city",
"street" : "streetqwe",
"streetNumber" : "59",
"cordX" : 2.229997,
"cordY" : 1.002539
},
"shoe"[{
"shoeName" : "addidas",
"number" : "631744030",
"producent" : "nike",
"price" : 999.0,
"sizes" : [30.0, 35.0, 38.0]
}]

while the correct JSON would be:

[{
"name" : "shopqwe",
"mobiles" : [],
"address" : {
"town" : "city",
"street" : "streetqwe",
"streetNumber" : "59",
"cordX" : 2.229997,
"cordY" : 1.002539
},
"shoe" : [{
"shoeName" : "addidas",
"number" : "631744030",
"producent" : "nike",
"price" : 999.0,
"sizes" : [30.0, 35.0, 38.0]
}
]
}
]

Your json contains an array, but you're trying to parse it as an object. This error occurs because objects must start with {.

You have 2 options:

  1. You can get rid of the ShopContainer class and use Shop[] instead

    ShopContainer response  = restTemplate.getForObject(
    url, ShopContainer.class);
    

    replace with

    Shop[] response  = restTemplate.getForObject(url, Shop[].class);
    

    and then make your desired object from it.

  2. You can change your server to return an object instead of a list

    return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(list);
    

    replace with

    return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(
    new ShopContainer(list));
    

I've had a very similar issue using spring-boot-starter-data-redis. To my implementation there was offered a @Bean for RedisTemplate as follows:

@Bean
public RedisTemplate<String, List<RoutePlantCache>> redisTemplate(RedisConnectionFactory connectionFactory) {
final RedisTemplate<String, List<RoutePlantCache>> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new Jackson2JsonRedisSerializer<>(RoutePlantCache.class));


// Add some specific configuration here. Key serializers, etc.
return template;
}

The fix was to specify an array of RoutePlantCache as following:

template.setValueSerializer(new Jackson2JsonRedisSerializer<>(RoutePlantCache[].class));

Below the exception I had:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `[...].RoutePlantCache` out of START_ARRAY token
at [Source: (byte[])"[{ ... },{ ... [truncated 1478 bytes]; line: 1, column: 1]
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59) ~[jackson-databind-2.11.4.jar:2.11.4]
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1468) ~[jackson-databind-2.11.4.jar:2.11.4]
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1242) ~[jackson-databind-2.11.4.jar:2.11.4]
at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1190) ~[jackson-databind-2.11.4.jar:2.11.4]
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeFromArray(BeanDeserializer.java:604) ~[jackson-databind-2.11.4.jar:2.11.4]
at com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:190) ~[jackson-databind-2.11.4.jar:2.11.4]
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:166) ~[jackson-databind-2.11.4.jar:2.11.4]
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4526) ~[jackson-databind-2.11.4.jar:2.11.4]
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3572) ~[jackson-databind-2.11.4.jar:2.11.4]

In my case, I had an incorrect return type. The return type was UserPost but it was supposed to be List and this addresses the previous approaches mentioned as above

Before


fun getApiCallResponse(): UserPost {
val userPosts = HttpClientHelper.getUserPostsUrl()
val response = memberHttpHelper.get(userPosts)
return jacksonUtils.fromJson(response, object :
TypeReference<ArrayList<UserPost>>() {})
}


After


fun getApiCallResponse(): List<UserPost> {
val userPosts = HttpClientHelper.getUserPostsUrl()
val response = memberHttpHelper.get(userPosts)
return jacksonUtils.fromJson(response, object :
TypeReference<ArrayList<UserPost>>() {})
}