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

ConditionalOnExpression fails to compare configuration property to enum type, works as string

我想根据属性文件中的枚举加载 @Configuration class,所以我有以下 class:

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

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

这不起作用,并抛出异常:

Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'value' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public or not valid?

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

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

问题:

为什么比较这样的枚举会失败?为什么 Spring 可以成功转换值并将其作为字符串进行比较而不是作为它们的类型进行比较?

这是在 Spring Boot 2.0.4

应该很明显,真的。

考虑以下 Java 代码:

foo.equals(DemoEnum.VALUE)

它需要一个对象 foo,也许是 this:

上的一个字段
this.foo.equals(DemoEnum.VALUE)

如果您的 属性 占位符的计算结果为 'foo',您的第一个 SpEL 表达式相当于

#this.foo eq T(DemoEnum).VALUE

所以 SpEL 在 #this

上寻找 属性 foo

编辑

如果创建 Class:

public class Foo {

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

    public getEnum() {
        return this.enum;
    }

}

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

foo.enum eq ...

因为 #this 是一个 BeanExpressionContext 允许您引用其他 bean。

我遇到了类似的问题。 我有一个功能,默认情况下启用。要禁用它,应用程序配置文件应该明确禁用它。 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这个组件将被初始化。