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
这个组件将被初始化。
我想根据属性文件中的枚举加载 @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
这个组件将被初始化。