Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
Dagger 2 injection with inheritance
/**
* This class allows to inject into objects through a base class,
* so we don't have to repeat injection code everywhere.
*
* The performance drawback is about 0.013 ms per injection on a very slow device,
* which is negligible in most cases.
*
* Example:
* <pre>{@code
* Component {
* void inject(B b);
* }
*
* class A {
* void onCreate() {
* componentReflectionInjector.inject(this);
* }
* }
*
* class B extends A {
* @Inject MyDependency dependency;
* }
*
* new B().onCreate() // dependency will be injected at this point
*
* class C extends B {
*
* }
*
* new C().onCreate() // dependency will be injected at this point as well
* }</pre>
*
* @param <T> a type of dagger 2 component.
*/
public final class ComponentReflectionInjector<T> implements Injector {
private final Class<T> componentClass;
private final T component;
private final HashMap<Class<?>, Method> methods;
public ComponentReflectionInjector(Class<T> componentClass, T component) {
this.componentClass = componentClass;
this.component = component;
this.methods = getMethods(componentClass);
}
public T getComponent() {
return component;
}
@Override
public void inject(Object target) {
Class targetClass = target.getClass();
Method method = methods.get(targetClass);
while (method == null && targetClass != null) {
targetClass = targetClass.getSuperclass();
method = methods.get(targetClass);
}
if (method == null)
throw new RuntimeException(String.format("No %s injecting method exists in %s component", target.getClass(), componentClass));
try {
method.invoke(component, target);
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
private static final ConcurrentHashMap<Class<?>, HashMap<Class<?>, Method>> cache = new ConcurrentHashMap<>();
private static HashMap<Class<?>, Method> getMethods(Class componentClass) {
HashMap<Class<?>, Method> methods = cache.get(componentClass);
if (methods == null) {
synchronized (cache) {
methods = cache.get(componentClass);
if (methods == null) {
methods = new HashMap<>();
for (Method method : componentClass.getMethods()) {
Class<?>[] params = method.getParameterTypes();
if (params.length == 1)
methods.put(params[0], method);
}
cache.put(componentClass, methods);
}
}
}
return methods;
}
}

And you will lost most valuable benefit of dagger 2 - proguard without headache.

Owner

konmik commented Aug 17, 2015

This is a proguard-friendly solution.

You are right, sorry

bejibx commented Apr 8, 2016

Can't get how to use it, do you have some examples?

esafirm commented Apr 21, 2016

Seems not working if Proguard is enabled, any idea?

nbsith commented Jun 10, 2016

I also encountered problem with Dagger 2 and don't know why. In my case it seems that inject(presenter) methods in component are not preserved as they are not called directly in code but only via reflection. I have dontoptimize setting enabled so Proguard should not strip them but it is.

sevar83 commented Jul 13, 2016

Does it have any ProGuard requirements? Seems elegant solution but I'm afraid of ProGuard.

You need to tell proguard to keep the Dagger2 Components:

-keep @interface dagger.Component
-keepclassmembers @dagger.Component class * { *; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment