Solving Spring RestTemplate JSON Deserialization Error: Can not deserialize instance of Country[] out of START_OBJECT token

Nov 28, 2025 · Programming · 12 views · 7.8

Keywords: Spring RestTemplate | JSON Deserialization | Jackson Annotations

Abstract: This paper provides an in-depth analysis of the 'Can not deserialize instance of hello.Country[] out of START_OBJECT token' error encountered during JSON deserialization with Spring RestTemplate. By examining the root cause of the error, it details the mismatch between JSON data structure and Java object mapping, and presents a complete solution involving wrapper class creation and @JsonProperty annotation usage. The article also explores Jackson library mechanics, compares different solution approaches, and provides practical code examples.

Problem Background and Error Analysis

When using Spring Framework's RestTemplate for REST API calls, developers frequently encounter JSON deserialization related errors. The case study discussed in this article involves the GeoNames API, which returns JSON data containing a root element "geonames" that encloses an array of country information.

The original problematic code attempted to directly deserialize JSON response into a Country array:

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

This direct mapping approach caused the Jackson library to throw an exception:

com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of hello.Country[] out of START_OBJECT token

Root Cause Examination

The fundamental cause of the error lies in the mismatch between the JSON data structure and the expected Java object structure. The API returns JSON in the following format:

{
"geonames": [
    {
        "continent": "EU",
        "capital": "Andorra la Vella",
        "countryName": "Andorra",
        "geonameId": 3041565
    }
]
}

The Jackson deserializer expects to find an array start token (START_ARRAY), but instead encounters an object start token (START_OBJECT). This occurs because the root level of the JSON response is an object containing the "geonames" property, rather than a direct array.

Solution Implementation

The correct solution requires creating an intermediate wrapper class that matches the complete JSON structure:

public class CountryInfoResponse {
    
    @JsonProperty("geonames")
    private List<Country> countries;
    
    public List<Country> getCountries() {
        return countries;
    }
    
    public void setCountries(List<Country> countries) {
        this.countries = countries;
    }
}

The corresponding invocation code should be modified to:

RestTemplate restTemplate = new RestTemplate();
List<Country> countries = restTemplate.getForObject(
    "http://api.geonames.org/countryInfoJSON?username=volodiaL",
    CountryInfoResponse.class
).getCountries();

Technical Details Deep Dive

The @JsonProperty annotation plays a crucial role in this solution. This annotation instructs the Jackson library to map the "geonames" field from JSON to the countries property of the Java object. This explicit mapping avoids potential matching issues that could arise from Jackson's default naming strategies.

The Country class definition should also be properly completed:

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Country {
    private String countryName;
    private long geonameId;
    
    public String getCountryName() {
        return countryName;
    }
    
    public void setCountryName(String countryName) {
        this.countryName = countryName;
    }
    
    public long getGeonameId() {
        return geonameId;
    }
    
    public void setGeonameId(long geonameId) {
        this.geonameId = geonameId;
    }
    
    @Override
    public String toString() {
        return countryName;
    }
}

Alternative Approaches Comparison

Another possible solution involves using a generic Object list:

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

While this approach can avoid type conversion errors, it sacrifices type safety and requires additional type checking and conversion in subsequent code, increasing code complexity and runtime error risks.

Best Practices Recommendations

In practical development, it is recommended to always create DTO (Data Transfer Object) classes that exactly match the API response structure. This approach not only resolves the current deserialization issue but also provides better type safety and code maintainability.

For complex API responses, consider using Jackson's @JsonRootName annotation or configuring ObjectMapper to support root-level wrapping, but these methods may be less directly effective than creating wrapper classes under Spring RestTemplate's default configuration.

Conclusion

By creating appropriate wrapper classes and utilizing @JsonProperty annotations, the START_OBJECT error encountered during Spring RestTemplate deserialization of nested JSON structures can be effectively resolved. This method maintains type safety, provides clear code structure, and represents the recommended approach for handling complex JSON responses.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.