package com.airbnb.epoxy; import android.support.annotation.Nullable; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.LinkedHashMap; import java.util.Map; /** * Looks up a generated {@link ControllerHelper} implementation for a given adapter. * If the adapter has no {@link com.airbnb.epoxy.AutoModel} models then a No-Op implementation will * be returned. */ class ControllerHelperLookup { private static final String GENERATED_HELPER_CLASS_SUFFIX = "_EpoxyHelper"; private static final Map<Class<?>, Constructor<?>> BINDINGS = new LinkedHashMap<>(); private static final NoOpControllerHelper NO_OP_CONTROLLER_HELPER = new NoOpControllerHelper(); static ControllerHelper getHelperForController(EpoxyController controller) { Constructor<?> constructor = findConstructorForClass(controller.getClass()); if (constructor == null) { return NO_OP_CONTROLLER_HELPER; } try { return (ControllerHelper) constructor.newInstance(controller); } catch (IllegalAccessException e) { throw new RuntimeException("Unable to invoke " + constructor, e); } catch (InstantiationException e) { throw new RuntimeException("Unable to invoke " + constructor, e); } catch (InvocationTargetException e) { Throwable cause = e.getCause(); if (cause instanceof RuntimeException) { throw (RuntimeException) cause; } if (cause instanceof Error) { throw (Error) cause; } throw new RuntimeException("Unable to get Epoxy helper class.", cause); } } @Nullable private static Constructor<?> findConstructorForClass(Class<?> controllerClass) { Constructor<?> helperCtor = BINDINGS.get(controllerClass); if (helperCtor != null || BINDINGS.containsKey(controllerClass)) { return helperCtor; } String clsName = controllerClass.getName(); if (clsName.startsWith("android.") || clsName.startsWith("java.")) { return null; } try { Class<?> bindingClass = Class.forName(clsName + GENERATED_HELPER_CLASS_SUFFIX); //noinspection unchecked helperCtor = bindingClass.getConstructor(controllerClass); } catch (ClassNotFoundException e) { helperCtor = findConstructorForClass(controllerClass.getSuperclass()); } catch (NoSuchMethodException e) { throw new RuntimeException("Unable to find Epoxy Helper constructor for " + clsName, e); } BINDINGS.put(controllerClass, helperCtor); return helperCtor; } }