2

I have a problem with @Autowired inside bean. I've posted simplified code structure. I have two classes annotated with @Configuration and two simple beans. In class D autowired bean doesn't injected. So I wonder is it posible to solve the NPE without changing structure?

Class A:

@Configuration
public class A {

    @Autowired
    private B b;

    @Bean
    publict Other other() {
        b.doFoo();
        Other other = new Other();
    }

    @Bean
    public C c() {            
        return new C();
    }
}

Class B:

@Configuration
public class B {

    @Bean
    public D d() {
        return new D();
    }

    public void doFoo() {
        d().doBar();
    }
}

Class C inner structure of doesn't matter. So class D:

public class D {

    @Autowired
    C c;

    public void doBar() {
        c.doFooBar(); // And here we got NPE
    }
}

I's must be noticed, that if I move initialization of bean D from B to A and autowired it to B everything works fine:

@Configuration
public class A {

    @Autowired
    private B b;

    @Bean
    publict Other other() {
        b.doFoo();
        Other other = new Other()
    }

    @Bean
    public C c() {            
        return new C();
    }

    @Bean
    public D d() {
        return new D();
    }
}

@Configuration
public class B {

    @Autowired
    private D d;

    public void doFoo() {
        d.doBar();
    }
}

But this method doesn't suit.

  • When I try your sample (after I modified it to compile) it works for me. Can you update the sample code so that it compiles? For example, b.doFoo() is void, but A#other() expects it to return a value to be injected into Other. Perhaps there are some discrepancies in how I modified the code and what your code actually looks like that are causing your issue. – Rob Winch Jan 31 '13 at 14:59
  • thx, but partlov's answer is right and explains everything. But I've edited the code of A#other(). – Vitali Zarembouski Jan 31 '13 at 15:16
  • @RobWinch you probably have aspectj weaver configured in eclipse or you added it to class path, it wasn't used proxy mechanism but aspectj weaving. In my case it doesn't work ether. – partlov Jan 31 '13 at 15:19
  • No this is not the case...please see my response to your comment below – Rob Winch Jan 31 '13 at 15:41

2 Answers2

0

Class D should also be annotated with @Component or something similar. Only spring beans will be susceptible to autowiring.

K.C.
  • 2,084
  • 2
  • 25
  • 38
  • No, if I move bean initialization of class D from B to A - autowiring workd fine. – Vitali Zarembouski Jan 31 '13 at 14:27
  • @ambiorix But class `D` is Spring bean, it is just created with factory method. It makes no difference. Just it should be injected with spring, not manually created. – partlov Jan 31 '13 at 15:00
0

Let's analyze class B for second. In that class when you call doFoo() method you have executed d().doBar();, which is like you manually created instance of class D, without any Spring. You called d() method directly it is just like you putted new D().doBar(). If you want to D be created with spring add this in class B:

@Autowired
private D d;

and change your method doFoo() to:

d.doBar();

Key part in your question was:

and autowired it to B everything works fine

This is also an answer.

partlov
  • 13,789
  • 6
  • 63
  • 82
  • Exactly! Thank you very much) I undestand what the problem was, but so simple answer, like autowire bean to the initializing class, was not obvious to me) – Vitali Zarembouski Jan 31 '13 at 15:01
  • FYI This may have solved the issue, but I don't think it is the underlying problem. Spring creates proxies using CGLIB so that method calls to the @Configuration classes are handled by Spring. See an example of this type of usage in the reference (notice the call to accountRepository()) http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-java-combining-xml-centric-declare-as-bean – Rob Winch Jan 31 '13 at 15:05
  • Yes but in this situation proxy is not handled because you executed a method from the same class. If class B would be injected you will have its proxy, here you just used your code without proxy. Maybe if you used aspectj weaving. – partlov Jan 31 '13 at 15:07
  • Since Spring loads the `@Configuration` classes, it replaces the method calls with calls to the proxy (including for invocations to by subclassing the `@Configuration` with cglib). Another (perhaps more concrete explanation) can be found in the reference here http://static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/beans.html#beans-java-further-information-java-config In short, the ConfigurationClassPostProcessor ensures that method invocations are referring to the proxy – Rob Winch Jan 31 '13 at 15:40
  • Yes, I know what you are talking about. But spring can replace my real class with proxy just for classes which are injected (by spring), but not if I'm calling another method in my own class. See [this example](http://stackoverflow.com/questions/7338760/spring-aop-intercepting-calls-from-within-the-same-service-class) – partlov Feb 01 '13 at 07:45
  • It is really easy to test. Put break point, and see that in this case class of object is you real class, when you are call method from another class in which it is injected, type is of spring's proxy. Except when you are using aspectj weaving. – partlov Feb 01 '13 at 07:47
  • Part from spring documentation: "In proxy mode (which is the default), only external method calls coming in through the proxy are intercepted. This means that self-invocation, in effect, a method within the target object calling another method of the target object, will not lead to an actual transaction at runtime even if the invoked method is marked with @Transactional." This is for transactional aspects, but this is true for everything. – partlov Feb 01 '13 at 07:50