Skip to content

Commit

Permalink
Rework the default loader into a cleaner, more explicit FallbackLoade…
Browse files Browse the repository at this point in the history
…r, and turn the previously chained loaders into ingredients that could be used in this or other loaders.
  • Loading branch information
cgruber committed Jun 12, 2013
1 parent 156bb39 commit bb488da
Show file tree
Hide file tree
Showing 12 changed files with 229 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
97 changes: 97 additions & 0 deletions core/src/main/java/dagger/internal/FailoverLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*
* Copyright (C) 2012 Square, Inc.
* Copyright (C) 2012 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;

/**
* Aggregates provided plugins and delegates its operations to them in order. Also provides some
* specific runtime facilities needed by the runtime.
*/
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) {
return result;
}

// Fall back on reflection.
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);
} catch (RuntimeException e) {
logNotFound("Binding", className, e);
throw e;
}
}

@Override public StaticInjection getStaticInjection(Class<?> injectedClass) {
try {
StaticInjection result = GeneratedAdapters.initStaticInjection(injectedClass);
if (result != null) {
return result;
}
return ReflectiveStaticInjection.create(injectedClass);
} 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);
}
}
}
2 changes: 1 addition & 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,7 @@
*/
public interface Loader {
/**
* Returns a binding that uses {@code @Inject} annotations.
* Returns a binding that uses {@code @Inject} annotations, or null if no such binding can beNo.
*/
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,14 @@
*/
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());

/** 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;
}
public final class Modules {

/**
* Returns a full set of module adapters, including module adapters for included
Expand Down Expand Up @@ -89,51 +75,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) 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;

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 {
public 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 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 (ClassNotFoundException e) {
if (logger.isLoggable(Level.FINE)) {
logger.log(Level.FINE, className + " 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 valid constructor found on " + className, e);
} catch (InstantiationException e) {
throw new RuntimeException("Failed to initialize " + className, e);
} catch (IllegalAccessException e) {
throw new RuntimeException("Failed to initialize " + className, e);
} catch (InvocationTargetException e) {
throw new RuntimeException("Error while initializing " + className, 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 bb488da

Please sign in to comment.