Spring Boot привязывает @Value к Enum без учета регистра

Enum

public enum Property {
    A,
    AB,
    ABC;
}

поле

@Value("${custom.property}")
protected Property property;

application.properties (нижний регистр)

custom.property=abc

Когда я запускаю приложение, у меня появляется ошибка:

Невозможно преобразовать значение типа [java.lang.String] в требуемый тип [com.xxx.Property]: не найдено подходящих редакторов или стратегии преобразования.

Принимая во внимание, что (верхний регистр):

custom.property=ABC

Работает отлично.

Есть ли способ связать значение без учета регистра? Как ABC, Abc, AbC, abc любой шаблон должен работать.

ПРИМЕЧАНИЕ: я видел этот вопрос - привязка Spring 3.0 MVC перечисления чувствительны к регистру, но в моем случае у меня более 10 классов перечислений / значений (и я ожидаю, что их будет больше), и реализация 10 различных привязок пользовательских свойств была бы болезненной, мне нужно какое-то общее решение,

5 ответов

Решение

@Value а также @ConfigurationProperties функции не совпадают. Я не мог подчеркнуть, как @ConfigurationProperties выше.

Во-первых, вы можете спроектировать свою конфигурацию в виде простого POJO, который вы можете внедрить в любое удобное для вас место (вместо использования выражений в аннотации, которые можно легко разбить опечаткой). Во-вторых, поддержка метаданных означает, что вы можете очень легко получить автозаполнение в своей IDE для ваших собственных ключей.

И, наконец, расслабленное связывание, описанное в документе, относится только к @ConfigurationProperties, @Value является функцией Spring Framework и не знает о непринужденной привязке. Мы намерены прояснить это в документе.

TL; DR abc работает с @ConfigurationProperties но не буду с @Value,

Проблема с ConfigurationPropertis (afaik) заключается в том, что вы не можете использовать инъекцию конструктора, и ваш класс должен быть изменяемым.

Обходное решение (или, если хотите, хакерство) может заключаться в том, чтобы использовать SpEL в верхнем регистре свойства перед его поиском, например:

@Value("#{'${custom.property}'.toUpperCase()}") Property property

Это должно работать, так как экземпляры перечислений являются константами и всегда должны быть определены в верхнем регистре: https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

Значения чувствительны к регистру (учитывайте ключи или пароли, введенные из среды), и ослабленная привязка применяется только к ключам. Имена перечислений Java также чувствительны к регистру (A а также a это разные значения), и вы не захотите раздавливать регистр.

Просто используйте правильный регистр в свойствах вашей конфигурации.

Другой вариант — внедрение сеттера:

      protected Property property;

@Autowired
public void setProperty(@Value("${custom.property}") String propertyString) {
  this.property = Property.valueOf(propertyString.toUpperCase())
}

Он более подробный, чем SpEL, но позволяет выполнять более сложную обработку.


Вы также можете объединить SpEL с собственной функцией синтаксического анализа:

      package com.example.enums

public enum Property {
  A,
  AB,
  ABC;

  public static Property parse(String name) {
    // you can do more complicated processing here
    return valueOf(name.toUpperCase());
  }

}
      @Value("#( T(com.example.enums.Property).parse('${custom.property}') )")
protected Property property;

В практическом мире это работает....

public enum Property {
    A, a
    AB, ab,
    ABC, abc,
    ABCD, abcd,
    ABCDE, abcde; 

    public boolean isA() {
        return this.equals(A) || this.equals(a);
    }

    public boolean isAB() {
        return this.equals(AB) || this.equals(ab);
    }

    ...etc...

}

... хотя это нарушает принцип перечисления!

Другие вопросы по тегам