Как преобразовать целое число в параметре запроса в enum для поля типа enum без использования @JsonCreator? - PullRequest
0 голосов
/ 10 октября 2019

в нашем проекте мы определяем перечисления как ниже

public enum GenderEnum implements IEnum{
  MALE(1),
  FEMALE(2);

  private Integer code;

  GenderEnum(int code) {
    this.code = code;
  }

  public static GenderEnum getByCode(int code) {
    for (GenderEnum genderEnum : values()) {
        if (genderEnum.code == code) {
            return genderEnum;
        }
    }
    return null;
  }
}

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

public class Param{
  String id;
  GenderEnum gender;
}

у нас есть контроллеры как

@RestController
class MyController{
  @PostMapping('/alink')
  ResponseBean doSomething(@RequestBody Param param){
      ...
  }
}

для приведенного выше случая, когда тело запроса равно

{"id":"L323", "gender":1}

, мы надеемся, 1 можно преобразовать в перечисление MALE

Одно из решений заключается в добавлении @JsonCreator over getByCode(int code) utНо в нашем существующем проекте слой хранилища преобразует enum в его строковое значение (MALE или FEMALE), но не в значение code перед вставкой их в базу данных. Поэтому, если мы добавим @JsonCreator сверх getByCode(int code), мы столкнемся с ошибками при попытке извлечь перечисления из базы данных.

как мы можем заставить mvc / controller преобразовать целочисленное значение входных данных в enum, не затрагивая слой хранилища?

Я вижу решение, как показано ниже:

    @Configuration
    public class WebMvcConfig implements WebMvcConfigurer {

        @Override
        public void addFormatters(FormatterRegistry registry) {  
            registry.addConverterFactory(new EnumConverterFactory());
        }
    }



static class EnumConverterFactory implements ConverterFactory<Integer, IEnum> {
    @Override
    public <T extends IEnum> Converter<Integer, T> getConverter(Class<T> targetType) {
        if (!targetType.isEnum()) {
            throw new UnsupportedOperationException(targetType + "is not enum");
        }
        return new EnumConverter(targetType);
    }

    private static class EnumConverter<T extends IEnum> implements Converter<Integer, T> {
        private final Class<T> enumType;

        public EnumConverter(Class<T> enumType) {
            this.enumType = enumType;
        }

        @Override
        public T convert(Integer code) {
            for (T t : enumType.getEnumConstants()) {
                if (code.equals(t.getCode())) {
                    return t;
                }
            }
            return null;
        }
    }
}

, ноэто решение не работает. При отладке я замечаю, что разрешение параметра зависит от сериализации Джексона (которая преобразует целое число в enum согласно порядковому номеру вместо значения кода), и преобразователь просто не задействован.

Итак, есть ли обходной путь?

1 Ответ

0 голосов
/ 10 октября 2019

Вы можете в своем контроллере объявить метод для пользовательского сопоставления параметров определенного типа:

@InitBinder
public void initBinder(WebDataBinder dataBinder) {

        dataBinder.registerCustomEditor(GenderEnum.class,
            new PropertyEditorSupport() {
                @Override
                public void setAsText(String value){                    
                    setValue(GenderEnum.getByCode(Integer.parseInt(value));
                }               
            });     
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...