Skip to content

Commit

Permalink
Merge pull request google#279 from cgruber/speeduploader
Browse files Browse the repository at this point in the history
Rework the default loader into a cleaner, more explicit FallbackLoader
  • Loading branch information
cgruber committed Jun 14, 2013
2 parents a8c471f + dbfa84f commit b892765
Show file tree
Hide file tree
Showing 12 changed files with 202 additions and 224 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@
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 dagger.internal.loaders.GeneratedAdapters.INJECT_ADAPTER_SUFFIX;
import static dagger.internal.loaders.GeneratedAdapters.STATIC_INJECTION_SUFFIX;
import static java.lang.reflect.Modifier.FINAL;
import static java.lang.reflect.Modifier.PRIVATE;
import static java.lang.reflect.Modifier.PUBLIC;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -296,7 +295,7 @@ private void writeModuleAdapter(TypeElement type, Map<String, Object> 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();
}
Expand Down
12 changes: 4 additions & 8 deletions core/src/main/java/dagger/ObjectGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,20 @@
package dagger;

import dagger.internal.Binding;
import dagger.internal.FailoverLoader;
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.
Expand Down Expand Up @@ -124,13 +123,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<Class<?>, StaticInjection> staticInjections;
Expand Down
69 changes: 69 additions & 0 deletions core/src/main/java/dagger/internal/FailoverLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
/*
* 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;

/**
* Handles loading/finding of modules, injection bindings, and static injections by use of a
* strategy of "load the appropriate generated code" or, if no such code is found, create a
* reflective equivalent.
*/
public final class FailoverLoader implements Loader {

/**
* Obtains a module adapter for {@code module} from the first responding resolver.
*/
@Override public <T> ModuleAdapter<T> getModuleAdapter(Class<? extends T> type, T instance) {
ModuleAdapter<T> result = GeneratedAdapters.initModuleAdapter(type);
if (result == null) {
result = ReflectiveModuleAdapter.create(type);
}
result.module = (instance != null) ? instance : result.newModule();
return result;
}

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

@Override public StaticInjection getStaticInjection(Class<?> injectedClass) {
StaticInjection result = GeneratedAdapters.initStaticInjection(injectedClass);
if (result == null) {
result = ReflectiveStaticInjection.create(injectedClass);
}
return result;
}
}
3 changes: 2 additions & 1 deletion core/src/main/java/dagger/internal/Loader.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 <T> ModuleAdapter<T> getModuleAdapter(Class<? extends T> moduleClass, T module) {
for (int i = 0; i < plugins.length; i++) {
try {
ModuleAdapter<T> 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);
}
}
}
75 changes: 75 additions & 0 deletions core/src/main/java/dagger/internal/loaders/GeneratedAdapters.java
Original file line number Diff line number Diff line change
@@ -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 <T> ModuleAdapter<T> initModuleAdapter(Class<? extends T> 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> 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());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -35,7 +35,7 @@
* Injects the {@code @Inject}-annotated fields and constructors of a class
* using reflection.
*/
final class ReflectiveAtInjectBinding<T> extends Binding<T> {
public final class ReflectiveAtInjectBinding<T> extends Binding<T> {
private final Field[] fields;
private final ClassLoader loader;
private final Constructor<T> constructor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -34,7 +34,7 @@
import javax.inject.Provider;
import javax.inject.Singleton;

final class ReflectiveModuleAdapter extends ModuleAdapter<Object> {
public final class ReflectiveModuleAdapter extends ModuleAdapter<Object> {
final Class<?> moduleClass;

public ReflectiveModuleAdapter(Class<?> moduleClass, Module annotation) {
Expand All @@ -60,7 +60,7 @@ private static String[] injectableTypesToKeys(Class<?>[] injectableTypes) {
}

@Override public void getBindings(Map<String, Binding<?>> 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) {
Expand Down Expand Up @@ -111,7 +111,7 @@ private <T> void handleSetBindings(Map<String, Binding<?>> bindings, Method meth
library));
}

@Override protected Object newModule() {
@Override public Object newModule() {
try {
Constructor<?> constructor = moduleClass.getDeclaredConstructor();
constructor.setAccessible(true);
Expand All @@ -129,6 +129,22 @@ private <T> void handleSetBindings(Map<String, Binding<?>> bindings, Method meth
}
}

/**
* Creates a ReflectiveModuleAdapter or throws an {@code IllegalArgumentException}.
*/
@SuppressWarnings("unchecked") // Runtime checks validate that the result type matches 'T'.
public static <T> ModuleAdapter<T> create(Class<? extends T> 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<T>) new ReflectiveModuleAdapter(moduleClass, annotation);
}

/**
* Invokes a method to provide a value. The method's parameters are injected.
*/
Expand Down
Loading

0 comments on commit b892765

Please sign in to comment.