mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Improve diagnostics when using @ConstructorBinding
on a Kotlin class
Closes gh-19312
This commit is contained in:
parent
02965e9744
commit
437941cc51
@ -836,6 +836,16 @@
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<!-- Test -->
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-reflect</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-jdk8</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-test-support</artifactId>
|
||||
@ -993,6 +1003,29 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>test-compile</id>
|
||||
<phase>test-compile</phase>
|
||||
<goals>
|
||||
<goal>test-compile</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<sourceDirs>
|
||||
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
|
||||
<sourceDir>${project.basedir}/src/test/java</sourceDir>
|
||||
</sourceDirs>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>java9+</id>
|
||||
|
@ -46,6 +46,7 @@ import org.springframework.boot.context.properties.ConstructorBinding;
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis;
|
||||
import org.springframework.boot.diagnostics.analyzer.AbstractInjectionFailureAnalyzer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.core.KotlinDetector;
|
||||
import org.springframework.core.ResolvableType;
|
||||
import org.springframework.core.annotation.MergedAnnotation;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
@ -120,10 +121,19 @@ class NoSuchBeanDefinitionFailureAnalyzer extends AbstractInjectionFailureAnalyz
|
||||
MergedAnnotation<ConfigurationProperties> configurationProperties = MergedAnnotations.from(declaringClass)
|
||||
.get(ConfigurationProperties.class);
|
||||
if (configurationProperties.isPresent()) {
|
||||
action = String.format(
|
||||
"%s%nConsider adding @%s to %s if you intended to use constructor-based "
|
||||
+ "configuration property binding.",
|
||||
action, ConstructorBinding.class.getSimpleName(), constructor.getName());
|
||||
if (KotlinDetector.isKotlinType(declaringClass) && !KotlinDetector.isKotlinReflectPresent()) {
|
||||
action = String.format(
|
||||
"%s%nConsider adding a dependency on kotlin-reflect so that the contructor used for @%s can be located. Also, ensure that @%s is present on '%s' if you intended to use constructor-based "
|
||||
+ "configuration property binding.",
|
||||
action, ConstructorBinding.class.getSimpleName(), ConstructorBinding.class.getSimpleName(),
|
||||
constructor.getName());
|
||||
}
|
||||
else {
|
||||
action = String.format(
|
||||
"%s%nConsider adding @%s to %s if you intended to use constructor-based "
|
||||
+ "configuration property binding.",
|
||||
action, ConstructorBinding.class.getSimpleName(), constructor.getName());
|
||||
}
|
||||
}
|
||||
}
|
||||
return new FailureAnalysis(message.toString(), action, cause);
|
||||
|
@ -0,0 +1,67 @@
|
||||
package org.springframework.boot.autoconfigure.diagnostics.analyzer
|
||||
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.beans.FatalBeanException
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties
|
||||
import org.springframework.boot.context.properties.ConstructorBinding
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties
|
||||
import org.springframework.boot.diagnostics.FailureAnalysis
|
||||
import org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter
|
||||
import org.springframework.boot.test.util.TestPropertyValues
|
||||
import org.springframework.boot.testsupport.classpath.ClassPathExclusions
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext
|
||||
import org.springframework.context.annotation.Configuration
|
||||
|
||||
/**
|
||||
* Tests for {@link ConfigurationProperties @ConfigurationProperties}-annotated beans when kotlin-reflect is not present
|
||||
* on the classpath.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@ClassPathExclusions("kotlin-reflect*.jar")
|
||||
class KotlinNoSuchBeanFailureAnalyzerNoKotlinReflectTests {
|
||||
|
||||
private val analyzer = NoSuchBeanDefinitionFailureAnalyzer()
|
||||
|
||||
@Test
|
||||
fun failureAnalysisForConfigurationPropertiesThatMaybeShouldHaveBeenConstructorBound() {
|
||||
val analysis = analyzeFailure(
|
||||
createFailure(ConstructorBoundConfigurationPropertiesConfiguration::class.java))
|
||||
assertThat(analysis!!.getAction()).startsWith(
|
||||
java.lang.String.format("Consider defining a bean of type '%s' in your configuration.", String::class.java!!.getName()))
|
||||
assertThat(analysis!!.getAction()).contains(java.lang.String.format(
|
||||
"Consider adding a dependency on kotlin-reflect so that the contructor used for @ConstructorBinding can be located. Also, ensure that @ConstructorBinding is present on '%s' ", ConstructorBoundProperties::class.java!!.getName()))
|
||||
}
|
||||
|
||||
private fun createFailure(config: Class<*>, vararg environment: String): FatalBeanException? {
|
||||
try {
|
||||
AnnotationConfigApplicationContext().use { context ->
|
||||
this.analyzer.setBeanFactory(context.beanFactory)
|
||||
TestPropertyValues.of(*environment).applyTo(context)
|
||||
context.register(config)
|
||||
context.refresh()
|
||||
return null
|
||||
}
|
||||
} catch (ex: FatalBeanException) {
|
||||
return ex
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun analyzeFailure(failure: Exception?): FailureAnalysis? {
|
||||
val analysis = this.analyzer.analyze(failure)
|
||||
if (analysis != null) {
|
||||
LoggingFailureAnalysisReporter().report(analysis)
|
||||
}
|
||||
return analysis
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(ConstructorBoundProperties::class)
|
||||
internal class ConstructorBoundConfigurationPropertiesConfiguration
|
||||
|
||||
@ConfigurationProperties("test")
|
||||
@ConstructorBinding
|
||||
internal class ConstructorBoundProperties(val name: String)
|
||||
}
|
Loading…
Reference in New Issue
Block a user