Introduction
Spring @ConditionalOnClass
and @ConditionalOnMissingClass
annotations let @Configuration
classes be included based on the presence or absence of specific classes. So @ConditionalOnClass
loads a bean only if a certain class is on the classpath and @ConditionalOnMissingClass
loads a bean only if a certain class is not on the classpath.
This mechanism does not apply the same way to @Bean
methods where typically the return type is the target of the condition: before the condition on the method applies, the JVM will have loaded the class and potentially processed method references which will fail if the class is not present.
Prerequisites
Gradle 5.6 – 6.7.1, Java at least 8, Spring Boot 2.1.7 – 2.4.3
Project Setup
Create a gradle or maven based project in your favorite IDE or tool with the project name as spring-conditional-on-class.
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.3
}
repositories {
maven {
url 'https://plugins.gradle.org/m2/'
}
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
plugins {
id 'java-library'
id 'org.springframework.boot' version "${springBootVersion}"
}
sourceCompatibility = 12
targetCompatibility = 12
repositories {
mavenCentral()
jcenter()
}
dependencies {
implementation("org.springframework.boot:spring-boot-starter-web:${springBootVersion}")
}
For maven based project you can use the following pom.xml file:
<?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-class</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>12</maven.compiler.source>
<maven.compiler.target>12</maven.compiler.target>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.7.RELEASE to 2.4.3</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>
Examples on @ConditionalOnClass
I will create various ways of using @ConditionalOnClass
annotation.
Service Class
I will create simple service class without any methods in it. Ideally this service class will have some methods to perform your project’s business operations.
Notice I have put clazz
in the package name because class is not allowed.
package com.roytuts.spring.conditional.on.clazz;
public class SpringService {
}
Main Class
I will create a main class to run our Spring Boot application. I will not modify our main class at all, that’s why I am writing the source code of main class here.
package com.roytuts.spring.conditional.on.clazz;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringConditionalOnClassApp implements CommandLineRunner {
@Autowired
private SpringService springService;
public static void main(String[] args) {
SpringApplication.run(SpringConditionalOnClassApp.class, args);
}
@Override
public void run(String... args) throws Exception {
System.out.println("Spring service fully qualified class name: " + springService.getClass());
}
}
Simple Class
I will create a simple class which will be required to call on @ConditionalOnClass
annotation because this class will be executed only when the required class is found.
Class – RequiredClass
Create a simple class as shown below:
package com.roytuts.spring.conditional.on.clazz;
public class RequiredClass {
}
Examples
I will create a Spring Config class and use annotation @ConditionalOnClass
in various ways, such as, by name, value and will see how it works.
I will modify our Spring Config class for each type of example.
@ConditionalOnClass – by name
I will now use the @ConditionalOnClass
by passing the class name for the value name
.
package com.roytuts.spring.conditional.on.clazz;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnClass(name = "com.roytuts.spring.conditional.on.clazz.RequiredClass")
public class SpringConfig {
@Bean
public SpringService springService() {
return new SpringService();
}
}
By executing the main class, you will see below output:
Spring service fully qualified class name: class com.roytuts.spring.conditional.on.clazz.SpringService
If your class RequiredClass
is not found then you will see following error:
The following candidates were found but could not be injected:
- Bean method 'springService' in 'SpringConfig' not loaded because @ConditionalOnClass did not find required class <Class Name>
In the above example, I am passing single bean name but you can also pass multiple bean names in the following way:
@ConditionalOnClass(name = { "com.roytuts.spring.conditional.on.clazz.RequiredClass",
"com.roytuts.spring.conditional.on.clazz.AnotherRequiredClass" })
@ConditionalOnClass – by value
Here I will show @ConditionalOnClass
by value in Spring Config class.
I will pass the class for the value value
.
package com.roytuts.spring.conditional.on.clazz;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnClass(value = RequiredClass.class)
public class SpringConfig {
@Bean
public SpringService springService() {
return new SpringService();
}
}
By executing the main class, you will see the same output as you had seen using class name
.
If you want to pass multiple classes for the parameter value then you can do in the following way:
@ConditionalOnClass(value = {RequiredClass.class, AnotherRequiredClass.class})
Examples on @ConditionalOnMissingClass
I will create various ways of using @ConditionalOnMissingClass
annotation.
This annotation supports by value
only.
Service Class
Create a simple service class:
package com.roytuts.spring.conditional.on.missing.clazz;
public class SpringService {
}
Config Class
I will create simple service class without any methods in it. Ideally this service class will have some methods to perform your project’s business operations.
package com.roytuts.spring.conditional.on.missing.clazz;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@ConditionalOnMissingClass(value = "com.roytuts.spring.conditional.on.missing.clazz.MissingClass")
public class SpringConfig {
@Bean
public SpringService springService() {
return new SpringService();
}
}
Main Class
I need this main class to test the application.
package com.roytuts.spring.conditional.on.missing.clazz;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringConditionalOnMissingClassApp implements CommandLineRunner {
@Autowired
private SpringService springService;
public static void main(String[] args) {
SpringApplication.run(SpringConditionalOnMissingClassApp.class, args);
}
@Override
public void run(String... args) throws Exception {
System.out.println("Spring service fully qualified class name: " + springService.getClass());
}
}
Running the above main class will produce below output:
Spring service fully qualified class name: class com.roytuts.spring.conditional.on.missing.clazz.SpringService
If MissingClass
exists then you will see the following error in console:
The following candidates were found but could not be injected:
- Bean method 'springService' in 'SpringConfig' not loaded because @ConditionalOnMissingClass found unwanted class 'com.roytuts.spring.conditional.on.missing.clazz.MissingClass'
Or
Field springService in com.roytuts.spring.conditional.on.missing.clazz.SpringConditionalOnMissingClassApp required a bean of type 'com.roytuts.spring.conditional.on.missing.clazz.SpringService' that could not be found.
That’s all about conditional on class and conditional on missing class in Spring framework.