Spring Boot将@Value绑定到枚举时不区分大小写

26

枚举

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

运行良好。

有没有一种方法可以不区分大小写地绑定值?像ABCAbcAbCabc这样的任何模式都应该起作用。

注意:我看到了这个问题 - Spring 3.0 MVC binding Enums Case Sensitive,但在我的情况下,我有超过10个枚举/值(并希望有更多)的类,并且实现10个不同的自定义属性绑定器将很痛苦,我需要一些通用解决方案。


看起来是松散绑定的潜在错误。 - chrylis -cautiouslyoptimistic-
抱歉,已编辑说明。值的大小写已切换。 - Mikhail Kholodkov
4个回答

32

@Value@ConfigurationProperties 的功能不匹配。我无法强调@ConfigurationProperties有多么优越。

首先,您可以在一个简单的POJO中设计配置,您可以在任何地方注入它(而不是在注释中使用表达式,您可能会因为输入错误而轻易破坏)。其次,元数据支持意味着您可以非常容易地在IDE中获得自己键的自动完成

最后,文档中描述的放松绑定仅适用于@ConfigurationProperties@Value 是Spring Framework的功能,不知道放松绑定的存在。我们打算在文档中让这更清楚

TL;DR abc 适用于@ConfigurationProperties但不适用于@Value


没问题,谢谢! - Mikhail Kholodkov
@Stephane Nicoll,对于Spring 4有什么建议? - userit1985
1
我认为松散绑定与键有关。我不确定在哪里明确指出值部分中的枚举名称将不区分大小写进行映射。不过,这非常方便。 - rougou

8
一个 ConfigurationProperties 的问题(据我所知)是您无法使用构造函数注入,而且您的类必须是可变的。
解决方法(或者说是hack)是使用 SpEL 在查找属性之前将其转换为大写,像这样: @Value("#{'${custom.property}'.toUpperCase()}") Property property 这应该可以工作,因为枚举实例是常量,并且应始终以大写字母定义:https://docs.oracle.com/javase/tutorial/java/javaOO/enum.html

2

另一个选项是setter注入:

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;

-13
在实际世界中,这是可行的...
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...

}

虽然这违反了枚举的原则!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接