CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework-boot--spring-boot-autoconfigure

Spring Boot AutoConfigure provides auto-configuration capabilities that automatically configure Spring applications based on jar dependencies present on the classpath

Pending
Overview
Eval results
Files

edge-cases.mddocs/examples/

Edge Cases and Advanced Scenarios

Handle special situations and edge cases in Spring Boot AutoConfigure.

Edge Case 1: Circular Dependencies

Problem

Two auto-configurations depend on each other's beans.

Solution

@AutoConfiguration
public class ServiceAConfiguration {
    
    @Bean
    @Lazy  // Break circular dependency
    public ServiceA serviceA(ServiceB serviceB) {
        return new ServiceA(serviceB);
    }
}

@AutoConfiguration
public class ServiceBConfiguration {
    
    @Bean
    public ServiceB serviceB(@Lazy ServiceA serviceA) {
        return new ServiceB(serviceA);
    }
}

Edge Case 2: Multiple Beans of Same Type

Problem

Multiple beans of the same type, need to select one.

Solution

@AutoConfiguration
public class DataSourceConfiguration {
    
    @Bean
    @Primary  // Default choice
    public DataSource primaryDataSource() {
        return new HikariDataSource();
    }
    
    @Bean
    @Qualifier("readonly")
    public DataSource readOnlyDataSource() {
        return new HikariDataSource();
    }
}

// Usage
@Service
public class MyService {
    private final DataSource dataSource;
    
    public MyService(@Qualifier("readonly") DataSource dataSource) {
        this.dataSource = dataSource;
    }
}

Edge Case 3: Conditional on Missing Property

Problem

Enable feature only when property is NOT set.

Solution

@Configuration
public class DefaultConfiguration {
    
    @Bean
    @ConditionalOnProperty(
        name = "custom.service.url",
        matchIfMissing = true  // Match when property is missing
    )
    public ServiceClient defaultServiceClient() {
        return new ServiceClient("http://default-url");
    }
    
    @Bean
    @ConditionalOnProperty(name = "custom.service.url")
    public ServiceClient customServiceClient(
            @Value("${custom.service.url}") String url) {
        return new ServiceClient(url);
    }
}

Edge Case 4: Nested Conditional Logic (OR)

Problem

Apply configuration if ANY condition matches.

Solution

@Configuration
@Conditional(DatabaseOrCacheCondition.class)
public class StorageConfiguration {
    // Configuration
}

static class DatabaseOrCacheCondition extends AnyNestedCondition {
    DatabaseOrCacheCondition() {
        super(ConfigurationPhase.REGISTER_BEAN);
    }
    
    @ConditionalOnProperty("database.enabled")
    static class DatabaseEnabled {}
    
    @ConditionalOnProperty("cache.enabled")
    static class CacheEnabled {}
}

Edge Case 5: Dynamic Bean Registration

Problem

Register beans based on runtime configuration.

Solution

@AutoConfiguration
public class DynamicBeanConfiguration implements ImportBeanDefinitionRegistrar {
    
    @Override
    public void registerBeanDefinitions(
            AnnotationMetadata metadata,
            BeanDefinitionRegistry registry) {
        
        // Read configuration
        Environment env = ((EnvironmentCapable) registry).getEnvironment();
        String[] serviceNames = env.getProperty(
            "services.names", 
            String[].class, 
            new String[0]
        );
        
        // Register bean for each service
        for (String name : serviceNames) {
            BeanDefinitionBuilder builder = BeanDefinitionBuilder
                .genericBeanDefinition(ServiceClient.class)
                .addConstructorArgValue(name)
                .addConstructorArgValue(
                    env.getProperty("services." + name + ".url")
                );
            
            registry.registerBeanDefinition(
                name + "Client",
                builder.getBeanDefinition()
            );
        }
    }
}

Edge Case 6: Conditional on Bean Method

Problem

Create bean only if another bean's method returns true.

Solution

// Don't do this - causes early initialization
@ConditionalOnExpression("@featureService.isEnabled('myFeature')")

// Instead, use property
@ConditionalOnProperty("features.myFeature.enabled")

// Or custom condition
public class FeatureEnabledCondition extends SpringBootCondition {
    @Override
    public ConditionOutcome getMatchOutcome(
            ConditionContext context,
            AnnotatedTypeMetadata metadata) {
        String enabled = context.getEnvironment()
            .getProperty("features.myFeature.enabled");
        return "true".equals(enabled) 
            ? ConditionOutcome.match() 
            : ConditionOutcome.noMatch("Feature disabled");
    }
}

Edge Case 7: Conditional on Multiple Classes (OR)

Problem

Enable if ANY of multiple classes is present.

Solution

public class OnAnyDatabaseDriverCondition extends AnyNestedCondition {
    OnAnyDatabaseDriverCondition() {
        super(ConfigurationPhase.REGISTER_BEAN);
    }
    
    @ConditionalOnClass(name = "com.mysql.cj.jdbc.Driver")
    static class MySQLPresent {}
    
    @ConditionalOnClass(name = "org.postgresql.Driver")
    static class PostgreSQLPresent {}
    
    @ConditionalOnClass(name = "oracle.jdbc.OracleDriver")
    static class OraclePresent {}
}

@Configuration
@Conditional(OnAnyDatabaseDriverCondition.class)
public class DatabaseConfiguration {
    // Configuration
}

Edge Case 8: Parameterized Container Beans

Problem

