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;
}
}
@IlyaEremin

This comment has been minimized.

Show comment Hide comment
@IlyaEremin

IlyaEremin Aug 9, 2015

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

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

@konmik

This comment has been minimized.

Show comment Hide comment
@konmik

konmik Aug 17, 2015

This is a proguard-friendly solution.

Owner

konmik commented Aug 17, 2015

This is a proguard-friendly solution.

@IlyaEremin

This comment has been minimized.

Show comment Hide comment
@IlyaEremin

IlyaEremin Mar 27, 2016

You are right, sorry

You are right, sorry

@bejibx

This comment has been minimized.

Show comment Hide comment
@bejibx

bejibx Apr 8, 2016

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

bejibx commented Apr 8, 2016

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

@esafirm

This comment has been minimized.

Show comment Hide comment
@esafirm

esafirm Apr 21, 2016

Seems not working if Proguard is enabled, any idea?

esafirm commented Apr 21, 2016

Seems not working if Proguard is enabled, any idea?

@nbsith

This comment has been minimized.

Show comment Hide comment
@nbsith

nbsith 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.

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

This comment has been minimized.

Show comment Hide comment
@sevar83

sevar83 Jul 13, 2016

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

sevar83 commented Jul 13, 2016

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

@sgc-code

This comment has been minimized.

Show comment Hide comment
@sgc-code

sgc-code Mar 21, 2017

You need to tell proguard to keep the Dagger2 Components:

-keep @interface dagger.Component
-keepclassmembers @dagger.Component class * { *; }

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