Spring @ConditionalOnExpression Example

Condition On Expression

I will create examples how to work with Spring Conditional on Expression using @ConditionalOnExpression. The @ConditionalOnExpression annotation lets configuration be included based on the result of a SpEL (Spring Expression Language) expression. For this example the Module class is only loaded if a particular SpEL is enabled. This way, you might create similar modules that are only loaded if their respective SpEL has been found or enabled.

SpEL or Spring Expression Language which can be used to query property value from properties file using $, or manipulate Java object and its attributes at runtime using #. Both modifiers $ and # can be used in spring XML configuration file directly, or can be used in Java source code with @Value annotation.

Prerequisites

Java 12/19, Gradle 5.6 – 6.7.1, Spring Boot 2.1.7 – 2.4.2/3.1.5, Maven 3.6.3/3.8.5

Project Setup

Create a gradle or maven based project in your favorite tool with the project name asĀ spring-conditional-on-expression.

The following pom.xml file can be used for the project:

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>

	<groupId>com.roytuts</groupId>
	<artifactId>spring-conditional-on-expression</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<maven.compiler.source>19</maven.compiler.source>
		<maven.compiler.target>19</maven.compiler.target>
	</properties>

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.1.5</version>
	</parent>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>
</project>

The default generated build.gradle script does not include required dependencies, so I will update the build script as follows to include the spring boot dependencies.

buildscript {
	ext {
		springBootVersion = '2.1.7.RELEASE' to '2.4.2'
	}
    repositories {
    	mavenLocal()
    	mavenCentral()
    }
    dependencies {
    	classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
    }
}

apply plugin: 'java'
apply plugin: 'org.springframework.boot'

sourceCompatibility = 12
targetCompatibility = 12

repositories {
	mavenLocal()
    mavenCentral()
}

dependencies {
	implementation("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
}

Module Class

Create a simple Module class just to check whether it is loaded or not based on SpEL condition.

public class Module {
}

Application Properties File

Create an application.properties file under src/main/resources folder with below content:

module.enabled=true
module.submodule.enabled=true

Spring Config Class

Create below SpringConfig class to load the Module class conditionally.

So if SpEL conditions are evaluated to true, then only Module class will be loaded otherwise not.

@Configuration
@ConditionalOnExpression(value = "${module.enabled} and ${module.submodule.enabled}")
class SpringConfig {
	@Bean
	public Module module() {
		return new Module();
	}
}

Main Class

Create main class to test the application.

@SpringBootApplication
public class SpringConditionalOnExpressionApp implements CommandLineRunner {
	@Autowired
	private ApplicationContext applicationContext;
	public static void main(String[] args) {
		SpringApplication.run(SpringConditionalOnExpressionApp.class, args);
	}
	@Override
	public void run(String... args) throws Exception {
		String[] beans = applicationContext.getBeanDefinitionNames();
		Arrays.sort(beans);
		boolean contains = Arrays.stream(beans).anyMatch("module"::equalsIgnoreCase);
		if (contains) {
			System.out.println("Module loaded");
		} else {
			System.out.println("Module not loaded");
		}
	}
}

Testing the Application

Now if you run the above main class, you will see below output:

Module loaded

If you make false to any of the keys in the application.properties file then you will get below output:

Module not loaded

You can also check if any of the values is true for the keys in application.properties file in the following way.

@ConditionalOnExpression(value = "${module.enabled} or ${module.submodule.enabled}")

By executing the main class you will get below output:

Module loaded

You can also pass default value to the SpEL using the following way:

@ConditionalOnExpression(value = "${module.enabled:true} and ${module.submodule.enabled:true}")

You can also check for equality of the expression values as shown below:

@ConditionalOnExpression("'${module.enabled}'.equals('${module.submodule.enabled:true}')")

You can use @ConditionalOnExpression on class object’s methods, i.e., @ConditionalOnExpression("#{T(java.lang.Math).random() gt 0}").

Remember the method has to be static.

For the above case, if the random value is greater than 0 then only module will be loaded.

Let’s say you have the following class:

public class SpEL {
	public static String getHello() {
		return "hello";
	}
}

And you want to use method from the above class on @ConditionalOnExpression. Then you can use the following:

@ConditionalOnExpression("#{T(com.roytuts.spring.conditional.on.expression.SpEL).getHello() eq 'hello'}")

or

@ConditionalOnExpression("#{T(com.roytuts.spring.conditional.on.expression.SpEL).getHello()?.equals('hello')}")

For the above case, the module is loaded only when getHello() returns hello.

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *