ConditionalOnExpression无法将配置属性与枚举类型进行比较,可作为字符串使用

时间:2018-08-15 06:50:32

标签: spring-boot spring-el

我想基于属性文件中的枚举加载@Configuration类,所以我有以下类:

@Configuration
@ConditionalOnExpression("#{ ${demo.spel.demo-enum} eq T(demo.spel.DemoEnum).VALUE }")
public class DemoConfig {}

我有:demo.spel.demo-enum=value中的application.properties

这不起作用,并引发异常:

  

由以下原因导致:org.springframework.expression.spel.SpelEvaluationException:EL1008E:在类型为“ org.springframework.beans.factory.config.BeanExpressionContext”的对象上找不到属性或字段“值”-可能不是公共的,也可能不是有效吗?

奇怪的是,如果我在表达式的属性部分添加单引号,在表达式的枚举部分添加toString(),则没有例外,条件为true,并且创建了bean(通过在调试日志记录中检查控制台输出进行验证):

@ConditionalOnExpression("#{ '${demo.spel.demo-enum}' eq T(demo.spel.DemoEnum).VALUE.toString() }")

问题:

为什么比较这样的枚举失败? Spring如何成功地转换值并以字符串而不是类型进行比较?

这是在Spring Boot 2.0.4上

2 个答案:

答案 0 :(得分:2)

这应该很明显。

考虑以下Java代码:

foo.equals(DemoEnum.VALUE)

这将需要一个对象foo,可能是this上的一个字段:

this.foo.equals(DemoEnum.VALUE)

如果属性占位符的计算结果为“ foo”,则第一个SpEL表达式等于

#this.foo eq T(DemoEnum).VALUE

因此SpEL在foo上寻找属性#this

编辑

如果您创建班级:

public class Foo {

    @Value("${some.property}")
    private DemoEnum enum;

    public getEnum() {
        return this.enum;
    }

}

然后将一个bean添加到名为“ foo”的上下文中,然后您就可以使用

foo.enum eq ...

由于#thisBeanExpressionContext,允许您引用其他bean。

答案 1 :(得分:0)

我有类似的问题。 我有一个功能,默认情况下已启用。要禁用它,应用程序配置文件应显式禁用它。 demo.feature.disable:true

我有一个以此属性为条件的spring bean(默认情况下启用)。

@ConditionalOnExpression("#{ ${demo.feature.disable} != true }")
@Component
public class FeatureModule {
}

问题是,当未在配置文件-demo.spel.value中定义application.yml时,此组件的初始化将因

而失败
Caused by: org.springframework.expression.spel.SpelParseException: EL1041E: After parsing a valid expression, there is still more data in the expression: 'lcurly({)'

为解决此问题,我提供了默认值。

@ConditionalOnExpression("#{ ${demo.feature.disable:false} != true }")
@Component
public class FeatureModule {
}

现在,当我对其进行测试时。 默认情况下,此组件已初始化。

如果配置文件中没有demo.feature.disable,则将初始化此组件。

如果配置文件中有demo.feature.disable:true,则不会初始化此组件。

如果配置文件中有demo.feature.disable:false,则此组件将被初始化。