Reputation: 775
I have a server that I've been developing. It uses Guice for it DI. There is a team library that I need to use. It uses @Autowired for its DI.
My code
import team.requiredlibrary.NeededClass
public class MyClass extends NeededClass {
@Inject
public MyClass() {
}
}
Imported library
public class NeededClass {
@Autowired
private NestedClass1 nestedClass1;
@Autowired
private NestedClass2 nestedClass2;
}
When this runs, nestedClass1 and nestedClass2 are null.
What are my options here. Is there a way to get Guice to recognize @Autowired? If it was an option to update the team library replacing @Autowired with @Inject, would the work be that simple and be worth the effort? Assuming the worst case, would I be stuck replacing Guice with Spring in my project for DI?
Upvotes: 2
Views: 1195
Reputation: 366
Spring supports @Inject
, so if it is possible to replace @Autowired
by @Inject
in your team library everything should be fine.
Otherwise you can create a custom injector for guice, see this link: https://github.com/google/guice/wiki/CustomInjections
You can create a custom injector for @Autowired
and use the method getProvider(Class)
of type TypeEncounter
of your TypeListener
to get a provider that you can use to retrieve the required type.
Of course you have to configure Guice correctly to be able to inject those types.
The issue with this approach: You maybe will not cover everything that Spring supports, e. g. @Qualifier
annotations.
Here is a working example:
public class AutowiredTypeListener implements TypeListener {
public <I> void hear(TypeLiteral<I> typeLiteral, TypeEncounter<I> typeEncounter) {
Class<?> clazz = typeLiteral.getRawType();
while (clazz != null) {
for (Field field : clazz.getDeclaredFields()) {
Autowired annotation = field.getAnnotation(Autowired.class);
if (annotation != null) {
typeEncounter.register(new AutowiredMembersInjector<I>(field,
typeEncounter.getProvider(field.getType())));
}
}
clazz = clazz.getSuperclass();
}
}
}
public class AutowiredMembersInjector<T> implements MembersInjector<T> {
private final Field field;
private final Provider<?> instanceProvider;
public AutowiredMembersInjector(Field field, Provider<?> instanceProvider) {
this.field = field;
this.instanceProvider = instanceProvider;
field.setAccessible(true);
}
public void injectMembers(T t) {
try {
field.set(t, instanceProvider.get());
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
And then just add bindListener(Matchers.any(), new AutowiredTypeListener());
inside your Guice module.
What I directly noticed is that @Autowired
supports optional injections, this seems to be impossible, because as soon as a provider was created using the typeEncounter
it is required to have a binding of the class registered.
Upvotes: 3