Last active
September 8, 2020 21:36
-
-
Save konmik/6ac725fa7134402539c4 to your computer and use it in GitHub Desktop.
Dagger 2 injection with inheritance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* 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; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
You need to tell proguard to keep the Dagger2 Components: