Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible and how to do Assisted Injection in Spring?

In Guice 2 or 3, exists so called Assisted/Partial Inject described here. With this, Guice synthesizes factory implementation (implementing my interface) for my object and some of the constructor arguments are injected by Guice, and some are provided from the context.

Is it possible and how to do the same thing with Spring?

like image 502
Op De Cirkel Avatar asked Jun 03 '11 02:06

Op De Cirkel


People also ask

When would you use assisted inject?

AssistedInject allows you to dynamically configure Factory for class instead of coding it by yourself. This is often useful when you have an object that has a dependencies that should be injected and some parameters that must be specified during creation of object.

Which type of injection is better in Spring?

We can combine constructor-based and setter-based types of injection for the same bean. The Spring documentation recommends using constructor-based injection for mandatory dependencies, and setter-based injection for optional ones.

How do you use Assist inject?

The assisted injection uses a factory to provide your assisted dependency, the steps are as follows: Annotate your dependency with @AssitedInject. Provide the dependencies that can be automatically wired by the DI library. Annotate your dynamically added dependencies with @Assisted and provide them with a name if ...


2 Answers

The following does exactly what i asked for. Though, it does not synthesize the implementation of the factory, it is good enough as the factory has access to the injection context so that can use other beans (injectable artifacts) during construction. It uses java based @Configuration instead of XML, but it will work with XML too.

The factory interface:

public interface Robot {

}

// Implementation of this is to be injected by the IoC in the Robot instances
public interface Brain {
    String think();
}

public class RobotImpl implements Robot {

    private final String name_;
    private final Brain brain_;

    @Inject
    public RobotImpl(String name, Brain brain) {
        name_ = name;
        brain_ = brain;
    }

    public String toString() {
        return "RobotImpl [name_=" + name_ + "] thinks about " + brain_.think();
    }
}

public class RobotBrain implements Brain {
    public String think() {
        return "an idea";
    }
}


// The assisted factory type
public interface RobotFactory {
    Robot newRobot(String name);
}

// this is the Spring configuration showing how to do the assisted injection

@Configuration
class RobotConfig {

    @Bean @Scope(SCOPE_PROTOTYPE)
    public RobotFactory robotFactory() {
        return new RobotFactory() {

            @Override
            public Robot newRobot(String name) {
                return new RobotImpl(name, r2dxBrain());
            }
        };
    }

    @Bean @Scope(SCOPE_PROTOTYPE)
    public Brain r2dxBrain() {
        return new RobotBrain();
    }
}

The test code:

public class RobotTest {

    @Test
    public void t1() throws Exception {
        ApplicationContext ctx = new 
                           AnnotationConfigApplicationContext(RobotConfig.class);
        RobotFactory rf = ctx.getBean(RobotFactory.class);
        assertThat(rf.newRobot("R2D2").toString(), 
           equalTo("RobotImpl [name_=R2D2] thins about an idea"));
    }

}

This achieves exactly what Guice does. The tricky difference is the Scope. Spring's default scope is Singleton and Guice's is not (it is prototype).

like image 197
Op De Cirkel Avatar answered Oct 20 '22 04:10

Op De Cirkel


AFAIK you can't. In Spring you can have Instantiation using a static factory method or Instantiation using an instance factory method. With the second option you can define a bean myFactoryBean working as a factory for another bean. You can also pass construction arguments to myFactoryBean by using constructor-arg (see for example the section Using An Instance Factory Method on this blog), which gives you the equivalent of Guice-injected arguments. However, I don't know of any way to provide further arguments from context when invoking the factory method.

like image 36
MarcoS Avatar answered Oct 20 '22 05:10

MarcoS