Tuesday, May 15, 2012

Spring MVC - REST ( JSON/XML) - Configuration



This post is an compilation of the problems that i have faced while configuring an Spring MVC Application that will acts as an API server providing all the services in an REST based manner.
It is an simple task to configure the whole environment and to make services available. However i have faced the following set of problems, which are little different in nature->

  1. Use JAXB annotations for the keys of the JSON that is being returned from the server (by default the JACKSON processor will take the variables names and will associate them as the keys in the returned JSON.
  2. Use same keys (in json) / tags (in xml) to receive the request (in POST/PUT).
  3. Apply Hibernate Validator by making use of Spring validation.
Guys at VMWare spring has done a fabulous jobs and all of the above mentioned requirements will be collated into a single line of XML that you need to declared in your dispatcher-servlet.xml (or any of the other spring application context file you are importing to build your app context
).
&
lt;mvc:annotation-driven/>
This line does a number of things
  1. Automatically add all types of interceptors like XML Based interceptors, String, Form based interceptors.
  2. Will provide automatic marshalling of your response/value object in XML/JSON
  3. Will provide the validation of your request VO, if you have enabled the @ExceptionHandler annotation on some method in your controller.
The problem that i had faced is that i could not be able to use my JAXB annotations as the KEYS in my request/response, because when i declared a different Jackson processor and added it to the AnnotationHandlerAdapter provided by spring, it is being ignored brutally by Spring under the wraps. And the one defined by the <mvc:annotation-driven/> one will take priority. As soon as the remove this annotation to make my JSON (with jaxb annotations you required another library JACKSON-XC.jar) the validation thing ceases to stopped. This all forces me to look onto the varous JIRA bugs raised against this annotation and finally i will be able to solve the problem with the help of Spring 3.1.

Note:- In case you are using spring 3.0 jar, please replace them with Spring 3.1 jar and use 3.1.xsd everywhere in your application context xml files (because the configuration which is represented below will only work it the XSD of 3.1 is being used as 3.0 does not allow any attribute and sub-element within the <mvc:annotation-driven/> option.
Following is the configuration which will allow use to solve the above three problems.
(Please make sure before running the code you must have all the bindings and jar files available in your classpath, Here is a brief listing of those.
-> For Validation: Hibernate-validator 4.2.0.Final.jar, javax.validation.api (JSR 303)
-> For Jackson : Jackson-core.jar, jackson-mapper-asl.jar, jacakson-xc.1.7.5.jar
-> For JaxB -> Jaxb API and Impl . jar

Configuration code:



 
 
 
 
   
   
 
    
  
  
    
  
   
    
    com.mycompany..CreateEmployeeRequestVO
    com.mycompany..CreateEmployeeResponseVO
   
  
  
     

 
 
      


  
  
   
     
      
     
      
       
        
        
        
       
      
     
   
   
    
    
     
      
       
       
       
                                               
     
    
   
   
  


NOTE: Please note that in above xml the last line has only one </beans> and nothing else. The three </bean> is being printed wrongly by the javascript library, i am using.

Here is the description of the components of XML file

  • Line 1-5 simply declares the XML namespaces and the various XSD files we are going to use.
  • Line 10-15 will register the JAXB Annotation Introspecter and associate itself with the ObjectMapper of the jackson library. (Many of the blogs will show directly mapping this to annotationIntrospector property of the objectmapper, but it has been changed, with the introduction of new API, now the annotationIntrospector is present in the serializationConfig and deserializationConfig object of the Object Mapper). This is the key to use JAXB annotations in the JSON Processing.
  • Line 18-27 registers the JAXB2 Marshaller taken from the OXM Library. here we can register the varous classes that we have to use either for taking the input or in generating the output i.e. RequestValueObject and ResponseValueObject. However, i found that there is no way through which you can give directly a packagename or a list of packages. The Other option that we have is to use eitehr the contextPath property or the jaxb.index thing.
  • LIne 31-32 will intialize the Spring Validator and the conversion service factory bean, which will automatically going to use the hibernate validator present on the classpath. The advantage of using hibernate validator is that the availablity of extra custom annotations like NotEmpty etc. It provides an way through which we can remove the annotations from our value objeect and place at in an XML file and at run time, the validator picks that file to perform the listed constraints on the various attributes of the request Value object.
  • Line 34-62 is the meat of the whole subject and contains all the necesseary plumbing to make the things work. (Note: for this to work we must have to include Spring 3.1 xsd otherwise Spring will throw an error that no element or attribute will be alloweed with ). IT does two things:
    • Registeres the custom XML marshaller converter with the automatically registered AnnotationHandlerAdapter by replacing the existing default converter.
    • Registers the custom JSON mapping converter, where we are using new created jacksonObjectMapper rather then the one which is avaiable by default. This also will displace the default registered converter with AnnotationHandlerAdapter with this one.
And that's all. Voila.. all of our test cases are running and our JSON/XML are being generated/consumed properly. In order to achieve this, i had taken help from various links, which i had mentioned below. And at last thanks to Juergen Holler and the team for the clear explanation on the JIRA.

https://jira.springsource.org/browse/SPR-6306
https://jira.springsource.org/browse/SPR-7504
https://jira.springsource.org/browse/SPR-7967
https://jira.springsource.org/browse/SPR-6817
https://jira.springsource.org/browse/SPR-6524

http://www.aviyehuda.com/2010/04/using-hibernate-validator-to-cover-your-validation-needs/
http://java.dzone.com/articles/using-hibernate-validator
http://stackoverflow.com/questions/8679122/custom-httpmessageconverters-does-not-take-precedence-for-string-objects-in-spri
http://stackoverflow.com/questions/7199652/mvcannotation-driven-with-un-annotated-controllers
http://forum.springsource.org/showthread.php?106594-complete-XML-for-mimicing-annotation-driven
http://stackoverflow.com/questions/6177913/configuring-the-jacksonobjectmapper-not-working-in-spring-mvc-3
http://scottfrederick.blogspot.in/2011/03/customizing-spring-3-mvcannotation.html
http://stackoverflow.com/questions/3693397/howto-get-rid-of-mvcannotation-driven
http://forum.springsource.org/showthread.php?101450-lt-mvc-annotation-driven-gt-issues

I hope, it will prove useful for the developer community.