web-dev-qa-db-fra.com

Spring'sRequestParam avec Enum

J'ai cette énumération:

public enum SortEnum {
    asc, desc;
}

Que je veux utiliser comme paramètre d'une demande de repos:

@RequestMapping(value = "/events", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
public List<Event> getEvents(@RequestParam(name = "sort", required = false) SortEnum sort) {

Cela fonctionne bien lorsque j'envoie ces demandes

/events 
/events?sort=asc
/events?sort=desc

Mais quand j'envoie:

/events?sort=somethingElse

Je reçois une réponse 500 et ce message dans la console:

2016-09-29 17:20:51.600 DEBUG 5104 --- [  XNIO-2 task-6] com.myApp.aop.logging.LoggingAspect   : Enter: com.myApp.web.rest.errors.ExceptionTranslator.processRuntimeException() with argument[s] = [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type [Java.lang.String] to required type [com.myApp.common.SortEnum]; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [Java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam com.myApp.common.SortEnum] for value 'somethingElse'; nested exception is Java.lang.IllegalArgumentException: No enum constant com.myApp.common.SortEnum.somethingElse]
2016-09-29 17:20:51.600 DEBUG 5104 --- [  XNIO-2 task-6] com.myApp.aop.logging.LoggingAspect   : Exit: com.myApp.web.rest.errors.ExceptionTranslator.processRuntimeException() with result = <500 Internal Server Error,com.myApp.web.rest.errors.ErrorVM@1e3343c9,{}>
2016-09-29 17:20:51.601  WARN 5104 --- [  XNIO-2 task-6] .m.m.a.ExceptionHandlerExceptionResolver : Resolved exception caused by Handler execution: org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type [Java.lang.String] to required type [com.myApp.common.SortEnum]; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [Java.lang.String] to type [@org.springframework.web.bind.annotation.RequestParam com.myApp.common.SortEnum] for value 'somethingElse'; nested exception is Java.lang.IllegalArgumentException: No enum constant com.myApp.common.SortEnum.somethingElse

Existe-t-il un moyen d'empêcher Spring de lancer ces exceptions et de définir l'énumération sur null?

MODIFIER 

La réponse acceptée de Strelok fonctionne. Cependant, j'ai décidé de m'occuper de la gestion de l'exception MethodArgumentTypeMismatchException.

@ControllerAdvice
public class ExceptionTranslator {

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    @ResponseBody
    public ResponseEntity<Object> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e) {
        Class<?> type = e.getRequiredType();
        String message;
        if(type.isEnum()){
            message = "The parameter " + e.getName() + " must have a value among : " + StringUtils.join(type.getEnumConstants(), ", ");
        }
        else{
            message = "The parameter " + e.getName() + " must be of type " + type.getTypeName();
        }
        return buildResponse(HttpStatus.UNPROCESSABLE_ENTITY, message);
    }
29
Antoine Martin

Vous pouvez créer un convertisseur personnalisé qui renverra null au lieu d'une exception lorsqu'une valeur non valide est fournie. 

Quelque chose comme ça:

@Configuration
public class MyConfig extends WebMvcConfigurationSupport {
   @Override
   public FormattingConversionService mvcConversionService() {
       FormattingConversionService f = super.mvcConversionService();
       f.addConverter(new MyCustomEnumConverter());
       return f;
   }
}

Et un convertisseur simple pourrait ressembler à ceci:

public class MyCustomEnumConverter implements Converter<String, SortEnum> {
    @Override
    public SortEnum convert(String source) {
       try {
          return SortEnum.valueOf(source);
       } catch(Exception e) {
          return null; // or SortEnum.asc
       }
    }
}
34
Strelok

vous devez faire ce qui suit

@InitBinder
public void initBinder(WebDataBinder dataBinder) {
    dataBinder.registerCustomEditor(YourEnum.class, new YourEnumConverter());
}

reportez-vous aux informations suivantes: https://machiel.me/post/Java-enums-as-request-parameters-in-spring-4/

19
satish chennupati

Les réponses fournies jusqu'à présent ne sont pas complètes. Voici un exemple de réponse étape par étape qui a fonctionné pour moi: -

1st Définissez l'énumération dans votre signature de point final (type d'abonnement).
Exemple :

public ResponseEntity v1_getSubscriptions(@PathVariable String agencyCode,
                                          @RequestParam(value = "uwcompany", required = false) String uwCompany,
                                          @RequestParam(value = "subscriptiontype", required = false) SubscriptionType subscriptionType,
                                          @RequestParam(value = "alert", required = false) String alert,

2nd Définissez un éditeur de propriétés personnalisé qui sera utilisé pour traduire de String en enum:

import Java.beans.PropertyEditorSupport;

public class SubscriptionTypeEditor extends PropertyEditorSupport {

    public void setAsText(String text) {
        try {
            setValue(SubscriptionType.valueOf(text.toUpperCase()));
        } catch (Exception ex) {
            setValue(null);
        }
    }
}

3e Inscrivez l'éditeur de propriété avec le contrôleur:

@InitBinder ("subscriptiontype")
public void initBinder(WebDataBinder dataBinder) {
    dataBinder.registerCustomEditor(SubscriptionType.class, new SubscriptionTypeEditor());
}

Les traductions de string en enum devraient se dérouler parfaitement maintenant. 

4
user3862533

Si vous utilisez Spring Boot, c’est la raison pour laquelle vous ne devez pas utiliser WebMvcConfigurationSupport

La meilleure pratique consiste à implémenter l'interface org.springframework.core.convert.converter.Converter et avec l'annotation @Component. Ensuite, Spring Boot chargera automatiquement tous les beans Converter. Code de démarrage de printemps

@Component
public class GenderEnumConverter implements Converter<String, GenderEnum> {
    @Override
    public GenderEnum convert(String value) {
        return GenderEnum.of(Integer.valueOf(value));
    }
}

Projet de démonstration

1
Cnfn