webentwicklung-frage-antwort-db.com.de

@RequestParam von Spring mit Enum

Ich habe diese enum:

public enum SortEnum {
    asc, desc;
}

Das möchte ich als Parameter für eine Restanfrage verwenden:

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

Es funktioniert gut, wenn ich diese Anfragen schicke

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

Aber wenn ich sende:

/events?sort=somethingElse

Ich bekomme eine 500-Antwort und diese Nachricht in der Konsole:

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,[email protected],{}>
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

Gibt es eine Möglichkeit, den Frühling daran zu hindern, diese Ausnahmen auszulösen, und die Aufzählung auf null setzen?

EDIT 

Die von Strelok akzeptierte Antwort funktioniert. Ich entschied mich jedoch für die Behandlung der 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

Sie können einen benutzerdefinierten Konverter erstellen, der anstelle einer Ausnahme null zurückgibt, wenn ein ungültiger Wert angegeben wird. 

Etwas wie das:

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

Und ein einfacher Konverter könnte so aussehen:

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

sie müssen folgendes tun

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

beziehen Sie sich auf: https://machiel.me/post/Java-enums-as-request-parameters-in-spring-4/

19

Die bisherigen Antworten sind nicht vollständig. Hier ist ein Antwortbeispiel, das Schritt für Schritt für mich funktioniert hat: -

1. Definieren Sie die Aufzählung in Ihrer Endpunktsignatur (Abonnementtyp).
Beispiel :

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,

2. Definieren Sie einen benutzerdefinierten Eigenschaftseditor, der zum Übersetzen von String in eine Enumeration verwendet wird:

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);
        }
    }
}

3. Registrieren Sie den Eigenschafteneditor beim Controller:

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

Übersetzungen von String zu Enum sollten jetzt perfekt sein. 

4
user3862533

Wenn Sie Spring Boot verwenden, sollten Sie das ist der Grund nicht WebMvcConfigurationSupport verwenden. 

Die bewährte Methode sollten Sie die Schnittstelle org.springframework.core.convert.converter.Converter und mit der Anmerkung @Component implementieren. Dann lädt Spring Boot alle Beans von Converter automatisch. Spring Boot-Code

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

Demo-Projekt

1
Cnfn

sie können String anstelle von SortEnum param verwenden

@RequestParam(name = "sort", required = false) String sort

und konvertieren Sie es mit

SortEnum se;
try {
   se = SortEnum.valueOf(source);
} catch(IllegalArgumentException e) {
   se = null;
}

innerhalb der getEvents (...) -Endpoint-Methode verliert sie an Eleganz, erhält jedoch mehr Kontrolle über die Konvertierung und die mögliche Fehlerbehandlung.

0
andrej