Anyway to @Inject/@Autowire an inner class into an outer class?

It is possible to declare and instantiate inner class beans through @Component annotations, but solution is ugly, but I will get to it later. First, here’s how you can do it with <bean> declarations in XML. Given

package com.example;

public class Example {
    @Autowired
    private Inner inner;
    public class Inner {        
    }
}

you’d have

<bean name="ex" class="com.example.Example" />
<bean name="inner" class="com.example.Example$Inner">
    <constructor-arg ref="ex"></constructor-arg>
</bean>

For inner classes, any constructor implicitly declares its first parameter as an instance of the enclosing type.

So

public Inner() {}

above would actually be compiled to

public Inner (Example enclosingInstance) {}

With Java code, the argument for that parameter is implicitly provided with the syntax

enclosingInstance.new Inner();

Spring uses reflection to instantiate your bean classes and initialize your beans. And the concept described here also applies to reflection. The Constructor used to initialize the Inner class has to have its first parameter be of the type of the enclosing class. That’s what we are doing explicitly here by declaring a constructor-arg.

The solution for using @Component depends on a few things. First, you have to know all the things discussed above. Basically, with a Constructor object, when you call newInstance(), you need to pass an instance of the enclosing class as the first argument. Second, you have to know how Spring processes the annotation. When the annotated class has a single constructor annotated with @Autowired, that’s the constructor it will choose to initialize the bean. It also uses the ApplicationContext to resolve beans to inject as arguments to the constructor.

Playing on those two facts, you can write a class like this

@Component
public class Example {
    @Component
    public class Inner {
        @Autowired
        public Inner() {}

    }
}

Here, our inner class has an @Autowired constructor, so Spring knows exactly which Constructor object to use. Because of the @Autowired it will also try to find a bean from the ApplicationContext to match and inject for every parameter the constructor has. In this case, the only parameter is of type Example, the enclosing class. Since Example is also annotated with @Component, it’s also a bean in the context, so Spring can inject it into the constructor of the inner class.

Leave a Comment