diff --git a/compiler/src/main/java/dagger/internal/codegen/InjectAdapterProcessor.java b/compiler/src/main/java/dagger/internal/codegen/InjectAdapterProcessor.java index 1c61996d2d0..30b2b68b23e 100644 --- a/compiler/src/main/java/dagger/internal/codegen/InjectAdapterProcessor.java +++ b/compiler/src/main/java/dagger/internal/codegen/InjectAdapterProcessor.java @@ -15,6 +15,9 @@ */ package dagger.internal.codegen; +import static dagger.internal.loaders.GeneratedAdapters.INJECT_ADAPTER_SUFFIX; +import static dagger.internal.loaders.GeneratedAdapters.STATIC_INJECTION_SUFFIX; + import com.squareup.java.JavaWriter; import dagger.MembersInjector; import dagger.internal.Binding; @@ -54,8 +57,6 @@ import static dagger.internal.codegen.TypeUtils.isCallableConstructor; import static dagger.internal.codegen.TypeUtils.rawTypeToString; import static dagger.internal.codegen.TypeUtils.typeToString; -import static dagger.internal.loaders.generated.GeneratedAdapterLoader.INJECT_ADAPTER_SUFFIX; -import static dagger.internal.loaders.generated.GeneratedAdapterLoader.STATIC_INJECTION_SUFFIX; import static java.lang.reflect.Modifier.FINAL; import static java.lang.reflect.Modifier.PRIVATE; import static java.lang.reflect.Modifier.PUBLIC; diff --git a/compiler/src/main/java/dagger/internal/codegen/ModuleAdapterProcessor.java b/compiler/src/main/java/dagger/internal/codegen/ModuleAdapterProcessor.java index bafbe5f4e8c..66e18c49356 100644 --- a/compiler/src/main/java/dagger/internal/codegen/ModuleAdapterProcessor.java +++ b/compiler/src/main/java/dagger/internal/codegen/ModuleAdapterProcessor.java @@ -58,10 +58,9 @@ import static dagger.internal.codegen.TypeUtils.isCallableConstructor; import static dagger.internal.codegen.TypeUtils.isInterface; import static dagger.internal.codegen.TypeUtils.typeToString; -import static dagger.internal.loaders.generated.GeneratedAdapterLoader.MODULE_ADAPTER_SUFFIX; +import static dagger.internal.loaders.GeneratedAdapters.MODULE_ADAPTER_SUFFIX; import static java.lang.reflect.Modifier.FINAL; import static java.lang.reflect.Modifier.PRIVATE; -import static java.lang.reflect.Modifier.PROTECTED; import static java.lang.reflect.Modifier.PUBLIC; import static java.lang.reflect.Modifier.STATIC; @@ -296,7 +295,7 @@ private void writeModuleAdapter(TypeElement type, Map module, if (noArgsConstructor != null && isCallableConstructor(noArgsConstructor)) { writer.emitEmptyLine(); writer.emitAnnotation(Override.class); - writer.beginMethod(typeName, "newModule", PROTECTED); + writer.beginMethod(typeName, "newModule", PUBLIC); writer.emitStatement("return new %s()", typeName); writer.endMethod(); } diff --git a/core/src/main/java/dagger/ObjectGraph.java b/core/src/main/java/dagger/ObjectGraph.java index 1f0d8ddf98e..3e56f2e774a 100644 --- a/core/src/main/java/dagger/ObjectGraph.java +++ b/core/src/main/java/dagger/ObjectGraph.java @@ -16,22 +16,22 @@ */ package dagger; +import dagger.internal.FailoverLoader; + import dagger.internal.Binding; import dagger.internal.Keys; import dagger.internal.Linker; import dagger.internal.Loader; import dagger.internal.ModuleAdapter; import dagger.internal.ProblemDetector; -import dagger.internal.RuntimeAggregatingLoader; import dagger.internal.StaticInjection; import dagger.internal.ThrowingErrorHandler; import dagger.internal.UniqueMap; -import dagger.internal.loaders.generated.GeneratedAdapterLoader; -import dagger.internal.loaders.reflect.ReflectiveLoader; import java.util.LinkedHashMap; import java.util.Map; -import static dagger.internal.RuntimeAggregatingLoader.getAllModuleAdapters; +import static dagger.internal.Modules.getAllModuleAdapters; + /** * A graph of objects linked by their dependencies. @@ -124,13 +124,10 @@ public abstract class ObjectGraph { * the graph at runtime. */ public static ObjectGraph create(Object... modules) { - RuntimeAggregatingLoader plugin = new RuntimeAggregatingLoader( - new GeneratedAdapterLoader(), new ReflectiveLoader()); - return DaggerObjectGraph.makeGraph(null, plugin, modules); + return DaggerObjectGraph.makeGraph(null, new FailoverLoader(), modules); } static class DaggerObjectGraph extends ObjectGraph { - private final DaggerObjectGraph base; private final Linker linker; private final Map, StaticInjection> staticInjections; diff --git a/core/src/main/java/dagger/internal/FailoverLoader.java b/core/src/main/java/dagger/internal/FailoverLoader.java new file mode 100644 index 00000000000..c8c16a55569 --- /dev/null +++ b/core/src/main/java/dagger/internal/FailoverLoader.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2013 Square, Inc. + * Copyright (C) 2013 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dagger.internal; + + +import dagger.internal.loaders.GeneratedAdapters; +import dagger.internal.loaders.ReflectiveAtInjectBinding; +import dagger.internal.loaders.ReflectiveModuleAdapter; +import dagger.internal.loaders.ReflectiveStaticInjection; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * Handles loading/finding of modules, injection bindings, and static injections by use of a + * strategy of "load the appropriate generaged code" or, if no such code is found, create a + * reflective equivalent. + */ +public final class FailoverLoader implements Loader { + private static final Logger logger = Logger.getLogger(Loader.class.getName()); + + /** + * Obtains a module adapter for {@code module} from the first responding resolver. + */ + @Override public ModuleAdapter getModuleAdapter(Class type, T instance) { + try { + ModuleAdapter result = GeneratedAdapters.initModuleAdapter(type); + if (result == null) { + result = ReflectiveModuleAdapter.createAdaptor(type); + } + result.module = (instance == null) ? result.newModule() : instance; + return result; + } catch (RuntimeException e) { + logNotFound("Module adapter", type.getName(), e); + throw e; + } + } + + @Override public Binding getAtInjectBinding(String key, String className, + ClassLoader classLoader, boolean mustHaveInjections) { + try { + Binding result = GeneratedAdapters.initInjectAdapter(className, classLoader); + if (result == null) { + // A null classloader is the system classloader. + classLoader = (classLoader != null) ? classLoader : ClassLoader.getSystemClassLoader(); + Class c = classLoader.loadClass(className); + if (!c.isInterface()) { + result = ReflectiveAtInjectBinding.create(c, mustHaveInjections); + } + } + return result; + } catch (ClassNotFoundException e) { + throw new RuntimeException("Could not find " + className + " needed for binding " + key, e); + } catch (RuntimeException e) { + logNotFound("Binding", className, e); + throw e; + } + } + + @Override public StaticInjection getStaticInjection(Class injectedClass) { + try { + StaticInjection result = GeneratedAdapters.initStaticInjection(injectedClass); + if (result == null) { + result = ReflectiveStaticInjection.create(injectedClass); + } + return result; + } catch (RuntimeException e) { + logNotFound("Static injection", injectedClass.getName(), e); + throw e; + } + } + + private void logNotFound(String type, String name, RuntimeException e) { + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, String.format("Could not initialize a %s for %s.", type, name), e); + } + } +} diff --git a/core/src/main/java/dagger/internal/Loader.java b/core/src/main/java/dagger/internal/Loader.java index beb7fdee237..c2016a5e106 100644 --- a/core/src/main/java/dagger/internal/Loader.java +++ b/core/src/main/java/dagger/internal/Loader.java @@ -23,7 +23,8 @@ */ public interface Loader { /** - * Returns a binding that uses {@code @Inject} annotations. + * Returns a binding that uses {@code @Inject} annotations, or null if no valid binding can + * be found or created. */ Binding getAtInjectBinding( String key, String className, ClassLoader classLoader, boolean mustHaveInjections); diff --git a/core/src/main/java/dagger/internal/RuntimeAggregatingLoader.java b/core/src/main/java/dagger/internal/Modules.java similarity index 52% rename from core/src/main/java/dagger/internal/RuntimeAggregatingLoader.java rename to core/src/main/java/dagger/internal/Modules.java index e2fba3a70da..ef994cd315c 100644 --- a/core/src/main/java/dagger/internal/RuntimeAggregatingLoader.java +++ b/core/src/main/java/dagger/internal/Modules.java @@ -16,28 +16,16 @@ */ package dagger.internal; -import dagger.ObjectGraph; + import java.util.LinkedHashMap; import java.util.Map; -import java.util.logging.Level; -import java.util.logging.Logger; /** - * Aggregates provided plugins and delegates its operations to them in order. Also provides some - * specific runtime facilities needed by the runtime. + * Static helper for organizing modules. */ -public final class RuntimeAggregatingLoader implements Loader { - private static final Logger logger = Logger.getLogger(ObjectGraph.class.getName()); +public final class Modules { - /** A list of {@code Linker.Plugin}s which will be consulted in-order to resolve requests. */ - private final Loader[] plugins; - - public RuntimeAggregatingLoader(Loader ... plugins) { - if (plugins == null || plugins.length == 0) { - throw new IllegalArgumentException("Must provide at least one plugin."); - } - this.plugins = plugins; - } + private Modules() { } /** * Returns a full set of module adapters, including module adapters for included @@ -89,51 +77,4 @@ private static void collectIncludedModulesRecursively(Loader plugin, ModuleAdapt } } - /** - * Obtains a module adapter for {@code module} from the first responding resolver. - */ - @Override public ModuleAdapter getModuleAdapter(Class moduleClass, T module) { - for (int i = 0; i < plugins.length; i++) { - try { - ModuleAdapter result = plugins[i].getModuleAdapter(moduleClass, module); - result.module = (module != null) ? module : result.newModule(); - return result; - } catch (RuntimeException e) { - if (i == plugins.length - 1) throw e; - logNotFound("Module adapter", moduleClass.getName(), e); - } - } - throw new AssertionError(); - } - - @Override public Binding getAtInjectBinding(String key, String className, - ClassLoader classLoader, boolean mustHaveInjections) { - for (int i = 0; i < plugins.length; i++) { - try { - return plugins[i].getAtInjectBinding(key, className, classLoader, mustHaveInjections); - } catch (RuntimeException e) { - if (i == plugins.length - 1) throw e; - logNotFound("Binding", className, e); - } - } - throw new AssertionError(); - } - - @Override public StaticInjection getStaticInjection(Class injectedClass) { - for (int i = 0; i < plugins.length; i++) { - try { - return plugins[i].getStaticInjection(injectedClass); - } catch (RuntimeException e) { - if (i == plugins.length - 1) throw e; - logNotFound("Static injection", injectedClass.getName(), e); - } - } - throw new AssertionError(); - } - - private void logNotFound(String type, String name, RuntimeException e) { - if (logger.isLoggable(Level.FINE)) { - logger.log(Level.FINE, String.format("%s for %s not found.", type, name), e); - } - } } diff --git a/core/src/main/java/dagger/internal/loaders/GeneratedAdapters.java b/core/src/main/java/dagger/internal/loaders/GeneratedAdapters.java new file mode 100644 index 00000000000..2682da0f6fa --- /dev/null +++ b/core/src/main/java/dagger/internal/loaders/GeneratedAdapters.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2013 Square, Inc. + * Copyright (C) 2013 Google, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package dagger.internal.loaders; + +import dagger.internal.Binding; +import dagger.internal.ModuleAdapter; +import dagger.internal.StaticInjection; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A utility for loading and initializing generated adapters. + */ +public final class GeneratedAdapters { + private static final String SEPARATOR = "$$"; + public static final String INJECT_ADAPTER_SUFFIX = SEPARATOR + "InjectAdapter"; + public static final String MODULE_ADAPTER_SUFFIX = SEPARATOR + "ModuleAdapter"; + public static final String STATIC_INJECTION_SUFFIX = SEPARATOR + "StaticInjection"; + private static final Logger logger = Logger.getLogger(GeneratedAdapters.class.getName()); + + private GeneratedAdapters() { } + + public static ModuleAdapter initModuleAdapter(Class moduleClass) { + return instantiate(moduleClass.getName() + MODULE_ADAPTER_SUFFIX, moduleClass.getClassLoader()); + } + + public static Binding initInjectAdapter(String className, ClassLoader classLoader) { + return instantiate(className + INJECT_ADAPTER_SUFFIX, classLoader); + } + + public static StaticInjection initStaticInjection(Class injectedClass) { + return instantiate(injectedClass.getName() + STATIC_INJECTION_SUFFIX, + injectedClass.getClassLoader()); + } + + private static T instantiate(String name, ClassLoader classLoader) { + try { + // A null classloader is the system classloader. + classLoader = (classLoader != null) ? classLoader : ClassLoader.getSystemClassLoader(); + Class generatedClass = classLoader.loadClass(name); + Constructor constructor = generatedClass.getDeclaredConstructor(); + constructor.setAccessible(true); + return (T) constructor.newInstance(); + } catch (ClassNotFoundException e) { + if (logger.isLoggable(Level.FINE)) { + logger.log(Level.FINE, name + " could not be found.", e); + } + return null; // Not finding a class is not inherently an error, unlike finding a bad class. + } catch (NoSuchMethodException e) { + throw new RuntimeException("No default constructor found on " + name, e); + } catch (InstantiationException e) { + throw new RuntimeException("Failed to initialize " + name, e); + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to initialize " + name, e); + } catch (InvocationTargetException e) { + throw new RuntimeException("Error while initializing " + name, e.getCause()); + } + } +} diff --git a/core/src/main/java/dagger/internal/loaders/reflect/ReflectiveAtInjectBinding.java b/core/src/main/java/dagger/internal/loaders/ReflectiveAtInjectBinding.java similarity index 98% rename from core/src/main/java/dagger/internal/loaders/reflect/ReflectiveAtInjectBinding.java rename to core/src/main/java/dagger/internal/loaders/ReflectiveAtInjectBinding.java index 1f74c381343..ed84a89a2ce 100644 --- a/core/src/main/java/dagger/internal/loaders/reflect/ReflectiveAtInjectBinding.java +++ b/core/src/main/java/dagger/internal/loaders/ReflectiveAtInjectBinding.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dagger.internal.loaders.reflect; +package dagger.internal.loaders; import dagger.internal.Binding; import dagger.internal.Keys; @@ -35,7 +35,7 @@ * Injects the {@code @Inject}-annotated fields and constructors of a class * using reflection. */ -final class ReflectiveAtInjectBinding extends Binding { +public final class ReflectiveAtInjectBinding extends Binding { private final Field[] fields; private final ClassLoader loader; private final Constructor constructor; diff --git a/core/src/main/java/dagger/internal/loaders/reflect/ReflectiveModuleAdapter.java b/core/src/main/java/dagger/internal/loaders/ReflectiveModuleAdapter.java similarity index 87% rename from core/src/main/java/dagger/internal/loaders/reflect/ReflectiveModuleAdapter.java rename to core/src/main/java/dagger/internal/loaders/ReflectiveModuleAdapter.java index 3fce06837d5..1ed3ee9f284 100644 --- a/core/src/main/java/dagger/internal/loaders/reflect/ReflectiveModuleAdapter.java +++ b/core/src/main/java/dagger/internal/loaders/ReflectiveModuleAdapter.java @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dagger.internal.loaders.reflect; +package dagger.internal.loaders; import dagger.Lazy; import dagger.Module; @@ -34,7 +34,7 @@ import javax.inject.Provider; import javax.inject.Singleton; -final class ReflectiveModuleAdapter extends ModuleAdapter { +public final class ReflectiveModuleAdapter extends ModuleAdapter { final Class moduleClass; public ReflectiveModuleAdapter(Class moduleClass, Module annotation) { @@ -60,7 +60,7 @@ private static String[] injectableTypesToKeys(Class[] injectableTypes) { } @Override public void getBindings(Map> bindings) { - for (Class c = moduleClass; c != Object.class; c = c.getSuperclass()) { + for (Class c = moduleClass; !c.equals(Object.class); c = c.getSuperclass()) { for (Method method : c.getDeclaredMethods()) { Provides provides = method.getAnnotation(Provides.class); if (provides != null) { @@ -111,7 +111,7 @@ private void handleSetBindings(Map> bindings, Method meth library)); } - @Override protected Object newModule() { + @Override public Object newModule() { try { Constructor constructor = moduleClass.getDeclaredConstructor(); constructor.setAccessible(true); @@ -129,6 +129,22 @@ private void handleSetBindings(Map> bindings, Method meth } } + /** + * Creates a ReflectiveModuleAdapter or throws an {@code IllegalArgumentException}. + */ + @SuppressWarnings("unchecked") // Runtime checks validate that the result type matches 'T'. + public static ModuleAdapter createAdaptor(Class moduleClass) { + Module annotation = moduleClass.getAnnotation(Module.class); + if (annotation == null) { + throw new IllegalArgumentException("No @Module on " + moduleClass.getName()); + } + if (!moduleClass.getSuperclass().equals(Object.class)) { + throw new IllegalArgumentException( + "Modules must not extend from other classes: " + moduleClass.getName()); + } + return (ModuleAdapter) new ReflectiveModuleAdapter(moduleClass, annotation); + } + /** * Invokes a method to provide a value. The method's parameters are injected. */ diff --git a/core/src/main/java/dagger/internal/loaders/reflect/ReflectiveStaticInjection.java b/core/src/main/java/dagger/internal/loaders/ReflectiveStaticInjection.java similarity index 63% rename from core/src/main/java/dagger/internal/loaders/reflect/ReflectiveStaticInjection.java rename to core/src/main/java/dagger/internal/loaders/ReflectiveStaticInjection.java index df3deb0c555..1150eed5d5e 100644 --- a/core/src/main/java/dagger/internal/loaders/reflect/ReflectiveStaticInjection.java +++ b/core/src/main/java/dagger/internal/loaders/ReflectiveStaticInjection.java @@ -13,23 +13,27 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package dagger.internal.loaders.reflect; +package dagger.internal.loaders; import dagger.internal.Binding; import dagger.internal.Keys; import dagger.internal.Linker; import dagger.internal.StaticInjection; import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import javax.inject.Inject; /** * Uses reflection to inject the static fields of a class. */ -final class ReflectiveStaticInjection extends StaticInjection { +public final class ReflectiveStaticInjection extends StaticInjection { private final ClassLoader loader; private final Field[] fields; private Binding[] bindings; - public ReflectiveStaticInjection(ClassLoader loader, Field[] fields) { + private ReflectiveStaticInjection(ClassLoader loader, Field[] fields) { this.fields = fields; this.loader = loader; } @@ -52,4 +56,19 @@ public ReflectiveStaticInjection(ClassLoader loader, Field[] fields) { throw new AssertionError(e); } } + + public static StaticInjection create(Class injectedClass) { + List fields = new ArrayList(); + for (Field field : injectedClass.getDeclaredFields()) { + if (Modifier.isStatic(field.getModifiers()) && field.isAnnotationPresent(Inject.class)) { + field.setAccessible(true); + fields.add(field); + } + } + if (fields.isEmpty()) { + throw new IllegalArgumentException("No static injections: " + injectedClass.getName()); + } + return new ReflectiveStaticInjection(injectedClass.getClassLoader(), + fields.toArray(new Field[fields.size()])); + } } \ No newline at end of file diff --git a/core/src/main/java/dagger/internal/loaders/generated/GeneratedAdapterLoader.java b/core/src/main/java/dagger/internal/loaders/generated/GeneratedAdapterLoader.java deleted file mode 100644 index a5eafbc8708..00000000000 --- a/core/src/main/java/dagger/internal/loaders/generated/GeneratedAdapterLoader.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright (C) 2012 Square, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dagger.internal.loaders.generated; - -import dagger.internal.Binding; -import dagger.internal.Loader; -import dagger.internal.ModuleAdapter; -import dagger.internal.StaticInjection; -import java.lang.reflect.Constructor; - -/** - * A runtime {@link Loader} that loads generated classes. - */ -public final class GeneratedAdapterLoader implements Loader { - public static final String INJECT_ADAPTER_SUFFIX = "$$InjectAdapter"; - public static final String MODULE_ADAPTER_SUFFIX = "$$ModuleAdapter"; - public static final String STATIC_INJECTION_SUFFIX = "$$StaticInjection"; - - @Override public ModuleAdapter getModuleAdapter(Class moduleClass, T module) { - return instantiate(moduleClass.getName(), MODULE_ADAPTER_SUFFIX, moduleClass.getClassLoader()); - } - - @Override public Binding getAtInjectBinding( - String key, String className, ClassLoader classLoader, boolean mustHaveInjections) { - return instantiate(className, INJECT_ADAPTER_SUFFIX, classLoader); - } - - @Override public StaticInjection getStaticInjection(Class injectedClass) { - return instantiate(injectedClass.getName(), STATIC_INJECTION_SUFFIX, - injectedClass.getClassLoader()); - } - - @SuppressWarnings("unchecked") // We use a naming convention to defend against mismatches. - private T instantiate(String className, String suffix, ClassLoader classLoader) { - String name = className + suffix; - try { - // A null classloader is the system classloader. - classLoader = (classLoader != null) ? classLoader : ClassLoader.getSystemClassLoader(); - Class generatedClass = classLoader.loadClass(name); - Constructor constructor = generatedClass.getConstructor(); - constructor.setAccessible(true); - return (T) constructor.newInstance(); - } catch (Exception e) { - throw new RuntimeException("Unexpected failure loading " + name, e); - } - } -} diff --git a/core/src/main/java/dagger/internal/loaders/reflect/ReflectiveLoader.java b/core/src/main/java/dagger/internal/loaders/reflect/ReflectiveLoader.java deleted file mode 100644 index 2a11ef3d3a8..00000000000 --- a/core/src/main/java/dagger/internal/loaders/reflect/ReflectiveLoader.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (C) 2012 Square, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package dagger.internal.loaders.reflect; - -import dagger.Module; -import dagger.internal.Binding; -import dagger.internal.Loader; -import dagger.internal.ModuleAdapter; -import dagger.internal.StaticInjection; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; -import java.util.List; -import javax.inject.Inject; - -/** - * Uses reflection to create bindings, module adapters and static injections. - */ -public final class ReflectiveLoader implements Loader { - @Override public Binding getAtInjectBinding( - String key, String className, ClassLoader classLoader, boolean mustHaveInjections) { - Class c; - try { - // A null classloader is the system classloader. - classLoader = (classLoader != null) ? classLoader : ClassLoader.getSystemClassLoader(); - c = classLoader.loadClass(className); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e); - } - - if (c.isInterface()) { - return null; - } - - return ReflectiveAtInjectBinding.create(c, mustHaveInjections); - } - - @SuppressWarnings("unchecked") // Runtime checks validate that the result type matches 'T'. - @Override public ModuleAdapter getModuleAdapter(Class moduleClass, T module) { - Module annotation = moduleClass.getAnnotation(Module.class); - if (annotation == null) { - throw new IllegalArgumentException("No @Module on " + moduleClass.getName()); - } - if (moduleClass.getSuperclass() != Object.class) { - throw new IllegalArgumentException( - "Modules must not extend from other classes: " + moduleClass.getName()); - } - return (ModuleAdapter) new ReflectiveModuleAdapter(moduleClass, annotation); - } - - @Override public StaticInjection getStaticInjection(Class injectedClass) { - List fields = new ArrayList(); - for (Field field : injectedClass.getDeclaredFields()) { - if (Modifier.isStatic(field.getModifiers()) && field.isAnnotationPresent(Inject.class)) { - field.setAccessible(true); - fields.add(field); - } - } - if (fields.isEmpty()) { - throw new IllegalArgumentException("No static injections: " + injectedClass.getName()); - } - return new ReflectiveStaticInjection(injectedClass.getClassLoader(), - fields.toArray(new Field[fields.size()])); - } -} \ No newline at end of file