Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consistent autowiring behavior for specifically typed injection points against loosely typed @Bean methods [SPR-14960] #19527

Closed
spring-issuemaster opened this issue Nov 29, 2016 · 2 comments

Comments

@spring-issuemaster
Copy link
Collaborator

commented Nov 29, 2016

satish surabhi opened SPR-14960 and commented

I want to report somewhat similar issue reported here: #15673 , now we are noticing autowire failing intermittently at least on the versions I have tried : 3.2.14 and 4.1.7.RELEASE. Following are the test classes with unit test. The test fails with NoSuchBeanDefinitionException for at least 2 (random) out of 5 attempts.

public interface BarInterface {}

public class Bar implements BarInterface {}

public class Foo {
 @Autowired
 public Bar bar;
}

@Configuration
public class FooBarConfiguration {
    @Bean
    public Foo foo() {
        return new Foo();
    }
    @Bean
    public BarInterface bar() {
        return new Bar();
    }
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {FooBarConfiguration.class}, loader=AnnotationConfigContextLoader.class)
public class TestSpringConfiguration {

    @Test
    public void testSpringConfiguration() {
        System.out.println("config test");
    }
}

Reference URL: #15673

Issue Links:

  • #15673 Unable to autowire concrete classes when java config methods return interface
  • #19073 Non-helpful NoSuchBeanDefinitionException rather than BeanNotOfRequiredTypeException due to creation order
  • #19074 Deterministic and JVM-independent @Bean registration order within Class-reflected configuration classes

Referenced from: commits 845dbf0, 66aeeed

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Nov 29, 2016

Juergen Hoeller commented

This is essentially a consequence of #19074: Depending on the particular runtime method order within a configuration class, a different bean may get initialized first... leading to different exceptions - or in your case, even to a different resolution outcome.

The root of all evil: The JVM does retain source declaration order in runtime reflection. As a consequence, Class.getDeclaredMethods() returns the methods in arbitrary order... even differening per JVM run, which is why you're seeing a random outcome for repeated runs.

To make things even more complicated, the bytecode in the class files does retain source declaration order. So if you're loading configuration class files through ASM, e.g. during classpath scanning, you will get a reliable initialization order... but not when you specify the .class directly like in your @ContextConfiguration, since we're using reflection there.

In your particular case, according to source declaration order, we'd initialize the foo bean first. The Bar injection point in that Foo class is not resolvable against the predicted types (return type declarations) of your bean definitions, so we unfortunately fail with a {NoSuchBeanDefinitionException}}. However, if we start initialization with the bar bean, we create it first and therefore know its specific instance type already... initializing foo next, resolving the Bar injection point against the known Bar instance type.

We generally try to provide predictable resolution behavior independent from the bean declaration order (see e.g. #19073). Let's see what we can do for your scenario, finding out about potential matches with loosely typed @Bean methods (which could match once their instance type is known) before failing with a NoSuchBeanDefinitionException.

Of course, the recommended solution is to declare Bar as return type of your bar method. We generally recommend to be as specific as you can there, and in particular as specific as your injection points need it to be.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

commented Dec 23, 2016

Juergen Hoeller commented

From my perspective, this is addressed along with #19074, with source-code declaration order consistently respected at runtime. We still can't predict @Bean implementation types before they're actually created, but at least we consistently succeed or consistently fail now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
2 participants
You can’t perform that action at this time.