@ConditionalOnProperty works straight forward, depending upon this property is present (and/or value is correct), condition will result into true or false. But can someone explain how @ConditionalOnClass works? If I am giving annotation as @ConditionalOnClass(Student.class), and the dependency is missing so that class Student not found there then I am getting error. Then how the else part of this conditional annotation works.

2

There are 2 best solutions below

0
trust_nickol On

Spring uses a Condition under the hood to check whether it should load & create the bean or not (pseudo code):

public class OnClassCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        ClassLoader classLoader = context.getClassLoader();
        for (String className : getClasses(metadata)) {
            try {
                Class<?> clazz = Class.forName(className, false, classLoader);
                if (clazz == null) {
                    return false;
                }
            } catch (ClassNotFoundException ex) {
                return false;
            }
        }
        return true;
    }
}

See org.springframework.boot.autoconfigure.condition.OnClassCondition for full implementation.

0
Pistolnikus On

While the answer https://stackoverflow.com/a/77969389/11130394 is correct I believe OP asks something slightly different (please correct me if I'm wrong).

I think the original question is more about this use case:

@ConditionalOnClass(Student.class)
@Configuration
public class ConditionalConfiguration {

    public ConditionalConfiguration() {
        System.out.println("conditional configuration loaded");
    }

}

If Student class does not exist in the code base, code would not compile thus it doesn't make sense to write code like that at all.

I have example where the class "exists" but at runtime the configuration will not be activated. Let's say you have junit dependency specified in pom like this (Under normal circumstances, junit should be included as scope test. I'm using it just because it is well known library.):

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-api</artifactId>
    <version>5.10.2</version>
    <scope>provided</scope><!-- just for example purposes, normally use 'test' scope instead -->
    <!--<scope>compile</scope>-->
</dependency>

Then, one could use ConditionalOnClass like this:

@ConditionalOnClass(org.junit.jupiter.api.Test.class)
@Configuration
public class TestOnClassPath {
    public TestOnClassPath() {
        System.out.println("yes, Test.class is on classpath");
    }
}

Code will compile without any issues, yet if you run it as any other Spring Boot app (e.g. in your IDE), you will not see that the configuration was instantiated (because the condition won't pass).

However, if you change the scope to compile, it will be instantiated (maybe run mvn clean package after changing the scope).

More on Maven scopes here.

Another example usage would be to use name(=String) instead: @ConditionalOnClass(name = "foo.bar.Student"). This way the condition will succeed only after you implement the given class in your project (however I don't think this is the intended usage).

Similar question: I have a problem about using @ConditionalOnClass