How can I make a non-assisted dependency assisted? - java

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.

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.

actually it is. Have a look Assisted Inject
Include
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-assistedinject</artifactId>
<version>${guice.version}</version>
</dependency>
Update injection with assisted
public class MyInjectedObject extends MyObject implements MyIntf {
#Inject
public MyObject(Foo foo, #Assisted Bar bar) { super(foo,bar); }
}
You have to add one more interface:
public interface MyIntf {}
In your module bind generic factory to your interface
install(new FactoryModuleBuilder()
.implement(MyIntf.class, MyInjectedObject.class)
.build(MyObjectFactory.class)
);
Now you can inject MyObjectFactory anywhere you want.
MyObject obj = myObjectFactory.build(bar);

Related

How can I inject for generic inherited types?

I spent a plenty of time for finding any answers, but I think I have to ask.
I'm using Weld-SE for testing my entities.
I prepared entity randomizer for testing.
abstract class BaseEntityRandomizer<T extends BaseEntity>
implements Randomizer<T> {
#Override public T getRandomValue() {
...
}
}
class MySomeOtherEntityRandomizer
extends BaseEntityRandomizer<MySomeOther> {
#Override public MySomeOther getRandomValue() {
...
}
}
Now, with my test class, I want to inject those randomizers which each matches generic parameters
#ExtendWith(WeldJunit5Extension.class)
#AddPackages({BaseEntityRandomizer.class})
abstract class BaseEntityTest<T extends BaseEntity> {
#Test void doSome() {
}
#Inject
private BaseEntityRandomizer<T> entityRandomizer;
}
class MySomeOtherTest extends BaseEntityTest<MySomeOther> {
...
// I expect an instance of MySomeOtherRandomizer in injected
// into the entityRandomizer field.
}
Subclasses of randomizers and tests are prepared.
But I failed to make it work.
How can I make it work?
I tried with following factory class
class BaseEntityRandomizerFactory {
#Produces
public BaseEntityRandomizer<MySome> produceMySomeRandomizer() {
return new MySomeRandomizer();
}
}
I got
org.jboss.weld.exceptions.IllegalArgumentException:
WELD-001408: Unsatisfied dependencies for type BaseEntityRandomizer<T extends BaseEntity> with qualifiers #Default
at injection point [BackedAnnotatedField] #Inject protected transient ....BaseEntityTest.entityRandomizer
at ....BaseEntityTest.entityRandomizer(BaseEntityTest.java:0)
One way to achieve this is to use CDI Programmatic lookup. In your case, I'd start with #Inject Instance<Object> and then you can use subsequent calls to select() and get() methods to pick up whichever bean you desire. Usage looks something like this (assumes existence of beans with types Foo, Bar and List<String>):
#Inject
private Instance<Object> instance;
#Test void doSome() {
// selecting and obtaining instances of beans
Foo foo = entityRandomizer.select(Foo.class).get();
Bar bar = entityRandomizer.select(Bar.class).get();
// in case you need to select a parameterized type from instance, use TypeLiteral
List<String> listBean = entityRandomized..select( new TypeLiteral<List<String>>(){}).get()
}

Spring injected beans null in nested class

