Tuesday, October 16, 2012

Customise error message for missing parameter exception (400) when using Spring @Controller and @RequestParam.

I am working on a project which needs a REST resource to accept client request for sending emails.

The parameters required by this Resource are:
1) from: a valid email address to send mails.
2) subject: the subject of mail.
3) to: a valid email address the mail send to.
4) text: the content of mail.

Because our project is using Spring to do everything we need and it can do. So Spring Rest Controller is my best option to implement this Resource.

the declaration of my resource is:

 @RequestMapping ( method = { RequestMethod.POST, RequestMethod.GET } )  
 @ResponseStatus ( HttpStatus.OK )  
 public void sendEmail( @RequestParam ( value = "from" ) String from,  
                    @RequestParam ( value = "subject" ) String subject,  
                    @RequestParam ( value = "to" ) String to,  
                    @RequestParam ( value = "text" ) String text,  
                    final HttpServletResponse response ) throws Exception  

And I test it by using following url.

 url/subject=hello&to=sean@abc.com&text=this+is+hello+from+Sean  

Because the parameter from is missing and the system should return a 400 exception with the right error message:

 HTTP Status 400 - Required String parameter 'from' is not present  
 type Status report  
 message Required String parameter 'from' is not present  
 description The request sent by the client was syntactically incorrect (Required String parameter 'from' is not present).  
 Apache Tomcat/7.0.23  

however, what I get is:

 HTTP Status 400 -   
 type Status report  
 description The request sent by the client was syntactically incorrect ().  

So what I need is how to customise the error message.

Actually, Spring does provide an exception for this case, it called
MissingServletRequestParameterException and returned the correct error message that what exact we want. But for some reason, the client side did not get the correct error message, but only the right status code which is 400.

My Solution (Also the solution shared by people online already):

Create my own AnnotationMethodHandlerAdapter and override the method invokeHandlerMethod.

 public class AnnotationMethodExceptionHandlerAdapter extends  
         AnnotationMethodHandlerAdapter  
 {  
     @Override  
     protected ModelAndView invokeHandlerMethod( HttpServletRequest request,  
                           HttpServletResponse response, Object handler ) throws Exception  
     {  
         try  
         {  
             return super.invokeHandlerMethod( request, response, handler );  
         }  
         catch ( MissingServletRequestParameterException e )  
         {  
             request.setAttribute( "EXCEPTION_NAME", e.getClass().getName() );  
             response.sendError( HttpServletResponse.SC_BAD_REQUEST, e.getMessage() );  
             return null;  
         }  
         catch ( Exception e )  
         {  
             request.setAttribute( "EXCEPTION_NAME", e.getClass().getName() );  
             response.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage() );  
             return null;  
         }  
     }  
 }  

I am not sure is there any exception which is not a MissingServletRequestParameterException can be thrown by  super.invokeHandlerMethod( request, response, handler ); and I do know what status should return in that case. So at here I just return 500.

And modify my servlet config.

 <!--To enable @RequestMapping process on type (class) level -->  
     <bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"/>  
     <!--To enable @RequestMapping process on method level -->  
   <bean class="YourProjectPath.AnnotationMethodExceptionHandlerAdapter"/>  

Do not need use
 <mvc:annotation-driven/>  

Then you will get the correct error message.


As I mentioned before and you can seen below, Spring does return the correct error message, but I do not know why client can not get it.




Hope this is helpful to you if you are struggling with the same problem with I got.

Thursday, October 11, 2012

Spring – load property value using @Value


Spring – load multiple property based on utils properties code

pure utils:property, one location
With the utils namespace in Spring 3.0 you can load a property file and use the values in Spring EL expressions.
– Spring config File –
 <util:properties id="someProps" location="classpath:mybasic.properties" />  
 <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
     ...  
   <property name="url" value="jdbc:h2:tcp://localhost/~/DB/#{someProps['database.dbname']}" />  
   <property name="username" value="#{someProps['database.user']}" />  
   <property name="password" value="#{someProps['database.password']}" />  
     ...  
 </bean>  
To use the property values in Java classes use the the EL expression with the @Value annotation.
– Java code –
 ...  
 HINT:the name you use for someProps can not includes '-'(e.g. can not be  
 words like some-props)  
 String @Value("#{someProps['my.tmp.dir']}") tmpDir;  
 ...  
Multiple property files
Please visit author's page http://develop.nydi.ch/2010/12/spring-multiple-properties/

Wednesday, October 10, 2012

Set up JRebel on Intellij for Maven project.

What is JReble and what can it do for you?
http://en.wikipedia.org/wiki/JRebel

Step 1:

How to install JRebel plugin on your IDE (Intellij as example)?
http://zeroturnaround.com/software/jrebel/download/using-jrebel-with-intellij/

Step 2:

Configure JRebel for your maven project.



Add the following snippet to your parent pom.xml. The rebel.xml configuration file will be generated
for each individual sub-module of your maven project.

 <plugin>  
     <groupId>org.zeroturnaround</groupId>  
     <artifactId>jrebel-maven-plugin</artifactId>  
     <version>1.1.1</version>  
     <executions>  
         <execution>  
             <id>generate-rebel-xml</id>  
             <phase>process-resources</phase>  
             <goals>  
                 <goal>generate</goal>  
             </goals>  
         </execution>  
     </executions>  
 </plugin> 


      This will generate JRebel configuration file rebel.xml 
      automatically on every build. If you want to generate the rebel.xml 
      manually run mvn jrebel:generate -Drebel.xml.dir=OUTPUT_DIRECTORY 
      (by default OUTPUT_DIRECTORY is target/classes). 
      Adding -Drebel.generate.show=true will print out generated rebel.xml 
      at info level, so you can immediately see what was generated.
    

      By default, the generated rebel.xml contains absolute paths 
      to your workspace. However if you want to deploy the artifacts for your 
      team to use, you will need to make sure that the paths are relative 
      using a configurable custom property.


Step 3:

Set up JRebel for you tomcat.

Create a file startup-jrebel.sh in the dir of you TOMCAT_HOME/bin

and add following content into it.
 #!/bin/bash  
 export CATALINA_OPTS="-javaagent:/home/seaxio/.IdeaIC11/config/plugins/jr-ide-idea/lib/jrebel/jrebel.jar $CATALINA_OPTS"  
 `dirname $0`/catalina.sh $@  

Step 4:

Start debugging.

 Run sh startup-jrebel.sh jpda start  

Done. compaile your project (Itellij: ctrl + f9) after every code change.

Do not to redeploy your project and you can see the changes in the fly.