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...
}
... хотя это нарушает принцип перечисления!