I have a class with 2 static nested classes that do the same operation on 2 different generic types.
I exposed the 2 classes as beans and added #Autowired for the constructors as I usually do.
Here is the basic setup
abstract class <T> Parent implements MyInterface<T> {
private final Service service;
Parent(Service service){ this.service = service; }
#Override public final void doInterfaceThing(T thing){
T correctedT = map(thing);
service.doTheThing(correctedT);
}
protected abstract T map(T t);
#Service
public static class ImplA extends Parent<A> {
#Autowired ImplA (Service service){ super(service); }
A map(A a){ //map a }
}
#Service
public static class ImplB extends Parent<B> {
#Autowired ImplB (Service service){ super(service); }
B map(B b){ //map b }
}
}
And in another class I have
#Service
public class Doer {
private final List<MyInterface<A>> aImpls;
#Autowired public Doer(List<MyInterface<A>> aImpls){ this.aImpls = aImpls; }
public void doImportantThingWithA(A a){
aImpls.get(0).doInterfaceThing(a);
}
}
When I run the app, everything appears to be injected correctly and when I put a breakpoint in the ImplA and ImplB constructors, I have a not-null value for "service". I also have an ImplA bean in the aImpls list in Doer.
When I call doImportantThingWithA(a) however, "service" is null inside ImplA and I obviously die.
I'm not sure how this is possible because:
I see a nonnull value in my constructors for service which is a final field.
If spring is injecting ImplA and ImplB into another class, it should already have either injected a Service into ImplA or ImplB, or thrown an exception on bean initialization. I have nothing set to lazily load and all bean dependencies are required.
The reason for the nested classes is because the only thing that changes between the 2 implementations is the map() function. Trying to avoid extra classes for 1 line of varying code.
More info:
When I add a breakpoint in Parent.doInterfaceThing(), if I add a watch on "service" I get null as the value. If I add a getService() method, and then call getService() instead of referring directly to this.service, I get the correct bean for service. I don't know the implications of this but something seems weird with the proxying.
It looks like what is causing the issue is Parent.doInterfaceThing();
If I remove final from the method signature, "service" field is correctly populated and the code works as expected.
I don't understand at all why changing a method signature affects the injected value of final fields in my class... but it works now.
What I meant with my "use mappers" comment was something like this:
class MyInterfaceImpl implements MyInterface {
#Autowired
private final Service service;
#Override public final <T> void doInterfaceThing(T thing, UnaryOperator<T> mapper){
T correctedT = mapper.apply(thing);
service.doTheThing(correctedT);
}
// new interface to allow autowiring despite type erasure
public interface MapperA extends UnaryOperator<A> {
public A map(A toMap);
default A apply(A a){ map(a); }
}
#Component
static class AMapper implements MapperA {
public A map(A a) { // ... }
}
public interface MapperB extends UnaryOperator<B> {
public B map(B toMap);
default B apply(B b){ map(b); }
}
#Component
static class BMapper implements MapperB {
public B map(B a) { // ... }
}
}
This does have a few more lines than the original, but not much; however, you do have a better Separation of Concern. I do wonder how autowiring works in your code with the generics, it does look as if that might cause problems.
Your client would look like this:
#Service
public class Doer {
private final List<MapperA> aMappers;
private final MyInterface myInterface;
#Autowired public Doer(MyInterface if, List<MapperA> mappers){
this.myInterface = if;
this.aImpls = mappers; }
public void doImportantThingWithA(A a){
aMappers.stream().map(m -> m.map(a)).forEach(myInterface::doInterfaceThing);
}
}

Dagger: Inject field on provided pojo

Currently testing with dagger, what I want to do is instantiate and inject different Bar implementations. How can I inject fields in provided fields?
for example:
Module:
#Module(
injects = {
Main.class
},
complete = false,
library = true
)
public class ExampleTestModule {
#Provides
public Foo providesFoo() {
return new Foo();
}
#Provides
public Bar providesBar(BarImpl impl) {
// return new BarImpl(); // null
return impl;
}
}
Main:
public class Main {
#Inject
Foo foo;
}
Foo:
public class Foo {
#Inject
Bar bar;
}
Bar:
public interface Bar {
}
BarImpl
public class BarImpl implements Bar {
}
TestCase:
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
public void testFoo() {
Main main = new Main();
ObjectGraph.create(new ExampleTestModule()).inject(main);
assertNotNull(main.foo);
}
public void testFooBar() {
Main main = new Main();
ObjectGraph.create(new ExampleTestModule()).inject(main);
assertNotNull(main.foo.bar);
}
}
Main.Foo is not null but Main.Foo.Bar is null.
You are never injecting bar into foo.
ObjectGraph.create(new ExampleTestModule()).inject(main);
This line will only look at the fields of main which are annotated by #Inject, and inject them. There is no recursive behavior.
Fixing the problem
Let's go step-by-step:
You provided complete = false and library = true in your Module. You should only use these if really necessary. Dagger will give you warnings when something is wrong, and these properties surpress these warnings. For example, removing them raises the following warning when compiling:
Error:(11, 8) error: No injectable members on BarImpl. Do you want to add an injectable constructor? required by providesBar(BarImpl) for ExampleTestModule.
Let's add an empty injectable constructor to BarImpl, as it suggests:
public class BarImpl implements Bar {
#Inject
BarImpl(){
}
}
Compiling will give a new error:
Error:(11, 8) error: Graph validation failed: You have these unused #Provider methods:
1. ExampleTestModule.providesBar()
Set library=true in your module to disable this check.
Apparently, providesBar() is never used. That means, the bar field in Foo will never be injected. You can do two things:
Inject bar manually:
ObjectGraph graph = ObjectGraph.create(new ExampleTestModule());
graph.inject(main);
graph.inject(main.foo);
Use injectable constructors (Preferred option):
public class Foo {
Bar bar;
#Inject
Foo(Bar bar){
this.bar = bar;
}
}
Using the injectable constructor, you will now have a compile error in providesFoo(), since you don't supply a Bar instance in the Foo constructor. The nice thing about Dagger is, you can safely completely remove this method. Since Foo is annotated with #Injectable, everywhere it needs to inject a Foo instance, it uses this constructor. And when it uses this constructor, it notices it needs a Bar instance, and injects this as well.
Finally, we can remove the #Inject annotation from the Foo field in Main, and create an injectable constructor. Using ObjectGraph.get(Class<?>) we can retrieve a fully instantiated Main instance.
The result
The end result should look like this:
Module:
#Module(
injects = Main.class
)
public class ExampleTestModule {
#Provides
public Bar providesBar(BarImpl impl) {
return impl;
}
}
Main:
public class Main {
Foo foo;
#Inject
Main(Foo foo) {
this.foo = foo;
}
}
Foo:
public class Foo {
Bar bar;
#Inject
Foo(Bar bar){
this.bar = bar;
}
}
Bar:
public interface Bar {
}
BarImpl:
public class BarImpl implements Bar {
#Inject
BarImpl(){
}
}
ApplicationTest:
public class ApplicationTest extends ApplicationTestCase<Application> {
public ApplicationTest() {
super(Application.class);
}
public void testFoo() {
Main main = ObjectGraph.create(new ExampleTestModule()).get(Main.class);
assertNotNull(main.foo);
}
public void testFooBar() {
Main main = ObjectGraph.create(new ExampleTestModule()).get(Main.class);
assertNotNull(main.foo.bar);
}
}
Conclusion
From the result, we can conclude some things:
Don't just add library = true and complete = false to your module. This should only be necessary when using multiple complex modules.
Try to use injectable constructors. This is what Dagger's built for, and works best. An extra perk is that you can now have your fields private, like they should be.
When using injectable constructors, you really only need to create providesXXX methods when injecting instances of interfaces, like we did with Bar and BarImpl. Because, hey, that's exactly what Dependency Injection is for, right?

