Skip to content

Commit

Permalink
Merge pull request google#7 from cgruber/speeduploader
Browse files Browse the repository at this point in the history
Rework Loader to throw fewer exceptions in the normal course of business.
  • Loading branch information
cgruber committed Jun 13, 2013
2 parents 156bb39 + 437b0e1 commit 5a31bed
Show file tree
Hide file tree
Showing 12 changed files with 226 additions and 224 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
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
13 changes: 5 additions & 8 deletions core/src/main/java/dagger/ObjectGraph.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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<Class<?>, StaticInjection> staticInjections;
Expand Down
91 changes: 91 additions & 0 deletions core/src/main/java/dagger/internal/FailoverLoader.java
Original file line number Diff line number Diff line change
@@ -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 <T> ModuleAdapter<T> getModuleAdapter(Class<? extends T> type, T instance) {
try {
ModuleAdapter<T> 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);
}
}
}
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
Loading

0 comments on commit 5a31bed

Please sign in to comment.