RadhaPublication
HomeInterviewLearning PathsRole TracksMockBooksPricing
Login / Sign UpLog in

© 2026 Radha Publication. All rights reserved.

Shop on AmazonDonateContactPrivacyTerms
Spring Boot questions
MediumSpring Boot#246 min readJul 11, 2026

Explain @ConditionalOnClass.

practice
learning
Practice modeTest yourself instead of reading straight through

Hook: This is Spring Boot’s “does the toolbox have this tool?” switch, and interviewers love it because it shows whether you understand optional dependencies instead of just memorizing annotations.

Question: Explain @ConditionalOnClass.

Answer: @ConditionalOnClass is a Spring Boot condition that creates a bean or configuration only when a specific class is present on the classpath, which is the set of libraries your app can see at runtime. It is most often used in auto-configuration so Boot can support optional features like JSON, web, or messaging without failing when those libraries are missing.

Interview-Ready Answer: I use @ConditionalOnClass when I want Spring Boot to enable a feature only if a dependency is available. It checks for the class on the classpath before the bean is created, so the app can start safely even when that library is absent. In practice, Boot auto-configurations use it together with @ConditionalOnMissingBean so the framework backs off if the user has already provided their own bean.

🧠 Memory Map
Memory map — visual summary of this topic

What it is

@ConditionalOnClass is a Spring Boot annotation used in auto-configuration and regular configuration to say: “Only activate this bean or config if this type exists.” It is a condition, meaning a rule that must be true before Spring registers the bean definition. This is different from normal @Bean creation, which happens unconditionally once the configuration class is processed.

How it works under the hood

  1. Spring Boot reads configuration metadata from the class bytecode first, not by eagerly creating objects. A class loader is the JVM component that finds and loads class bytecode.
  2. @ConditionalOnClass is backed by Boot’s internal OnClassCondition, which checks whether each required class name is available to the class loader.
  3. Boot can evaluate this from metadata, so it does not need to instantiate the optional class or even load the whole configuration class if the condition fails.
  4. If every listed class is present, the condition matches and Spring keeps that configuration or bean definition.
  5. If one class is missing, Spring skips that bean/configuration silently, which is exactly what makes optional integrations safe.
  6. In auto-configuration, Boot commonly adds @ConditionalOnMissingBean too, so it also avoids overriding a user’s custom bean.

When to use it

Use it when your code depends on an optional library: for example, only wire JSON helpers if Jackson is on the classpath, only create an AMQP adapter if RabbitMQ classes exist, or only enable a cloud integration when the vendor SDK is present. This is one of the core tricks that lets Spring Boot ship many starter modules without forcing every project to pull in every dependency.

Comparison with related conditions

AnnotationChecksTypical use
@ConditionalOnClassType existsOptional library support
@ConditionalOnBeanBean existsBuild on user beans
@ConditionalOnMissingClassType absentFallback behavior

Performance and edge cases

The check is cheap: roughly O(n) in the number of class names listed in the annotation, with each lookup being a fast classpath check. Boot also caches condition evaluation during startup, so this is tiny compared with creating beans or opening network connections. The big gotcha is that value = SomeType.class requires that type to be available at compile time, while name = "com.example.SomeType" lets you avoid a hard dependency on an optional library. Another subtle point: the annotation checks presence, not version or API compatibility, so a class can exist and still be the wrong version for your code.

Version note: the behavior is the same in modern Spring Boot 2.x and 3.x, and it remains a main building block of Boot auto-configuration. The practical rule is simple: if you are integrating with something that may or may not be on the classpath, guard it with @ConditionalOnClass and pair it with a sensible fallback.

Real-world story

Imagine a checkout service that supports Stripe only when the Stripe SDK is installed. With @ConditionalOnClass(name = "com.stripe.Stripe"), Spring Boot creates the Stripe payment adapter only in deployments that include that library. In a test environment or a lightweight internal deployment, the app still starts, and the fallback payment path stays active.

What goes wrong when this is misunderstood: a developer imports the Stripe class directly in a configuration class and forgets the optional dependency is missing in staging. The app crashes during startup with a NoClassDefFoundError, Kubernetes marks the pod as failing, and users see checkout unavailable. In logs, you usually see the failure before the web server finishes booting, which is a strong clue that the problem is classpath-related, not a runtime business bug.

Spring Boot
package com.example.conditionalonclass;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@SpringBootApplication
public class ConditionalOnClassDemoApplication implements CommandLineRunner {

    private final ApplicationContext context;

    public ConditionalOnClassDemoApplication(ApplicationContext context) {
        this.context = context;
    }

    public static void main(String[] args) {
        SpringApplication.run(ConditionalOnClassDemoApplication.class, args);
    }

    @Override
    public void run(String... args) {
        // If the condition matched, the bean exists; if not, the app still starts.
        printBean("featureBean");
        printBean("missingFeatureBean");
        printBean("fallbackBean");
    }

