From be161b23cb58b05a103da421d79c87871ce787fc Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Mon, 31 Dec 2018 10:36:02 +0100 Subject: [PATCH] Polish class conditions documentation Closes gh-15578 --- .../condition/ConditionalOnClass.java | 8 +++- .../main/asciidoc/spring-boot-features.adoc | 41 ++++++++++++++++--- 2 files changed, 42 insertions(+), 7 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClass.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClass.java index a030852261..5fe1328d01 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClass.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/condition/ConditionalOnClass.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2017 the original author or authors. + * Copyright 2012-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,12 @@ import org.springframework.context.annotation.Conditional; /** * {@link Conditional} that only matches when the specified classes are on the classpath. + *

+ * A {@link #value()} can be safely specified on {@code @Configuration} classes as the + * annotation metadata is parsed by using ASM before the class is loaded. Extra care is + * required when placed on {@code @Bean} methods, consider isolating the condition in a + * separate {@code Configuration} class, in particular if the return type of the method + * matches the {@link #value target of the condition}. * * @author Phillip Webb */ diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 4fbe146f3b..b968e9a241 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -7606,12 +7606,41 @@ annotations include: [[boot-features-class-conditions]] ==== Class Conditions -The `@ConditionalOnClass` and `@ConditionalOnMissingClass` annotations let configuration -be included based on the presence or absence of specific classes. Due to the fact that -annotation metadata is parsed by using http://asm.ow2.org/[ASM], you can use the `value` -attribute to refer to the real class, even though that class might not actually appear on -the running application classpath. You can also use the `name` attribute if you prefer to -specify the class name by using a `String` value. +The `@ConditionalOnClass` and `@ConditionalOnMissingClass` annotations let +`@Configuration` classes be included based on the presence or absence of specific classes. +Due to the fact that annotation metadata is parsed by using http://asm.ow2.org/[ASM], you +can use the `value` attribute to refer to the real class, even though that class might not +actually appear on the running application classpath. You can also use the `name` +attribute if you prefer to specify the class name by using a `String` value. + +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. + +To handle this scenario, a separate `@Configuration` class can be used to isolate the +condition, as shown in the following example: + +[source,java,indent=0] +---- + @Configuration + // Some conditions + public class MyAutoConfiguration { + + // Auto-configured beans + + @Configuration + @ConditionalOnClass(EmbeddedAcmeService.class) + static class EmbeddedConfiguration { + + @Bean + @ConditionalOnMissingBean + public EmbeddedAcmeService embeddedAcmeService() { ... } + + } + + } +---- [TIP] ====