ComponentReflectionInjector.java 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. package eu.kanade.mangafeed;
  2. import java.lang.reflect.Method;
  3. import java.util.HashMap;
  4. import java.util.concurrent.ConcurrentHashMap;
  5. /**
  6. * This class allows to inject into objects through a base class,
  7. * so we don't have to repeat injection code everywhere.
  8. *
  9. * The performance drawback is about 0.013 ms per injection on a very slow device,
  10. * which is negligible in most cases.
  11. *
  12. * Example:
  13. * <pre>{@code
  14. * Component {
  15. * void inject(B b);
  16. * }
  17. *
  18. * class A {
  19. * void onCreate() {
  20. * componentReflectionInjector.inject(this);
  21. * }
  22. * }
  23. *
  24. * class B extends A {
  25. * @Inject MyDependency dependency;
  26. * }
  27. *
  28. * new B().onCreate() // dependency will be injected at this point
  29. *
  30. * class C extends B {
  31. *
  32. * }
  33. *
  34. * new C().onCreate() // dependency will be injected at this point as well
  35. * }</pre>
  36. *
  37. * @param <T> a type of dagger 2 component.
  38. */
  39. public final class ComponentReflectionInjector<T> {
  40. private final Class<T> componentClass;
  41. private final T component;
  42. private final HashMap<Class<?>, Method> methods;
  43. public ComponentReflectionInjector(Class<T> componentClass, T component) {
  44. this.componentClass = componentClass;
  45. this.component = component;
  46. this.methods = getMethods(componentClass);
  47. }
  48. public T getComponent() {
  49. return component;
  50. }
  51. public void inject(Object target) {
  52. Class targetClass = target.getClass();
  53. Method method = methods.get(targetClass);
  54. while (method == null && targetClass != null) {
  55. targetClass = targetClass.getSuperclass();
  56. method = methods.get(targetClass);
  57. }
  58. if (method == null)
  59. throw new RuntimeException(String.format("No %s injecting method exists in %s component", target.getClass(), componentClass));
  60. try {
  61. method.invoke(component, target);
  62. }
  63. catch (Exception e) {
  64. throw new RuntimeException(e);
  65. }
  66. }
  67. private static final ConcurrentHashMap<Class<?>, HashMap<Class<?>, Method>> cache = new ConcurrentHashMap<>();
  68. private static HashMap<Class<?>, Method> getMethods(Class componentClass) {
  69. HashMap<Class<?>, Method> methods = cache.get(componentClass);
  70. if (methods == null) {
  71. synchronized (cache) {
  72. methods = cache.get(componentClass);
  73. if (methods == null) {
  74. methods = new HashMap<>();
  75. for (Method method : componentClass.getMethods()) {
  76. Class<?>[] params = method.getParameterTypes();
  77. if (params.length == 1)
  78. methods.put(params[0], method);
  79. }
  80. cache.put(componentClass, methods);
  81. }
  82. }
  83. }
  84. return methods;
  85. }
  86. }