    private void printBean(String beanName) {
        if (context.containsBean(beanName)) {
            System.out.println(beanName + " = " + context.getBean(beanName));
        } else {
            System.out.println(beanName + " was skipped because its class condition did not match.");
        }
    }

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(name = "com.fasterxml.jackson.databind.ObjectMapper")
    static class FeatureConfig {
        @Bean
        String featureBean() {
            // This bean only appears when the optional library is actually on the classpath.
            return "Feature enabled: Jackson-like library detected";
        }
    }

    @Configuration(proxyBeanMethods = false)
    static class FallbackConfig {
        @Bean
        String fallbackBean() {
            // A normal bean with no condition: always available.
            return "Always available fallback";
        }

        @Bean
        @ConditionalOnClass(name = "com.example.optional.DoesNotExist")
        String missingFeatureBean() {
            // This never runs in a normal app, which is exactly the point:
            // the optional integration is skipped instead of breaking startup.
            return "You should never see this";
        }
    }
}

Follow-up & Tricky Questions:

  • How is @ConditionalOnClass different from @ConditionalOnBean? @ConditionalOnClass checks the classpath, while @ConditionalOnBean checks the application context for an actual bean instance. One is about available libraries; the other is about already-created Spring beans.
  • Why does Spring Boot often pair it with @ConditionalOnMissingBean? So Boot can provide a default only when the user has not defined their own bean. This is the “back off” rule that makes Boot auto-configuration polite instead of invasive.
  • When should I use name instead of value? Use name when the class may not be on your compile classpath, because value = SomeType.class requires the type to be available to compile. name is the safer choice for truly optional external libraries.
  • Can I put it on a @Bean method? Yes. That lets Spring skip only that bean while keeping the rest of the configuration class active, which is useful when one feature is optional but the rest of the module is always needed.
  • How do I test it? Use ApplicationContextRunner in Boot tests to start a tiny context and assert whether the bean is present. That gives you fast, focused condition tests without launching the whole app.
  • Tricky: does it load the class or just check it? It just checks presence; it does not instantiate the class. That is why it is safe for optional integrations.
  • Tricky: does it verify the library version? No. A class can be present but still be the wrong version or missing a method your code expects, so compatibility is still your job.
  • Tricky: if my config class directly mentions a missing type in a field or method signature, will the condition save me? Not always. Direct references can cause class loading problems before the condition helps, which is why Boot samples separate optional integration code and often use string-based class names.

Common Mistakes:

  • Confusing classpath checks with bean checks. Correction: use @ConditionalOnClass for libraries and @ConditionalOnBean for Spring beans.
  • Using value = OptionalType.class for a dependency that may be absent. Correction: use name = "fully.qualified.Type" for optional libraries.
  • Thinking it validates API compatibility. Correction: it only checks presence, not behavior or version.
  • Putting optional code in the same class in a way that still loads the missing type. Correction: isolate optional integrations into separate config classes or use string-based names.

Memory Hook: Think: “If the tool is in the toolbox, open the box; if not, leave the room.” The classpath is the toolbox, and @ConditionalOnClass decides whether the box gets opened.

Cheat Sheet:

  • Checks for a class on the classpath.
  • Used heavily in Spring Boot auto-configuration.
  • Prevents startup failures for optional dependencies.
  • Often combined with @ConditionalOnMissingBean.
  • Use name for truly optional external types.
  • Presence only: no version, no API validation.

Practice Tasks:

  • Add a second conditional bean that activates only when org.h2.Driver is present, then run the app with and without H2.
  • Write a test with ApplicationContextRunner that asserts featureBean exists when the class is present and disappears when it is not.
  • Refactor one configuration class so the optional integration is isolated cleanly, then explain why that avoids class loading problems.
Previous
Back to Questions←→to navigate
Next

Recommended Resources

Recommended Book

Cracking the Coding Interview

189 Programming Questions and Solutions

Recommended Book

Cracking the Coding Interview

189 Programming Questions and Solutions

package com.example.conditionalonclass; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @SpringBootApplication public class ConditionalOnClassDemoApplication implements CommandLineRunner { private final ApplicationContext context; public ConditionalOnClassDemoApplication(ApplicationContext context) { this.context = context; } public static void main(String[] args) { SpringApplication.run(ConditionalOnClassDemoApplication.class, args); } @Override public void run(String... args) { // If the condition matched, the bean exists; if not, the app still starts. printBean("featureBean"); printBean("missingFeatureBean"); printBean("fallbackBean"); } private void printBean(String beanName) { if (context.containsBean(beanName)) { System.out.println(beanName + " = " + context.getBean(beanName)); } else { System.out.println(beanName + " was skipped because its class condition did not match."); } } @Configuration(proxyBeanMethods = false) @ConditionalOnClass(name = "com.fasterxml.jackson.databind.ObjectMapper") static class FeatureConfig { @Bean String featureBean() { // This bean only appears when the optional library is actually on the classpath. return "Feature enabled: Jackson-like library detected"; } } @Configuration(proxyBeanMethods = false) static class FallbackConfig { @Bean String fallbackBean() { // A normal bean with no condition: always available. return "Always available fallback"; } @Bean @ConditionalOnClass(name = "com.example.optional.DoesNotExist") String missingFeatureBean() { // This never runs in a normal app, which is exactly the point: // the optional integration is skipped instead of breaking startup. return "You should never see this"; } } }