Guice: Binding several objects with different dependencies

I have the following code using Guice bindings:
public class MyApplication {
public static void main(String[] args) {
Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(Foo.class).annotatedWith(Names.named("first")).toInstance(new Foo("firstFoo"));
bind(Foo.class).annotatedWith(Names.named("second")).toInstance(new Foo("secondFoo"));
bind(Bar.class).to(BarImpl.class);
bind(MyApplication.class).asEagerSingleton();
}
});
}
private #Named("first") Bar first;
private #Named("second") Bar second;
static #Value class Foo { String name; }
static interface Bar {}
static class BarImpl implements Bar {
#Inject #Named Foo foo;
}
}
I'm trying to get a Bar object for both named Foos injected in my application. Basically, it should somehow connect the #Named on Foo with the one on Bar. I have tried several solutions, from putting #Named on everything to writing a custom Provider. The latter didn't work because I don't have access to the value of the #Named annotation inside the provider. I think the solution is somewhere in the line bind(Bar.class).to(BarImpl.class);, telling it to remember the value of the #Named annotation.
My question is, is this possible at all, and if so, how?
It is using PrivateModules. Basically:
A private module's configuration information is hidden from its environment by default. Only bindings that are explicitly exposed will be available to other modules and to the users of the injector. For more explanation see this FAQ entry.
Here is how you'd use it:
protected void configure() {
install(new PrivateModule() {
#Override
protected void configure() {
// #bind makes bindings internal to this module unlike using AbstractModule
// this binding only applies to bindings inside this module
bind(Foo.class).toInstance(new Foo("first"));
// Bar's foo dependency will use the preceding binding
bind(Bar.class).annotatedWith(Names.named("first")).to(BarImpl.class);
// if we'd stop here, this would be useless
// but the key method here is #expose
// it makes a binding visible outside as if we did AbstractModule#bind
// but the binding that is exposed can use "private" bindings
// in addition to the inherited bindings
expose(Bar.class).annotatedWith(Names.named("first"));
}
});
install(new PrivateModule() {
#Override
protected void configure() {
bind(Foo.class).toInstance(new Foo("second"));
bind(Bar.class).annotatedWith(Names.named("second")).to(BarImpl.class);
expose(Bar.class).annotatedWith(Names.named("second"));
}
});
bind(MyApplication.class).asEagerSingleton();
}
}
Now you effectively have 2 Bars each of which look like
static class BarImpl implements Bar {
#Inject Foo foo;
}
but with the power of PrivateModules have a different implementation bound for the same dependency.
Hope it makes sense.

Guice wrap generic injections

Is it possible to wrap generic injections in some way?
Given the interface:
interface IFoo<T>
In my guice module:
bind((Key<IFoo<SomeType>) Key.get(Types.newParameterizedType(IFoo.class, SomeType.class))).to(Foo.class);
But before I return the Foo instance I want to wrap it with this:
class FooWrapper<T> implements IFoo<T> { public FooWrapper(Foo<T> foo) { ... } }
Somewhere like this:
return new FooWrapper<T>(foo);
Here's one way you can do this:
public class FooModule extends PrivateModule {
#Retention(RUNTIME) #BindingAnnotation
private #interface Internal {}
#Override protected void configure() {
bind(new TypeLiteral<IFoo<SomeType>>(){}).annotatedWith(Internal.class)
.to(new TypeLiteral<Foo<SomeType>>(){});
}
#Provides #Exposed IFoo<SomeType> provideFoo(#Internal IFoo<SomeType> foo) {
return new FooWrapper<SomeType>(foo);
}
}
Another thing that might work well would be to add a general annotation like #Wrapped and then to declare FooWrapper's constructor like this:
#Inject public FooWrapper(#Wrapped IFoo<T> foo) { ... }
Then in your private module you could bind Foo annotated with #Wrapped and bind and expose FooWrapper normally, without needing to use an #Provides method.
There may well be better ways of doing this I haven't thought of yet. Do also keep in mind that method interception is often a good way of decorating interface implementations with other behavior as well.

Categories