Wednesday, April 9, 2014

Could not read JSON: No suitable constructor found for type

Summary:
"Could not read JSON: No suitable constructor found for type" is the exception which came when jackson tried create an object of Dog bean in one of my restful application examples. I had mistakenly created an explicit constructor with 2 parameters and forgot to provide a constructor with no params in the Dog bean. As a result jackson failed to create object of my class and raised this exception. A fix to this solution is not to provide any explicit constructor in the class or when there is an explicit constructor then also create an empty constructor with it.

Detailed explanation:
FRAMEWORK : Spring 3.2.3.RELEASE
JACKSON VERSION : 2.2.3
REST API URL : http://localhost:8080/rest/api/dogs
METHOD : PUT

REQUEST:
curl -i -X PUT -H "Content-Type: application/json" -d "{\"id\":"1",\"name\":\"Labrador\",\"ownerName\":\"Waseem\"}" http://localhost:8080/rest/api/dogs

RESPONSE:
HTTP/1.1 400 Bad Request
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=utf-8
Content-Language: en
Content-Length: 968
Date: Wed, 09 Apr 2014 18:33:55 GMT
Connection: close


<html><head><title>Apache Tomcat/7.0.52 - Error report</title><style><!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR{color : #525D76;}--></style> </head><body><h1>HTTP Status 400 - </h1><HR size="1" noshade="noshade"><p><b>type</b> Status report</p><p><b>message</b> <u></u></p><p><b>description</b> <u>The request sent by the client was syntactically incorrect.</u></p><HR size="1" noshade="noshade"><h3>Apache Tomcat/7.0.52</h3></body></html>

Problematic DOG BEAN: 
public class Dog {
private Long id;
private String name;
private String ownerName;

//this bean is missing a constructor with no params

public Dog(Long id, String name, String ownerName) {
this.id = id;
this.name = name;
this.ownerName = ownerName;
}

//All the getters and setters
}

DogsController Code:
@Controller
@RequestMapping(value = "dogs")
class DogsController {
@Autowired
DogService dogService;


       @RequestMapping(method = RequestMethod.PUT)
@ResponseStatus(HttpStatus.OK)
public void update(@RequestBody Dog dog) {
RestPreconditions.checkNotNull(dog);
dogService.update(dog);
}
}

SERVER DEBUG LOGS:
DEBUG RequestResponseBodyMethodProcessor - Reading [class org.rest.valueobject.Dog] as "application/json" using [org.springframework.http.converter.js
on.MappingJackson2HttpMessageConverter@2d046021]
DEBUG ExceptionHandlerExceptionResolver - Resolving exception from handler [public void org.rest.controller.DogsController.update(org.rest.valueobject
.Dog)]: org.springframework.http.converter.HttpMessageNotReadableException: Could not read JSON: No suitable constructor found for type [simple type,

class org.rest.valueobject.Dog]: can not instantiate from JSON object (need to add/enable type information?)

RESOLUTION:
Since i provided a custom constructor in the Dog bean [public Dog(Long id, String name, String ownerName)] therefore an empty constructor was also needed
So the fix is to add an empty constructor in the Dog bean

FIXED DOG BEAN: 
public class Dog {
private Long id;
private String name;
private String ownerName;

//Empty constructor is added to fix the code
public Dog() {
}

public Dog(Long id, String name, String ownerName) {
this.id = id;
this.name = name;
this.ownerName = ownerName;
}

//All the getters and setters
}

5 comments: