Would be nice to add an operator to @OptionalOnProperty
which distinguishes how multiple name items are handled:
- ALL: the same as now, all properties must be there.
- ANY: at least 1 property must be there.
- NONE: none of properties. But this somewhat clashes with 'havingValue' and 'matchIfMissing'.
- Maybe something else.
Most interesting is ANY operator.
Why this is necessary?
Imagine that we have a bunch of beans (which represent some feature). Beans declared in class MyConfig, which is in dependency project (jar).
```java @Configuration @ConditionalOnProperty(prefix = "my.feature", name = {"foo", "bar"}, operator = Operators.ANY) MyConfig { @Bean bean1() ... @Bean bean2() ... @Bean bean3() ... }
In the main project (which references that jar) we don't want these beans to be initiated (thus feature to be enabled) by default, but only when we set either `my.feature.foo` or `my.feature.bar`.
For us this is very typical case.
Meanwhile we solve this with workarounds:
- Sometimes messy `AnyNestedCondition`.
- Sometimes we introduce artificial `my.feature.enabled` property, so we use `@ConditionalOnProperty("my.feature.enabled")`. Thus if we want to enable feature with "foo" option, we need to set both `my.feature.enabled=true` and `my.feature.foo = foo_value` instead of just `my.feature.foo = foo_value`
Similar stuff can be added to other annotations (@ConditionalOnBean, @ConditionalOnResource etc), though we don't have related use-cases.
Ideally it would be nice to have "complex conditions", like:
```java
@Configuration
@ConditionalOnComplexCondition(
@And({
@Or({ // ANY operator with @Or annotation
@ConditionalOnProperty("my.feature.foo"),
@ConditionalOnProperty("my.feature.bar")}
}),
@ConditionalOnJava(JavaVersion.NINE)
})
)
MyConfig {
...
}
but guess this is impossible with annotations syntax.
Comment From: quaff
My suggestion is add a simple flag negative
default false
to negate current result.
@ConditionalOnProperty(value = "foo.bar", negative = true) // match if "foo.bar" not exists
@ConditionalOnProperty(value = "foo.bar", havingValue = "test", negative = true) // match if "foo.bar" not exists or not equals "test"
@ConditionalOnProperty(value = "foo.bar", havingValue = "test", matchIfMissing = true, negative = true) // match if "foo.bar" exists and not equals "test"
WDYT @wilkinsona ?
Comment From: snicoll
@quaff ConditionalOnProperty
we've considered such an option in the past and our thinking is that the condition is already involved enough. Adding more attributes will make the annotation harder to resonate about, thanks for the suggestion in any case.
Comment From: quaff
@quaff
ConditionalOnProperty
we've considered such an option in the past and our thinking is that the condition is already involved enough. Adding more attributes will make the annotation harder to resonate about, thanks for the suggestion in any case.
What's the best practice NOT to match specified value? @snicoll
Comment From: snicoll
Good question. You'll find a number of issues in the issue tracker: #23794 and #4938.
Comment From: quaff
Good question. You'll find a number of issues in the issue tracker: #23794 and #4938.
If I understood correctly, you are suggesting writing my own condition extends NoneNestedConditions
, I don't think it's graceful than @ConditionalOnExpression("'${key:defaultValue}' != 'value'")
.
Anyway, It should be mentioned in references and ConditionalOnProperty
javadoc also.