1717package org .springframework .boot .autoconfigure .diagnostics .analyzer ;
1818
1919import java .lang .annotation .Annotation ;
20+ import java .lang .reflect .Constructor ;
2021import java .util .ArrayList ;
2122import java .util .Arrays ;
2223import java .util .Collections ;
3031import org .springframework .beans .factory .BeanFactory ;
3132import org .springframework .beans .factory .BeanFactoryAware ;
3233import org .springframework .beans .factory .BeanFactoryUtils ;
34+ import org .springframework .beans .factory .InjectionPoint ;
3335import org .springframework .beans .factory .NoSuchBeanDefinitionException ;
3436import org .springframework .beans .factory .UnsatisfiedDependencyException ;
3537import org .springframework .beans .factory .annotation .AnnotatedBeanDefinition ;
3941import org .springframework .boot .autoconfigure .condition .ConditionEvaluationReport .ConditionAndOutcome ;
4042import org .springframework .boot .autoconfigure .condition .ConditionEvaluationReport .ConditionAndOutcomes ;
4143import org .springframework .boot .autoconfigure .condition .ConditionOutcome ;
44+ import org .springframework .boot .context .properties .ConfigurationProperties ;
45+ import org .springframework .boot .context .properties .ConstructorBinding ;
4246import org .springframework .boot .diagnostics .FailureAnalysis ;
4347import org .springframework .boot .diagnostics .analyzer .AbstractInjectionFailureAnalyzer ;
4448import org .springframework .context .annotation .Bean ;
4549import org .springframework .core .ResolvableType ;
50+ import org .springframework .core .annotation .MergedAnnotation ;
51+ import org .springframework .core .annotation .MergedAnnotations ;
4652import org .springframework .core .type .MethodMetadata ;
4753import org .springframework .core .type .classreading .CachingMetadataReaderFactory ;
4854import org .springframework .core .type .classreading .MetadataReader ;
@@ -85,11 +91,14 @@ protected FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionExc
8591 StringBuilder message = new StringBuilder ();
8692 message .append (String .format ("%s required %s that could not be found.%n" ,
8793 (description != null ) ? description : "A component" , getBeanDescription (cause )));
88- List <Annotation > injectionAnnotations = findInjectionAnnotations (rootFailure );
89- if (!injectionAnnotations .isEmpty ()) {
90- message .append (String .format ("%nThe injection point has the following annotations:%n" ));
91- for (Annotation injectionAnnotation : injectionAnnotations ) {
92- message .append (String .format ("\t - %s%n" , injectionAnnotation ));
94+ InjectionPoint injectionPoint = findInjectionPoint (rootFailure );
95+ if (injectionPoint != null ) {
96+ Annotation [] injectionAnnotations = injectionPoint .getAnnotations ();
97+ if (injectionAnnotations .length > 0 ) {
98+ message .append (String .format ("%nThe injection point has the following annotations:%n" ));
99+ for (Annotation injectionAnnotation : injectionAnnotations ) {
100+ message .append (String .format ("\t - %s%n" , injectionAnnotation ));
101+ }
93102 }
94103 }
95104 if (!autoConfigurationResults .isEmpty () || !userConfigurationResults .isEmpty ()) {
@@ -105,6 +114,18 @@ protected FailureAnalysis analyze(Throwable rootFailure, NoSuchBeanDefinitionExc
105114 (!autoConfigurationResults .isEmpty () || !userConfigurationResults .isEmpty ())
106115 ? "revisiting the entries above or defining" : "defining" ,
107116 getBeanDescription (cause ));
117+ if (injectionPoint != null && injectionPoint .getMember () instanceof Constructor ) {
118+ Constructor <?> constructor = (Constructor <?>) injectionPoint .getMember ();
119+ Class <?> declaringClass = constructor .getDeclaringClass ();
120+ MergedAnnotation <ConfigurationProperties > configurationProperties = MergedAnnotations .from (declaringClass )
121+ .get (ConfigurationProperties .class );
122+ if (configurationProperties .isPresent ()) {
123+ action = String .format (
124+ "%s%nConsider adding @%s to %s if you intended to use constructor-based "
125+ + "configuration property binding." ,
126+ action , ConstructorBinding .class .getSimpleName (), constructor .getName ());
127+ }
128+ }
108129 return new FailureAnalysis (message .toString (), action , cause );
109130 }
110131
@@ -182,13 +203,13 @@ private void collectExcludedAutoConfiguration(NoSuchBeanDefinitionException caus
182203 }
183204 }
184205
185- private List < Annotation > findInjectionAnnotations (Throwable failure ) {
206+ private InjectionPoint findInjectionPoint (Throwable failure ) {
186207 UnsatisfiedDependencyException unsatisfiedDependencyException = findCause (failure ,
187208 UnsatisfiedDependencyException .class );
188209 if (unsatisfiedDependencyException == null ) {
189- return Collections . emptyList () ;
210+ return null ;
190211 }
191- return Arrays . asList ( unsatisfiedDependencyException .getInjectionPoint (). getAnnotations () );
212+ return unsatisfiedDependencyException .getInjectionPoint ();
192213 }
193214
194215 private class Source {
0 commit comments