Detect generic beans like Repository<User>.

Solution

@Configuration
public class RepositoryConfiguration {
    
    @Bean
    @ConditionalOnBean(
        value = User.class,
        parameterizedContainer = Repository.class
    )
    public UserService userService(Repository<User> userRepository) {
        return new UserService(userRepository);
    }
}

Edge Case 9: Conditional on Resource Pattern

Problem

Enable if any file matching pattern exists.

Solution

@Configuration
@ConditionalOnResource(resources = "classpath*:config/*.xml")
public class XmlBasedConfiguration {
    
    @Bean
    public XmlConfigLoader xmlConfigLoader(ResourceLoader loader) throws IOException {
        Resource[] resources = loader.getResources("classpath*:config/*.xml");
        return new XmlConfigLoader(resources);
    }
}

Edge Case 10: Conditional on Cloud Platform

Problem

Different configuration for each cloud provider.

Solution

@Configuration
public class CloudConfiguration {
    
    @Bean
    @ConditionalOnCloudPlatform(CloudPlatform.KUBERNETES)
    public ServiceDiscovery k8sServiceDiscovery() {
        return new KubernetesServiceDiscovery();
    }
    
    @Bean
    @ConditionalOnCloudPlatform(CloudPlatform.CLOUD_FOUNDRY)
    public ServiceDiscovery cfServiceDiscovery() {
        return new CloudFoundryServiceDiscovery();
    }
    
    @Bean
    @ConditionalOnCloudPlatform(CloudPlatform.NONE)
    public ServiceDiscovery localServiceDiscovery() {
        return new LocalServiceDiscovery();
    }
}

Edge Case 11: Version-Specific Configuration

Problem

Different configuration for different Java versions.

Solution

@Configuration
public class JavaVersionConfiguration {
    
    @Bean
    @ConditionalOnJava(JavaVersion.TWENTY_ONE)
    public Executor virtualThreadExecutor() {
        return Executors.newVirtualThreadPerTaskExecutor();
    }
    
    @Bean
    @ConditionalOnJava(
        value = JavaVersion.TWENTY_ONE,
        range = Range.OLDER_THAN
    )
    public Executor platformThreadExecutor() {
        return Executors.newFixedThreadPool(10);
    }
}

Edge Case 12: Conditional on War Deployment

Problem

Different configuration for WAR vs embedded server.

Solution

@Configuration
public class DeploymentConfiguration {
    
    @Bean
    @ConditionalOnWarDeployment
    public ServletContextInitializer warInitializer() {
        return servletContext -> {
            // WAR-specific initialization
        };
    }
    
    @Bean
    @ConditionalOnNotWarDeployment
    public WebServerFactoryCustomizer<TomcatServletWebServerFactory>
            embeddedCustomizer() {
        return factory -> {
            // Embedded server customization
        };
    }
}

Edge Case 13: Conditional on Threading Model

Problem

Configure based on virtual vs platform threads.

Solution

@Configuration
public class ThreadingConfiguration {
    
    @Bean
    @ConditionalOnThreading(Threading.VIRTUAL)
    public TaskExecutor virtualThreadTaskExecutor() {
        return new VirtualThreadTaskExecutor();
    }
    
    @Bean
    @ConditionalOnThreading(Threading.PLATFORM)
    public TaskExecutor platformThreadTaskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.initialize();
        return executor;
    }
}

Edge Case 14: Conditional on Filter Bean

Problem

Register filter only if another filter doesn't exist.

Solution

@Configuration
public class FilterConfiguration {
    
    @Bean
    @ConditionalOnMissingFilterBean(CorsFilter.class)
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        FilterRegistrationBean<CorsFilter> bean = 
            new FilterRegistrationBean<>();
        bean.setFilter(new CorsFilter());
        bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return bean;
    }
}

Edge Case 15: Conditional on Single Candidate

Problem

Require exactly one bean (or one primary).

Solution

@Configuration
public class SingleDataSourceConfiguration {
    
    @Bean
    @ConditionalOnSingleCandidate(DataSource.class)
    public DataSourceHealthIndicator healthIndicator(DataSource dataSource) {
        return new DataSourceHealthIndicator(dataSource);
    }
}

Troubleshooting Edge Cases

Debug Condition Evaluation

debug=true
logging.level.org.springframework.boot.autoconfigure=DEBUG

Access Condition Report

@Component
public class ConditionReportPrinter implements ApplicationListener<ContextRefreshedEvent> {
    @Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
        ConditionEvaluationReport report = ConditionEvaluationReport.get(
            event.getApplicationContext().getBeanFactory()
        );
        
        report.getConditionAndOutcomesBySource().forEach((source, outcomes) -> {
            System.out.println(source + ": " + outcomes.isFullMatch());
        });
    }
}

Best Practices for Edge Cases

  1. Test Edge Cases: Write tests for all conditional paths
  2. Document Behavior: Explain complex conditions
  3. Fail Fast: Validate configuration early
  4. Use Specific Conditions: Avoid @ConditionalOnExpression
  5. Order Matters: Place fast conditions first
  6. Avoid Early Initialization: Don't reference beans in conditions

See Also

  • Common Patterns
  • Conditions Reference
  • Custom Auto-Configurations

Install with Tessl CLI

npx tessl i tessl/maven-org-springframework-boot--spring-boot-autoconfigure

docs

examples

common-patterns.md

edge-cases.md

real-world-scenarios.md

index.md

tile.json