Spring @ConditionalOnClass and @ConditionalOnMissingClass

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

Eclipse 2019-06(4.12), Gradle 5.6, Java 12, Spring Boot 2.1.7

Creating Project

Create a gradle based project in Eclipse with the project name as spring-conditional-on-class.

Updating Build Script

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

buildscript {
	ext {
		springBootVersion = '2.1.7.RELEASE'
	}
    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}")
}

Examples on @ConditionalOnClass

We will create various ways of using @ConditionalOnClass annotation.

Creating Service Class

We 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 {
}

Creating Main Class

We will create a main class to run our Spring Boot application. We will not modify our main class at all, that’s why we are 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());
	}
}

Creating a Simple Class

We 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 {
}

Creating Examples

We will create a Spring Config class and use annotation @ConditionalOnClass in various ways, such as, by namevalue and will see how it works.

We will modify our Spring Config class for each type of example.

@ConditionalOnClass – by name

We 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, we are 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 we will see @ConditionalOnClass by value in Spring Config class.

We 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 we 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

We will create various ways of using @ConditionalOnMissingClass annotation.

This annotation supports by value only.

Creating Service Class

Create a simple service class:

package com.roytuts.spring.conditional.on.missing.clazz;
public class SpringService {
}

Creating Config Class

We 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();
	}
}

Creating Main Class

We need this main class to test our 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'

Source Code

@ConditionalOnClass @ConditionalOnMissingClass

Thanks for reading.

Related posts

Leave a Comment