2011-02-07 6 views
7

Uso Spring WebMVC per fornire un'API REST. Uso metodi comeErrore di parsing dei parametri di cattura in Spring 3.0 WebMVC

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

Quando il client in modo non corretto mettere una stringa invece di un id intero nella query, ottengo un NumberFormatException come:

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) 

La mia domanda è ora, come posso elegantemente prenderlo? So che Spring fornisce le annotazioni @ExeptionHandler, ma non voglio prendere la NFE in generale. Voglio essere in grado di catturare tutte le eccezioni di parsing per presentare un messaggio di errore piacevole al client.

Qualche idea?

Cheers,

gen

risposta

0

Io non sono sicuro al 100% circa se questo funziona per @PathVaribale o no, ma in generale per il modello di legame si potrebbe usare un oggetto BindingResult accanto al tuo variabile del percorso e il modello e l'analisi l'errore verrà aggiunto all'oggetto BindingResult/Errors.

+0

Ho effettuato alcune ricerche ma non sono riuscito a trovare una connessione tra PathVariable e BindingResult. Chiunque altro? – Jan

+0

Non ce n'è, non funziona. – Affe

2

È l'eccezione effettiva? (non corrisponde al tuo esempio di codice) Normalmente ci si aspetterebbe che fosse incapsulato in org.springframework.beans.TypeMismatchException che è probabilmente abbastanza specifico da poter scrivere per esso un metodo @ExceptionHandler.

Se questo non è abbastanza specifico, è necessario rinunciare a Spring-Magic e basta modificare il tipo di parametro in String + analizzarlo da soli. Allora puoi gestirlo come più ti piace.

+0

Sì, mi aspettavo lo stesso, ma l'NFE è l'eccezione di root. E mi dispiace di aver mixato a lungo e int nel mio esempio. – Jan

0

Forse lo faccio perché sono un vecchio programmatore Tyme, ma io uso String come tipo per tutti i @PathVariable e @RequestParameter parametri poi faccio l'analisi all'interno del metodo del gestore. Questo mi consente di catturare facilmente tutte le eccezioni NumberFormatException.

Anche se questo non è il modo "Spring" per farlo, lo consiglio perché è facile per me e facile da comprendere per i miei futuri programmatori di manutenzione in mare aperto.

+0

Fino a sapere questo sembra la soluzione preferita ma non mi piace davvero (perché ha comportato un sacco di cambiamenti). Spero che ci sarà un'altra soluzione. – Jan

+0

L'altra soluzione è quella di sovrascrivere/scrivere il proprio WebDataBinder e lanciare eccezioni più specifiche. – Affe

0

mettere insieme i vostri commenti, ho provato la seguente:

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 è un'eccezione personalizzata che viene catturato con un metodo @ExceptionController annotato (io uso questa eccezione in tutte le classi di convalida).

Spero vi piaccia esso,

gen

1

Ho trovato la soluzione per il problema qui http://www.coderanch.com/t/625951/Spring/REST-request-mapping-parameter-type

Basta provare

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

E poi non utilizzo valido causerà 404. I non sono sicuro che la versione 3.0 supporti questo.

+0

Bella soluzione. Con l'attuale Spring 4 usiamo @ControllerAdvice per catturare le eccezioni ed è molto conveniente. – Jan

+0

Buona soluzione. A proposito, questo genera HttpRequestMethodNotSupportedException. –

Problemi correlati