Sriram G
Sriram G

Reputation: 301

no String-argument constructor/factory method to deserialize from String value - Exception while deserializing json object from restTemplate

Facing issue while making call to retrieve a json response and parse it.

[
    {
        "name": "john doe",
        "age": "24",
        "address": "{\"state\":\"LA\",\"country\":\"US\"}"
    }
]

Models:

Person.java

@Data
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true) 
public class Person {
    private String name;
    private String age;
    private Address address;
}

Address .java

@Data
@NoArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true) 
public class Address {
    private String state;
    private String country;
}

Code to read this data,

ResponseEntity<List<Person>> response = restTemplate.exchange(builder.toUriString(), HttpMethod.GET,requestEntity,new ParameterizedTypeReference<List<Person>>() {});

However i get below exception,

RestClientException while invoking ABS ServiceError while extracting response for type [java.util.List<com.bp.model.Person>] and content type [application/json;charset=UTF-8]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of com.bp.model.Address (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"state":"LA","country":"US"}'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of com.bp.model.Address (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"state":"IN","brand":"anthem"}') at [Source: (PushbackInputStream); line: 1, column: 325] (through reference chain: java.util.ArrayList[0]->com.bp.model.Person["address"])

Upvotes: 16

Views: 99763

Answers (3)

CodingBee
CodingBee

Reputation: 1199

JSON string to Map:
String json = "{"name":"mkyong", "age":"37"}";
Output {name=mkyong, age=37}

public static void main(String[] args) {
    ObjectMapper mapper = new ObjectMapper();
    String json = "{\"name\":\"mkyong\", \"age\":\"37\"}";
    try {
        // convert JSON string to Map
        Map<String, String> map = mapper.readValue(json, Map.class);

        // it works
        //Map<String, String> map = mapper.readValue(json, new TypeReference<Map<String, String>>() {});
        System.out.println(map);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Map to JSON string:
{"name":"mkyong","age":"37"}
{ "name" : "mkyong", "age" : "37" }

public static void main(String[] args) {
    ObjectMapper mapper = new ObjectMapper();
    Map<String, String> map = new HashMap<>();
    map.put("name", "mkyong");
    map.put("age", "37");
    try {
        // convert map to JSON string
        String json = mapper.writeValueAsString(map);
        System.out.println(json);   // compact-print

        json = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(map);
        System.out.println(json);   // pretty-print

    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
}

In Jackson, we can use mapper.readValue(json, Map.class) to convert a JSON string to a Map. Dependency

<dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>2.9.8</version>
  </dependency>

Upvotes: 1

user20046025
user20046025

Reputation: 1

Here we can try to set the values during runtime.

@JsonProperty("address")
    public void setCustomAddress(String addressFromJson){
        this.address = new Gson().fromJson(addressFromJson, Address.class);
    }

Upvotes: 0

rph
rph

Reputation: 2639

The code is correct but there's a problem with the JSON. The address is a string and not a JSON object. For it to work, it would need to be something like:

"address": {"state": "LA", "country": "US"}

Without the outer quotes and the escape characters.

Upvotes: 17

Related Questions