How can I help without help?

Suppose I have a third party class as follows:

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

Now suppose I have a factory interface, for example:

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

The idea is that I want to have a MyObjectFactory that builds MyObject for a fixed Foo - that is, essentially adding a @Assisted annotation to 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 that I have instances of Guice build MyObject - for example, method hooks. This seems to work for an “injector injection":

 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); } } 

It sounds wicked and boiler-tiled-y, so I'm wondering if there are alternative implementations and / or a way to get Guice to generate a factory impl.

+6
source share
2 answers

First of all, rarely do you want to pass instances of MyObject in your class precisely for the reasons you describe. You have no control over them, so you cannot add @Assisted annotations, you cannot add method hooks, etc. Etc. Also, what happens when you want to swap a third-party library for another implementation?

Therefore, you must wrap MyObject in 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 links to MyObject throughout your code using the naming convention described above, there should only be links to MyWrapperInterface .

+1
source

in fact it is. Take a look at Assisted Inject

Enable

  <dependency> <groupId>com.google.inject.extensions</groupId> <artifactId>guice-assistedinject</artifactId> <version>${guice.version}</version> </dependency> 

Update injection with

 public class MyInjectedObject extends MyObject implements MyIntf { @Inject public MyObject(Foo foo, @Assisted Bar bar) { super(foo,bar); } } 

You need to add another interface:

 public interface MyIntf {} 

In your module, associate a common factory with your interface

  install(new FactoryModuleBuilder() .implement(MyIntf.class, MyInjectedObject.class) .build(MyObjectFactory.class) ); 

Now you can paste MyObjectFactory anywhere.

 MyObject obj = myObjectFactory.build(bar); 
-1
source

Source: https://habr.com/ru/post/989780/


All Articles