Search code examples
javaaopguicefactory-pattern

How to supply parameters in Guice injections, while not breaking Guice-AOP method interception?


I have a situation where I need to use Guice 3.0 to instantiate my object but one of the values will change potentially with each instance. I cannot bind that value's type and I won't know until I need to create the instance.

For instance:

public class Foo {
    public Foo(Bar bar, Baz baz) {...}
}

I want Guice to inject the Bar param but I won't know Baz until I need Foo. The value isn't scope-specific (e.g. RequestScope) either.

The whole reason I want this object fully instantiated by Guice is because I need method interception. In Guice, "manually constructed instances do not participate in AOP".

I've tried to do this with Provider<Foo> but that only allows me public Foo get() { ... }.

It would be a configuration nightmare to have to create a provider for every possible value of Baz, so I can't simply have Baz be defined in FooProvider's constructor.

I feel like I'm missing something fundamental here. Perhaps it is because it is the last thing I'm doing on a Friday. Any ideas would be appreciated.

Edit: The answer below to use "assisted injection" seems to only work if you have the ability to edit the source of Foo. Foo may actually be outside of my control for some instances. And if I create the instances myself (i.e., implement my own factory) then Guice-AOP method interceptors don't seem to ever know about the object.


Solution

  • It looks like "assisted injection" might be a solution:

    http://google-guice.googlecode.com/svn/trunk/latest-javadoc/com/google/inject/assistedinject/FactoryModuleBuilder.html

    Except it doesn't work if you don't have access to annotate the constructor of Foo.

    EDIT: what I have found is that I am able to add the assisted injection annotations by extending the type and adding them to the constructor that I wish to use:

    public class AssistedFoo extends Foo {
        @AssistedInject
        public AssistedFoo(
            Bar bar,
            @Assisted Baz baz) {
            super(bar, baz);
        }
    }
    

    Then use this extended implementation in the assisted injection registration:

    public interface FooFactory {
        Foo create(Baz baz);
    }
    
    //...
    
    install(new FactoryModuleBuilder()
        .implement(Foo.class, AssistedFoo.class)
        .build(FooFactory.class));
    

    The extra inheritance class is only needed when you don't have access to change Foo. Obviously this workaround wouldn't work if the class is final.