Reputation: 4646
I want to optionally enable a @Configuration
, based on whether a type of application.properties
property exists or not. However I will not know the whole property name in advance, only part of its prefix i.e.
spring.security.oauth2.<provider-name>.url=x.y.z
And the goal is to enable the configuration using something like:
@ConditionalOnProperty(prefix = "spring.security", value="oauth2.*")
or something like that but it doesn't seem to work. I've tried multiple combinations, none work it always expects the full property name but I don't know the <provider-name>
in advance. Any ways to achieve this functionality?
Upvotes: 4
Views: 1804
Reputation: 2188
To improve on @Pentakon answer, few more additions that we can do:
Create our own annotation to hold the prefix
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PropertyPrefix {
String value();
}
Use this on in your configuration class
@PropertyPrefix("redis")
@Conditional(PropertyPrefixPresentCondition.class)
And the implementation of PropertyPrefixPresentCondition
public class PropertyPrefixPresentCondition implements Condition {
@Override
public boolean matches(@NotNull ConditionContext context, AnnotatedTypeMetadata metadata) {
var prefix = metadata.getAnnotations()
.get(PropertyPrefix.class)
.getValue("value")
.map(Object::toString)
.orElse(null);
if (StringUtils.isEmpty(prefix)) {
throw new IllegalStateException("Prefix must be present");
}
var env = context.getEnvironment();
for (PropertySource<?> source : ((AbstractEnvironment) env).getPropertySources()) {
if (source instanceof MapPropertySource mapPropertySource) {
for (String propertyName : mapPropertySource.getSource().keySet()) {
if (propertyName.startsWith(prefix)) {
return true;
}
}
}
}
return false;
}
}
Upvotes: 0
Reputation: 4646
As of right now Spring does not support the requested functionality with the out of the box annotations which means a custom @Conditional
condition must be created that does what we want. The Condition
implementation looks like this:
public class EnableOAuth2Condition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment env = context.getEnvironment();
for(Iterator it = ((AbstractEnvironment) env).getPropertySources().iterator(); it.hasNext(); ) {
PropertySource propertySource = (PropertySource) it.next();
if (propertySource instanceof MapPropertySource) {
for (String propertyName : ((MapPropertySource) propertySource).getSource().keySet()) {
if(propertyName.startsWith("spring.security.oauth2")) {
return true;
}
}
}
}
return false;
}
}
and the way to use it on a @Configuration
class is the following:
@Configuration
@Conditional(EnableOAuth2Condition.class)
public class MyOAuth2Config {
...
}
A bit messy for something simple but that's the way to go for now.
Upvotes: 3