Catch parameter parsing exception in Spring 3.0 WebMVC

I am using Spring WebMVC to provide a REST API. I use methods like

@RequestMapping("/path({id}") void getById(@PathVariable("id") int id) {} .

When a client incorrectly places a string instead of an integer id in a request, I get a NumberFormatException, for example:

 java.lang.NumberFormatException: For input string: "dojo" at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48) at java.lang.Long.parseLong(Long.java:410) at java.lang.Long.valueOf(Long.java:525) at org.springframework.util.NumberUtils.parseNumber(NumberUtils.java:158) at org.springframework.core.convert.support.StringToNumberConverterFactory$StringToNumber.convert(StringToNumberConverterFactory.java:59) at org.springframework.core.convert.support.StringToNumberConverterFactory$StringToNumber.convert(StringToNumberConverterFactory.java:1) at org.springframework.core.convert.support.GenericConversionService$ConverterFactoryAdapter.convert(GenericConversionService.java:420) at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:37) at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:135) at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:199) at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:104) at org.springframework.beans.SimpleTypeConverter.convertIfNecessary(SimpleTypeConverter.java:47) at org.springframework.validation.DataBinder.convertIfNecessary(DataBinder.java:526) at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolvePathVariable(HandlerMethodInvoker.java:602) at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.resolveHandlerArguments(HandlerMethodInvoker.java:289) at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:163) at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:414) at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:402) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:771) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:716) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:647) 

My question now is, how can I gracely catch him? I know that Spring provides @ExeptionHandler annotations, but I don't want to catch NFE at all. I want to be able to catch all exceptions for parsing in order to provide the client with an error message.

Any ideas?

Greetings

Jan

+7
source share
5 answers

Is this an actual exception? (this does not match your code example) You can usually expect it to be wrapped in org.springframework.beans.TypeMismatchException , which is probably specific enough for you to write an @ExceptionHandler method for it.

If this is not enough, you need to abandon Spring -Magic and simply change the parameter type to String + to parse it yourself. Then you can handle it in any way.

+2
source

I found a solution for your problem here http://www.coderanch.com/t/625951/Spring/REST-request-mapping-parameter-type

Just try

 @RequestMapping("/path({id:[\\d]+}") void getById(@PathVariable("id") int id) {} methods. 

And then an invalid use will cause 404. I'm not sure if version 3.0 is supported.

+1
source

I am not 100% sure whether this works for @PathVaribale or not, but usually to bind to the model you can use the BindingResult object next to your path variable, and the model and parsing error will be added to the BindingResult/Errors object.

0
source

Maybe I do this because I'm an old tyme programmer, but I use String as a type for all @PathVariable and @RequestParameter , then I do parsing inside the handler method. This allows me to easily catch all NumberFormatException exceptions.

Although this is not a "Spring" method, I recommend it because it is easy for me and easy for my future marine service programmers to understand.

0
source

Putting together your comments, I tried the following:

 public class ValidatingAnnotationMethodHandlerAdapter extends AnnotationMethodHandlerAdapter { @Override protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object target, String objectName) throws Exception { return new ServletRequestDataBinder(target, objectName) { @Override public <T> T convertIfNecessary(Object value, Class<T> requiredType) throws TypeMismatchException { try { return super.convertIfNecessary(value, requiredType); } catch (RuntimeException e) { throw new ControllerException("Could not parse parameter: " + e.getMessage()); } } @Override public <T> T convertIfNecessary(Object value, Class<T> requiredType, MethodParameter methodParam) throws TypeMismatchException { try { return super.convertIfNecessary(value, requiredType, methodParam); } catch (RuntimeException e) { throw new ControllerException("Could not parse parameter: " + e.getMessage()); } } }; } 

ControllerException is a custom exception that is caught by the annotated @ExceptionController method (I use this exception in all validation classes).

I hope you will like it,

Jan

0
source

All Articles