170

Given the following .json file:

[
    {
        "name" : "New York",
        "number" : "732921",
        "center" : [
                "latitude" : 38.895111, 
                "longitude" : -77.036667
            ]
    },
    {
        "name" : "San Francisco",
        "number" : "298732",
        "center" : [
                "latitude" : 37.783333, 
                "longitude" : -122.416667
            ]
    }
]

I prepared two classes to represent the contained data:

public class Location {
    public String name;
    public int number;
    public GeoPoint center;
}

...

public class GeoPoint {
    public double latitude;
    public double longitude;
}

In order to parse the content from the .json file I use Jackson 2.2.x and prepared the following method:

public static List<Location> getLocations(InputStream inputStream) {
    ObjectMapper objectMapper = new ObjectMapper();
    try {
        TypeFactory typeFactory = objectMapper.getTypeFactory();
        CollectionType collectionType = typeFactory.constructCollectionType(
                                            List.class, Location.class);
        return objectMapper.readValue(inputStream, collectionType);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

As long as I leave out the center property all content can be parsed. However, when I try to parse the geo-coordinates I end up with the following error message:

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of
com.example.GeoPoint out of START_ARRAY token at [Source: android.content.res.AssetManager$AssetInputStream@416a5850; line: 5, column: 25]
(through reference chain: com.example.Location["center"])

Syscall
  • 19,327
  • 10
  • 37
  • 52
JJD
  • 50,076
  • 60
  • 203
  • 339
  • why are you using jackson if you can simply parse it with json parser – Smogger Oct 12 '13 at 10:38
  • 5
    Your JSON string is malformed, the type of `center` is an array of invalid objects. Try to replace `[` and `]` with `{` and `}` in the JSON string around `longitude` and `latitude` so they will be objects. – Katona Oct 12 '13 at 10:40
  • 1
    @Katona Thank you. Can you please convert your comment into an answer so I can close the question?! – JJD Oct 16 '13 at 15:47
  • I had the same error, but because I had used a LocalDate class. Once i added the missing JavaTimeModule with "mapper.registerModule(new JavaTimeModule());" , the problem went away. – codester Sep 28 '20 at 18:52

5 Answers5

186

JsonMappingException: out of START_ARRAY token exception is thrown by Jackson object mapper as it's expecting an Object {} whereas it found an Array [{}] in response.

This can be solved by replacing Object with Object[] in the argument for geForObject("url",Object[].class). References:

  1. Ref.1
  2. Ref.2
  3. Ref.3
Community
  • 1
  • 1
Abhijeet
  • 8,561
  • 5
  • 70
  • 76
  • 1
    For Kotliners here is an example: val result: ResponseEntity> = restTemplate.getForEntity(uri, Array::class.java) – Beezer Apr 28 '22 at 08:09
97

Your JSON string is malformed: the type of center is an array of invalid objects. Replace [ and ] with { and } in the JSON string around longitude and latitude so they will be objects:

[
    {
        "name" : "New York",
        "number" : "732921",
        "center" : {
                "latitude" : 38.895111, 
                "longitude" : -77.036667
            }
    },
    {
        "name" : "San Francisco",
        "number" : "298732",
        "center" : {
                "latitude" : 37.783333, 
                "longitude" : -122.416667
            }
    }
]
Katona
  • 4,816
  • 23
  • 27
  • 2
    The same problem I had, but it crazy since in jackson 2.6.3v there was a totally different crazy error, and with 2.9.8v everything worked. Damn it, so these serialization errors are so annoying. – brebDev Mar 13 '19 at 14:49
  • Atul Sharma answer Below looks more relevant for this question. Kindly review and modify. Thanks – Kanthishere Sep 27 '20 at 22:43
20

I sorted this problem as verifying the json from JSONLint.com and then, correcting it. And this is code for the same.

String jsonStr = "[{\r\n" + "\"name\":\"New York\",\r\n" + "\"number\": \"732921\",\r\n"+ "\"center\": {\r\n" + "\"latitude\": 38.895111,\r\n"  + " \"longitude\": -77.036667\r\n" + "}\r\n" + "},\r\n" + " {\r\n"+ "\"name\": \"San Francisco\",\r\n" +\"number\":\"298732\",\r\n"+ "\"center\": {\r\n" + "    \"latitude\": 37.783333,\r\n"+ "\"longitude\": -122.416667\r\n" + "}\r\n" + "}\r\n" + "]";

ObjectMapper mapper = new ObjectMapper();
MyPojo[] jsonObj = mapper.readValue(jsonStr, MyPojo[].class);

for (MyPojo itr : jsonObj) {
    System.out.println("Val of name is: " + itr.getName());
    System.out.println("Val of number is: " + itr.getNumber());
    System.out.println("Val of latitude is: " + 
        itr.getCenter().getLatitude());
    System.out.println("Val of longitude is: " + 
        itr.getCenter().getLongitude() + "\n");
}

Note: MyPojo[].class is the class having getter and setter of json properties.

Result:

Val of name is: New York
Val of number is: 732921
Val of latitude is: 38.895111
Val of longitude is: -77.036667
Val of name is: San Francisco
Val of number is: 298732
Val of latitude is: 37.783333
Val of longitude is: -122.416667
JJD
  • 50,076
  • 60
  • 203
  • 339
Atul KS
  • 908
  • 11
  • 21
  • 1
    This fixed the problem I've been having for days, no other answers made sense. For anyone else having the same error. It's worth noting that if your JSON has multiple object in, you need to be returning multiple objects. I had been returning MyObject, where I should have been returning MyObject[] – Aaria May 16 '20 at 17:26
15

As said, JsonMappingException: out of START_ARRAY token exception is thrown by Jackson object mapper as it's expecting an Object {} whereas it found an Array [{}] in response.

A simpler solution could be replacing the method getLocations with:

public static List<Location> getLocations(InputStream inputStream) {
    ObjectMapper objectMapper = new ObjectMapper();
    try {
        TypeReference<List<Location>> typeReference = new TypeReference<>() {};
        return objectMapper.readValue(inputStream, typeReference);
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

On the other hand, if you don't have a pojo like Location, you could use:

TypeReference<List<Map<String, Object>>> typeReference = new TypeReference<>() {};
return objectMapper.readValue(inputStream, typeReference);
freedev
  • 25,946
  • 8
  • 108
  • 125
  • 1
    Thank you for sharing this alternative implementation. Can you tell if there are advantages or disadvantages with using `CollectionType` vs. `TypeReference`? – JJD Feb 05 '18 at 21:04
  • 1
    `TypeReference` syntax is far shorter than the other. Not sure, if in some cases there could be a counter-indication related to the type erasure... but in my world `TypeReference` is just easier to use and understand. – freedev Feb 06 '18 at 17:19
-1

For instance:

data class

data class ToDo(
var id: Int, 
var text: String?, 
var completed: Boolean?) {}

Above deserialization error thrown when you use ToDo::class.java but not Array::class.java for json list

DOEST NOT WORK

    private val mapper = ObjectMapper().registerKotlinModule()
    .....
    val todo= mapper.readValue(response.body(), ToDo::class.java)

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize value of type com.example.api.dto.ToDo from Array value (token JsonToken.START_ARRAY) at [Source: (String)"[{"id":14,"text":"TEST","completed":true},{"id":13,"text":"TEST","completed":true},{"id":19,"text":"TEST","completed":true"[truncated 84 chars]; line: 1, column: 1]

WORK

private val mapper = ObjectMapper().registerKotlinModule()
.....
val todos = mapper.readValue(response.body(), Array<ToDo>::class.java)
27P
  • 1,183
  • 16
  • 22