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

I finally ported Guice AsssitedInject to Spring (or maybe any jakarta.inject container if you're lucky)

https://gitlab.com/wholesail-oss/assisted-inject

Check it out and let me know if it helps you :)


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.


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).