Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I make a non-assisted dependency assisted?

Suppose I have a third party class as follows:

public class MyObject {
    @Inject
    public MyObject(Foo foo, Bar bar) { ... }
}

Now suppose that I have a factory interface like so:

public interface MyObjectFactory {
    public MyObject build(Bar bar);
}

The idea is that I wish to have a MyObjectFactory that builds a MyObject for a fixed Foo - that is, essentially adding in the @Assisted annotation on the Bar constructor parameter from the outside. Of course, manually implementing MyObjectFactory is always possible:

public class MyObjectFactoryImpl implements MyObjectFactory {
    @Inject private Provider<Foo> foo;

    @Override
    public MyObject build(Bar bar) { return new MyObject(foo.get(), bar); }
}

But let's say that there are conditions that require me to have Guice build MyObject instances - for example, method interceptors. This seems like a job for "injecting the injector":

public class MyObjectFactoryImpl implements MyObjectFactory {
    @Inject private Injector injector;

    @Override
    public MyObject build(Bar bar) {
        Injector child = injector.createChildInjector(new AbstractModule() {
            @Override
            protected void configure() {
                bind(Bar.class).toInstance(bar);
                // Set up method interceptors for MyObject here...
            }
        });
        return child.getInstance(MyObject.class);
    }
}

This sounds evil and boiler-plate-y, so I'm wondering if there are any alternate implementations and/or a way to have Guice generate the factory impl.

like image 537
Kelvin Chung Avatar asked Jun 26 '15 03:06

Kelvin Chung


1 Answers

First of all, it is rare that you want to be passing instances of MyObject around in your class for exactly the reasons you describe. You have no control over them, so you can't add @Assisted annotations, you can't add method interceptors, etc. etc. Plus, what happens when you want to swap out the third party library for a different implementation?

Therefore, you should be wrapping MyObject into another object.

// **Please** choose better names than this in your real code.
public class MyWrapperBackedByMyObject implements MyWrapperInterface {
    private final MyObject delegate;

    @Inject
    MyWrapperObject(Foo foo, @Assisted Bar bar) {
        delegate = new MyObject(foo, bar);
    }

    @NotOnWeekends  // Example of how you might do method interception
    public void orderPizza() {
       delegate.orderPizza();
    }
}

Then, remove all references to MyObject throughout your code, using the naming convention I describe above, there should only be references to MyWrapperInterface.

like image 94
durron597 Avatar answered Nov 08 '22 08:11

durron597