I am currently having trouble with my dataSource bean creation on condition of String property from my applications.yaml file.
Ideally, I would only like to create the dataSource bean only if the url is set in my application.yaml file. Shouldn't create the bean if its not present (empty or null). I know this condition checks on boolean but is there anyway to check if the string property is empty or null?
DatabaseConfig.java
@Configuration
public class DatabaseConfig {
@Value("${database.url:}")
private String databaseUrl;
@Value("${database.username:}")
private String databaseUsername;
@Value("${database.password:}")
private String databasePassword;
protected static final String DRIVER_CLASS_NAME = "com.sybase.jdbc4.jdbc.SybDriver";
/**
* Configures and returns a datasource. Optional
*
* @return A datasource.
*/
@ConditionalOnProperty(value = "database.url")
@Bean
public DataSource dataSource() {
return DataSourceBuilder.create()
.url(testDatabaseUrl)
.username(testDatabaseUsername)
.password(testDatabasePassword)
.build();
}
}
application.yml (This field will be optional)
database:
url: http://localhost:9000
Annotation Type ConditionalOnExpressionReferencing a bean in the expression will cause that bean to be initialized very early in context refresh processing. As a result, the bean won't be eligible for post-processing (such as configuration properties binding) and its state may be incomplete.
The Spring framework provides the @ConditionalOnProperty annotation precisely for this purpose. In short, the @ConditionalOnProperty enables bean registration only if an environment property is present and has a specific value. By default, the specified property must be defined and not equal to false.
The Spring Expression Language (SpEL for short) is a powerful expression language that supports querying and manipulating an object graph at runtime. The language syntax is similar to Unified EL but offers additional features, most notably method invocation and basic string templating functionality.
matchIfMissing. public abstract boolean matchIfMissing. Specify if the condition should match if the property is not set. Defaults to false . Returns: if the condition should match if the property is missing Default: false.
You could use @ConditionalOnExpression
with a Spring Expression Language (SpEL) expression as value:
@ConditionalOnExpression("!T(org.springframework.util.StringUtils).isEmpty('${database.url:}')")
@Bean
public DataSource dataSource() {
// snip
}
For better readability and reusability you could turn this into an annotation:
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@ConditionalOnExpression("!T(org.springframework.util.StringUtils).isEmpty('${database.url:}')")
public @interface ConditionalOnDatabaseUrl {
}
@ConditionalOnDatabaseUrl
@Bean
public DataSource dataSource() {
// snip
}
I'm having the same issue. As I undestood, you'r looking for "property exists and not empty" condition. This condition doesn't come out of the box, therefore some coding required. Solution using org.springframework.context.annotation.Conditional
works for me:
Create ConditionalOnPropertyNotEmpty
annotation and accompanied OnPropertyNotEmptyCondition
class as follows:
// ConditionalOnPropertyNotEmpty.java
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.core.type.AnnotatedTypeMetadata;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.Map;
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Conditional(ConditionalOnPropertyNotEmpty.OnPropertyNotEmptyCondition.class)
public @interface ConditionalOnPropertyNotEmpty {
String value();
class OnPropertyNotEmptyCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attrs = metadata.getAnnotationAttributes(ConditionalOnPropertyNotEmpty.class.getName());
String propertyName = (String) attrs.get("value");
String val = context.getEnvironment().getProperty(propertyName);
return val != null && !val.trim().isEmpty();
}
}
}
Annotate your bean with ConditionalOnPropertyNotEmpty
, like:
@ConditionalOnPropertyNotEmpty("database.url")
@Bean
public DataSource dataSource() { ... }
--
Alternatively, you can either set detabase.url to false explicitly (e.g. detabase.url: false
) or do not define detabase.url
at all in your config. Then, @ConditionalOnProperty(value = "database.url")
will work for you as expected.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With