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

AndroidJsonSpringWeb ServicesJackson

Android Problem Overview


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 in console looks like:

[ {  "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.

Android Solutions


Solution 1 - Android

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.

  1. 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));

Solution 2 - Android

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]
			}
		]
	}
]

Solution 3 - Android

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]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDaramView Question on Stackoverflow
Solution 1 - AndroidOrdonView Answer on Stackoverflow
Solution 2 - AndroidgeoandView Answer on Stackoverflow
Solution 3 - AndroidRadu LinuView Answer on Stackoverflow