it-swarm.com.ru

Весенний @RequestParam с Enum

У меня есть это перечисление:

public enum SortEnum {
    asc, desc;
}

Что я хочу использовать в качестве параметра запроса на отдых:

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

Работает нормально при отправке этих запросов

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

Но когда я отправляю:

/events?sort=somethingElse

Я получаю ответ 500 и это сообщение в консоли:

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

Есть ли способ предотвратить выброс этих исключений пружиной и установить для перечисления значение null?

ПРАВКА 

Принятый ответ Стрелка работает. Однако я решил разобраться с обработкой исключения 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

Вы можете создать собственный конвертер, который будет возвращать null вместо исключения, если указано неверное значение. 

Что-то вроде этого:

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

И простой конвертер может выглядеть так:

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

вам нужно сделать следующее

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

см. следующее: https://machiel.me/post/Java-enums-as-request-parameters-in-spring-4/

19
satish chennupati

Ответы, представленные до настоящего времени, не являются полными. Вот пример ответа шаг за шагом, который работал для меня: -

1. Определите перечисление в вашей подписи конечной точки (тип подписки).
Пример :

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-й Определите пользовательский редактор свойств, который будет использоваться для перевода из String в 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);
        }
    }
}

3-й Зарегистрируйте редактор свойств с контроллером:

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

Переводы из строки в enum должны теперь происходить идеально. 

4
user3862533

Если вы используете Spring Boot, это причина что вы не должны использовать WebMvcConfigurationSupport

Лучше всего использовать интерфейс org.springframework.core.convert.converter.Converter и аннотацию @Component. Затем Spring Boot автоматически загрузит все компоненты Converter. Spring Boot code

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

Демонстрационный проект

1
Cnfn