Wednesday, April 9, 2014

org.springframework.web.HttpMediaTypeNotAcceptableException: Could not find acceptable representation

This exception is raised when an http converter is not available on the classpath
In this blog i will show an example to configure Jackson JSON and XStream XML http message converters

Add XStream and Jackson libraries on the classpath
<properties>
<jackson.version>2.2.3</jackson.version>
<xstream.version>1.4.6</xstream.version>
</properties>

<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>${xstream.version}</version>
</dependency>
</dependencies>


Make sure Spring OXM is also added on the classpath
<!-- Spring OXM -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring-framework.version}</version>
</dependency>

Now extend your WebMVC configuration class with WebMvcConfigurerAdapter and override the configureMessageConverters method to register the XStream XML and Jackson JSON converters
This how your WebMVC Configuration class should look like

@EnableWebMvc
@Configuration
@ComponentScan({ "change.it.your.controllers.package" })
public class WebConfig extends WebMvcConfigurerAdapter {
 
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
messageConverters.add(createXmlHttpMessageConverter());
messageConverters.add(new MappingJackson2HttpMessageConverter());
 
super.configureMessageConverters(converters);
}
private HttpMessageConverter<Object> createXmlHttpMessageConverter() {
MarshallingHttpMessageConverter xmlConverter =
 new MarshallingHttpMessageConverter();
 
XStreamMarshaller xstreamMarshaller = new XStreamMarshaller();
xmlConverter.setMarshaller(xstreamMarshaller);
xmlConverter.setUnmarshaller(xstreamMarshaller);
 
return xmlConverter;
}
}

You are all done and the converters have been registered to handle XML and JSON rest services

To test use the curl with following headers
FOR XML
"Accept: text/xml"
FOR JSON
"Accept: application/json"
Example:
curl -i -X GET -H "Accept: application/json" http://url-of-you-rest-service/
OR
curl -i -X GET -H "Accept: text/xml" http://url-of-you-rest-service/

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
}

Could not read JSON: Unexpected character (''' (code 39))

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 Akram"}' 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:15:26 GMT
Connection: close

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

public Dog() {
}

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@12157135]
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: Unexpected character (''' (code 39)): expected a vali
d value (number, String, array, object, 'true', 'false' or 'null')

RESOLUTION:
Changed the data part in curl command from
 '{"id":"1","name":"Labrador","ownerName":"Waseem Akram"}'
to
 "{\"id\":1,\"name\":\"Labrador\",\"ownerName\":\"Waseem Akram\"}"


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

Tuesday, April 8, 2014

Spring REST Application returns Http 406 error code

Reason: JSON library is not on your project's class path. I resolved this issue by adding following dependency in my project pom.xml file

<properties>
<jackson.version>2.2.3</jackson.version>
</properties>

<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>${jackson.version}</version>
</dependency>

Once this library is on the classpath, your spring annotation-driven code will use it to return json responses instead of returning http 406

Thursday, April 3, 2014

Configuring Remote Java Application debugger in Spring tool suite to debug maven based applications deployed in Tomcat


Create an environment variable

Variable Name: JPDA_OPTS
Variable Value: -agentlib:jdwp=transport=dt_socket,address=8000,server=y,suspend=n



Now in spring tool suite go to the Run -> Debug Configurations menu
Right click on the Remote Java Application menu in the right pane and click new.

Give this configuration a suitable name
In Connection type select Standard (Socket Attach)
In host enter localhost and on the port enter 8000
Now click on the source tab and use the add button to add the projects you want to debug.

Now deploy the project wars in the tomcat and start the tomcat server. Start server with following command from Windows command prompt
Tomcat_7_0_52\bin>catalina.bat jpda start


And then use the debug button to start your debugger (see the screen shot below). That's it...