aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--build.properties2
-rw-r--r--build.xml13
-rw-r--r--core/src/com/google/inject/internal/ProviderMethodsModule.java12
-rw-r--r--core/src/com/google/inject/spi/Elements.java56
-rw-r--r--core/src/com/google/inject/spi/ModuleSource.java60
-rw-r--r--extensions/dagger-adapter/build.properties8
-rw-r--r--extensions/dagger-adapter/build.xml21
-rw-r--r--extensions/dagger-adapter/lib/dagger-2.0-20150205.014011-14.jarbin0 -> 16693 bytes
-rw-r--r--extensions/dagger-adapter/pom.xml28
-rw-r--r--extensions/dagger-adapter/src/com/google/inject/daggeradapter/DaggerAdapter.java90
-rw-r--r--extensions/dagger-adapter/src/com/google/inject/daggeradapter/DaggerMethodScanner.java75
-rw-r--r--extensions/dagger-adapter/test/com/google/inject/daggeradapter/DaggerAdapterTest.java99
-rw-r--r--extensions/pom.xml1
13 files changed, 406 insertions, 59 deletions
diff --git a/build.properties b/build.properties
index f1e04745..cca000c0 100644
--- a/build.properties
+++ b/build.properties
@@ -8,6 +8,7 @@ jmx.src.dir=extensions/jmx/src
jndi.src.dir=extensions/jndi/src
throwingproviders.src.dir=extensions/throwingproviders/src
multibindings.src.dir=extensions/multibindings/src
+daggeradapter.src.dir=extensions/dagger-adapter/src
privatemodules.src.dir=extensions/privatemodules/src
lifecycle.src.dir=extensions/lifecycle/src
persist.src.dir=extensions/persist/src
@@ -26,6 +27,7 @@ javadoc.packagenames=com.google.inject,com.google.inject.spi,\
com.google.inject.assistedinject,\
com.google.inject.throwingproviders,\
com.google.inject.multibindings,\
+ com.google.inject.daggeradapter,\
com.google.inject.privatemodules,\
com.google.inject.util,\
com.google.inject.persist,\
diff --git a/build.xml b/build.xml
index 1efac5f1..3d0c7722 100644
--- a/build.xml
+++ b/build.xml
@@ -10,9 +10,9 @@
</path>
<path id="javadoc.classpath">
- <path refid="compile.classpath"/>
+ <path refid="compile.classpath"/>
<fileset dir="extensions">
- <include name="*/lib/*.jar"/>
+ <include name="*/lib/*.jar"/>
</fileset>
<pathelement location="${build.dir}/classes"/>
</path>
@@ -35,6 +35,7 @@
<ant antfile="extensions/jndi/build.xml" target="distjars" inheritAll="false"/>
<ant antfile="extensions/throwingproviders/build.xml" target="distjars" inheritAll="false"/>
<ant antfile="extensions/multibindings/build.xml" target="distjars" inheritAll="false"/>
+ <ant antfile="extensions/dagger-adapter/build.xml" target="distjars" inheritAll="false"/>
<ant antfile="extensions/persist/build.xml" target="distjars" inheritAll="false"/>
<ant antfile="extensions/grapher/build.xml" target="distjars" inheritAll="false"/>
<ant antfile="extensions/testlib/build.xml" target="distjars" inheritAll="false"/>
@@ -64,6 +65,9 @@
<fileset dir="extensions/multibindings/build" includes="*.jar"/>
</copy>
<copy toDir="${build.dir}/dist">
+ <fileset dir="extensions/dagger-adapter/build" includes="*.jar"/>
+ </copy>
+ <copy toDir="${build.dir}/dist">
<fileset dir="extensions/persist/build" includes="*.jar"/>
</copy>
<copy toDir="${build.dir}/dist">
@@ -159,6 +163,7 @@
<fileset dir="${jndi.src.dir}"/>
<fileset dir="${throwingproviders.src.dir}"/>
<fileset dir="${multibindings.src.dir}"/>
+ <fileset dir="${daggeradapter.src.dir}"/>
<fileset dir="${persist.src.dir}"/>
<fileset dir="${struts2.src.dir}"/>
<fileset dir="${grapher.src.dir}"/>
@@ -214,6 +219,9 @@
<group title="Multibinder Extension" packages="com.google.inject.multibindings"/>
<fileset dir="${multibindings.src.dir}"/>
+ <group title="Dagger Adapter" packages="com.google.inject.daggeradapter"/>
+ <fileset dir="${daggeradapter.src.dir}"/>
+
<group title="ThrowingProviders Extension" packages="com.google.inject.throwingproviders"/>
<fileset dir="${throwingproviders.src.dir}"/>
@@ -302,6 +310,7 @@
<ant dir="extensions/jndi" antfile="build.xml" target="clean"/>
<ant dir="extensions/throwingproviders" antfile="build.xml" target="clean"/>
<ant dir="extensions/multibindings" antfile="build.xml" target="clean"/>
+ <ant dir="extensions/dagger-adapter" antfile="build.xml" target="clean"/>
<ant dir="extensions/persist" antfile="build.xml" target="clean"/>
<ant dir="extensions/grapher" antfile="build.xml" target="clean"/>
<ant dir="extensions/testlib" antfile="build.xml" target="clean"/>
diff --git a/core/src/com/google/inject/internal/ProviderMethodsModule.java b/core/src/com/google/inject/internal/ProviderMethodsModule.java
index 4ff3e9fd..3b68b5c5 100644
--- a/core/src/com/google/inject/internal/ProviderMethodsModule.java
+++ b/core/src/com/google/inject/internal/ProviderMethodsModule.java
@@ -29,10 +29,10 @@ import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Provides;
import com.google.inject.TypeLiteral;
-import com.google.inject.spi.ModuleAnnotatedMethodScanner;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.Message;
+import com.google.inject.spi.ModuleAnnotatedMethodScanner;
import com.google.inject.util.Modules;
import java.lang.annotation.Annotation;
@@ -55,8 +55,8 @@ public final class ProviderMethodsModule implements Module {
private static ModuleAnnotatedMethodScanner PROVIDES_BUILDER =
new ModuleAnnotatedMethodScanner() {
@Override
- public <T> Key<T> prepareMethod(Binder binder, Annotation annotation, Key<T> key,
- InjectionPoint injectionPoint) {
+ public <T> Key<T> prepareMethod(
+ Binder binder, Annotation annotation, Key<T> key, InjectionPoint injectionPoint) {
return key;
}
@@ -89,7 +89,7 @@ public final class ProviderMethodsModule implements Module {
/**
* Returns a module which creates bindings methods in the module that match the scanner.
*/
- public static Module forModule(Module module, ModuleAnnotatedMethodScanner scanner) {
+ public static Module forModule(Object module, ModuleAnnotatedMethodScanner scanner) {
return forObject(module, false, scanner);
}
@@ -114,8 +114,8 @@ public final class ProviderMethodsModule implements Module {
return new ProviderMethodsModule(object, skipFastClassGeneration, scanner);
}
- public Module getDelegateModule() {
- return delegate instanceof Module ? (Module) delegate : null;
+ public Object getDelegateModule() {
+ return delegate;
}
@Override
diff --git a/core/src/com/google/inject/spi/Elements.java b/core/src/com/google/inject/spi/Elements.java
index fcd714d2..aaeb7968 100644
--- a/core/src/com/google/inject/spi/Elements.java
+++ b/core/src/com/google/inject/spi/Elements.java
@@ -17,13 +17,11 @@
package com.google.inject.spi;
import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.inject.internal.InternalFlags.IncludeStackTraceOption;
import static com.google.inject.internal.InternalFlags.getIncludeStackTraceOption;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
-
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Binding;
@@ -44,6 +42,7 @@ import com.google.inject.internal.BindingBuilder;
import com.google.inject.internal.ConstantBindingBuilderImpl;
import com.google.inject.internal.Errors;
import com.google.inject.internal.ExposureBuilder;
+import com.google.inject.internal.InternalFlags.IncludeStackTraceOption;
import com.google.inject.internal.PrivateElementsImpl;
import com.google.inject.internal.ProviderMethodsModule;
import com.google.inject.internal.util.SourceProvider;
@@ -111,7 +110,7 @@ public final class Elements {
StackTraceElements.clearCache();
return Collections.unmodifiableList(binder.elements);
}
-
+
private static class ElementsAsModule implements Module {
private final Iterable<? extends Element> elements;
@@ -119,6 +118,7 @@ public final class Elements {
this.elements = elements;
}
+ @Override
public void configure(Binder binder) {
for (Element element : elements) {
element.applyTo(binder);
@@ -191,6 +191,7 @@ public final class Elements {
}
/*if[AOP]*/
+ @Override
public void bindInterceptor(
Matcher<? super Class<?>> classMatcher,
Matcher<? super Method> methodMatcher,
@@ -200,19 +201,23 @@ public final class Elements {
}
/*end[AOP]*/
+ @Override
public void bindScope(Class<? extends Annotation> annotationType, Scope scope) {
elements.add(new ScopeBinding(getElementSource(), annotationType, scope));
}
+ @Override
@SuppressWarnings("unchecked") // it is safe to use the type literal for the raw type
public void requestInjection(Object instance) {
requestInjection((TypeLiteral<Object>) TypeLiteral.get(instance.getClass()), instance);
}
+ @Override
public <T> void requestInjection(TypeLiteral<T> type, T instance) {
elements.add(new InjectionRequest<T>(getElementSource(), type, instance));
}
+ @Override
public <T> MembersInjector<T> getMembersInjector(final TypeLiteral<T> typeLiteral) {
final MembersInjectorLookup<T> element
= new MembersInjectorLookup<T>(getElementSource(), typeLiteral);
@@ -244,21 +249,20 @@ public final class Elements {
Binder binder = this;
boolean unwrapModuleSource = false;
// Update the module source for the new module
- if (!(module instanceof ProviderMethodsModule)) {
- moduleSource = getModuleSource(module);
- unwrapModuleSource = true;
- } else {
+ if (module instanceof ProviderMethodsModule) {
// There are two reason's we'd want to get the module source in a ProviderMethodsModule.
// ModuleAnnotatedMethodScanner lets users scan their own modules for @Provides-like
// bindings. If they install the module at a top-level, then moduleSource can be null.
// Also, if they pass something other than 'this' to it, we'd have the wrong source.
- Module delegate = ((ProviderMethodsModule) module).getDelegateModule();
- if (delegate != null
- && (moduleSource == null
- || !moduleSource.getModuleClassName().equals(delegate.getClass().getName()))) {
+ Object delegate = ((ProviderMethodsModule) module).getDelegateModule();
+ if (moduleSource == null
+ || !moduleSource.getModuleClassName().equals(delegate.getClass().getName())) {
moduleSource = getModuleSource(delegate);
unwrapModuleSource = true;
}
+ } else {
+ moduleSource = getModuleSource(module);
+ unwrapModuleSource = true;
}
if (module instanceof PrivateModule) {
binder = binder.newPrivateBinder();
@@ -348,37 +352,45 @@ public final class Elements {
return new RecordingBinder(this, null, newSourceProvider);
}
+ @Override
public PrivateBinder newPrivateBinder() {
PrivateElementsImpl privateElements = new PrivateElementsImpl(getElementSource());
RecordingBinder binder = new RecordingBinder(this, privateElements);
elements.add(privateElements);
return binder;
}
-
+
+ @Override
public void disableCircularProxies() {
elements.add(new DisableCircularProxiesOption(getElementSource()));
}
-
+
+ @Override
public void requireExplicitBindings() {
- elements.add(new RequireExplicitBindingsOption(getElementSource()));
+ elements.add(new RequireExplicitBindingsOption(getElementSource()));
}
-
+
+ @Override
public void requireAtInjectOnConstructors() {
elements.add(new RequireAtInjectOnConstructorsOption(getElementSource()));
}
+ @Override
public void requireExactBindingAnnotations() {
elements.add(new RequireExactBindingAnnotationsOption(getElementSource()));
}
+ @Override
public void expose(Key<?> key) {
exposeInternal(key);
}
+ @Override
public AnnotatedElementBuilder expose(Class<?> type) {
return exposeInternal(Key.get(type));
}
+ @Override
public AnnotatedElementBuilder expose(TypeLiteral<?> type) {
return exposeInternal(Key.get(type));
}
@@ -388,7 +400,9 @@ public final class Elements {
addError("Cannot expose %s on a standard binder. "
+ "Exposed bindings are only applicable to private binders.", key);
return new AnnotatedElementBuilder() {
+ @Override
public void annotatedWith(Class<? extends Annotation> annotationType) {}
+ @Override
public void annotatedWith(Annotation annotation) {}
};
}
@@ -398,7 +412,7 @@ public final class Elements {
return builder;
}
- private ModuleSource getModuleSource(Module module) {
+ private ModuleSource getModuleSource(Object module) {
StackTraceElement[] partialCallStack;
if (getIncludeStackTraceOption() == IncludeStackTraceOption.COMPLETE) {
partialCallStack = getPartialCallStack(new Throwable().getStackTrace());
@@ -426,7 +440,7 @@ public final class Elements {
}
IncludeStackTraceOption stackTraceOption = getIncludeStackTraceOption();
if (stackTraceOption == IncludeStackTraceOption.COMPLETE ||
- (stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE
+ (stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE
&& declaringSource == null)) {
callStack = new Throwable().getStackTrace();
}
@@ -450,9 +464,9 @@ public final class Elements {
}
/**
- * Removes the {@link #moduleSource} call stack from the beginning of current call stack. It
- * also removes the last two elements in order to make {@link #install(Module)} the last call
- * in the call stack.
+ * Removes the {@link #moduleSource} call stack from the beginning of current call stack. It
+ * also removes the last two elements in order to make {@link #install(Module)} the last call
+ * in the call stack.
*/
private StackTraceElement[] getPartialCallStack(StackTraceElement[] callStack) {
int toSkip = 0;
@@ -466,7 +480,7 @@ public final class Elements {
System.arraycopy(callStack, 1, partialCallStack, 0, chunkSize);
return partialCallStack;
}
-
+
@Override public String toString() {
return "Binder";
}
diff --git a/core/src/com/google/inject/spi/ModuleSource.java b/core/src/com/google/inject/spi/ModuleSource.java
index 19add7ee..1e07de2b 100644
--- a/core/src/com/google/inject/spi/ModuleSource.java
+++ b/core/src/com/google/inject/spi/ModuleSource.java
@@ -27,7 +27,7 @@ import java.util.List;
/**
* Associated to a {@link Module module}, provides the module class name, the parent module {@link
* ModuleSource source}, and the call stack that ends just before the module {@link
- * Module#configure(Binder) configure(Binder)} method invocation.
+ * Module#configure(Binder) configure(Binder)} method invocation.
*/
final class ModuleSource {
@@ -35,16 +35,16 @@ final class ModuleSource {
* The class name of module that this {@link ModuleSource} associated to.
*/
private final String moduleClassName;
-
+
/**
* The parent {@link ModuleSource module source}.
*/
private final ModuleSource parent;
-
- /**
- * The chunk of call stack that starts from the parent module {@link Module#configure(Binder)
- * configure(Binder)} call and ends just before the module {@link Module#configure(Binder)
- * configure(Binder)} method invocation. For a module without a parent module the chunk starts
+
+ /**
+ * The chunk of call stack that starts from the parent module {@link Module#configure(Binder)
+ * configure(Binder)} call and ends just before the module {@link Module#configure(Binder)
+ * configure(Binder)} method invocation. For a module without a parent module the chunk starts
* from the bottom of call stack. The array is non-empty if stack trace collection is on.
*/
private final InMemoryStackTraceElement[] partialCallStack;
@@ -52,32 +52,32 @@ final class ModuleSource {
/**
* Creates a new {@link ModuleSource} with a {@literal null} parent.
* @param module the corresponding module
- * @param partialCallStack the chunk of call stack that starts from the parent module {@link
- * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
+ * @param partialCallStack the chunk of call stack that starts from the parent module {@link
+ * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
* Module#configure(Binder) configure(Binder)} method invocation
*/
- ModuleSource(Module module, StackTraceElement[] partialCallStack) {
+ ModuleSource(Object module, StackTraceElement[] partialCallStack) {
this(null, module, partialCallStack);
- }
-
+ }
+
/**
* Creates a new {@link ModuleSource} Object.
- * @param parent the parent module {@link ModuleSource source}
+ * @param parent the parent module {@link ModuleSource source}
* @param module the corresponding module
- * @param partialCallStack the chunk of call stack that starts from the parent module {@link
- * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
+ * @param partialCallStack the chunk of call stack that starts from the parent module {@link
+ * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
* Module#configure(Binder) configure(Binder)} method invocation
*/
private ModuleSource(
- /* @Nullable */ ModuleSource parent, Module module, StackTraceElement[] partialCallStack) {
+ /* @Nullable */ ModuleSource parent, Object module, StackTraceElement[] partialCallStack) {
Preconditions.checkNotNull(module, "module cannot be null.");
Preconditions.checkNotNull(partialCallStack, "partialCallStack cannot be null.");
this.parent = parent;
this.moduleClassName = module.getClass().getName();
this.partialCallStack = StackTraceElements.convertToInMemoryStackTraceElement(partialCallStack);
}
-
- /**
+
+ /**
* Returns the corresponding module class name.
*
* @see Class#getName()
@@ -95,27 +95,27 @@ final class ModuleSource {
StackTraceElement[] getPartialCallStack() {
return StackTraceElements.convertToStackTraceElement(partialCallStack);
}
-
+
/**
* Returns the size of partial call stack if stack trace collection is on otherwise zero.
*/
int getPartialCallStackSize() {
return partialCallStack.length;
}
-
- /**
+
+ /**
* Creates and returns a child {@link ModuleSource} corresponding to the {@link Module module}.
* @param module the corresponding module
- * @param partialCallStack the chunk of call stack that starts from the parent module {@link
- * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
+ * @param partialCallStack the chunk of call stack that starts from the parent module {@link
+ * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
* Module#configure(Binder) configure(Binder)} method invocation
*/
- ModuleSource createChild(Module module, StackTraceElement[] partialCallStack) {
+ ModuleSource createChild(Object module, StackTraceElement[] partialCallStack) {
return new ModuleSource(this, module, partialCallStack);
}
- /**
- * Returns the parent module {@link ModuleSource source}.
+ /**
+ * Returns the parent module {@link ModuleSource source}.
*/
ModuleSource getParent() {
return parent;
@@ -123,7 +123,7 @@ final class ModuleSource {
/**
* Returns the class names of modules in this module source. The first element (index 0) is filled
- * by this object {@link #getModuleClassName()}. The second element is filled by the parent's
+ * by this object {@link #getModuleClassName()}. The second element is filled by the parent's
* {@link #getModuleClassName()} and so on.
*/
List<String> getModuleClassNames() {
@@ -138,7 +138,7 @@ final class ModuleSource {
}
/**
- * Returns the size of {@link ModuleSource ModuleSources} chain (all parents) that ends at this
+ * Returns the size of {@link ModuleSource ModuleSources} chain (all parents) that ends at this
* object.
*/
int size() {
@@ -147,7 +147,7 @@ final class ModuleSource {
}
return parent.size() + 1;
}
-
+
/**
* Returns the size of call stack that ends just before the module {@link Module#configure(Binder)
* configure(Binder)} method invocation (see {@link #getStackTrace()}).
@@ -170,7 +170,7 @@ final class ModuleSource {
int cursor = 0;
ModuleSource current = this;
while (current != null) {
- StackTraceElement[] chunk =
+ StackTraceElement[] chunk =
StackTraceElements.convertToStackTraceElement(current.partialCallStack);
int chunkSize = chunk.length;
System.arraycopy(chunk, 0, callStack, cursor, chunkSize);
diff --git a/extensions/dagger-adapter/build.properties b/extensions/dagger-adapter/build.properties
new file mode 100644
index 00000000..97e53c23
--- /dev/null
+++ b/extensions/dagger-adapter/build.properties
@@ -0,0 +1,8 @@
+lib.dir=../../lib
+ext.lib.dir=lib
+src.dir=src
+test.dir=test
+build.dir=build
+test.class=com.google.inject.daggeradapter.DaggerAdapterTest
+module=com.google.inject.daggeradapter
+fragment=true
diff --git a/extensions/dagger-adapter/build.xml b/extensions/dagger-adapter/build.xml
new file mode 100644
index 00000000..27eb4290
--- /dev/null
+++ b/extensions/dagger-adapter/build.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+
+<project name="guice-dagger-adapter" basedir="." default="jar">
+
+ <import file="../../common.xml"/>
+
+ <path id="compile.classpath">
+ <fileset dir="${lib.dir}" includes="*.jar"/>
+ <fileset dir="${ext.lib.dir}" includes="*.jar"/>
+ <pathelement path="../../build/classes"/>
+ <fileset dir="../multibindings/build" includes="*.jar"/>
+ </path>
+
+ <target name="jar" depends="compile, manifest" description="Build jar.">
+ <jar destfile="${build.dir}/${ant.project.name}-${version}.jar"
+ manifest="${build.dir}/META-INF/MANIFEST.MF">
+ <fileset dir="${build.dir}/classes" />
+ </jar>
+ </target>
+
+</project>
diff --git a/extensions/dagger-adapter/lib/dagger-2.0-20150205.014011-14.jar b/extensions/dagger-adapter/lib/dagger-2.0-20150205.014011-14.jar
new file mode 100644
index 00000000..3690cdc7
--- /dev/null
+++ b/extensions/dagger-adapter/lib/dagger-2.0-20150205.014011-14.jar
Binary files differ
diff --git a/extensions/dagger-adapter/pom.xml b/extensions/dagger-adapter/pom.xml
new file mode 100644
index 00000000..e93b1d74
--- /dev/null
+++ b/extensions/dagger-adapter/pom.xml
@@ -0,0 +1,28 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>com.google.inject.extensions</groupId>
+ <artifactId>extensions-parent</artifactId>
+ <version>4.0-SNAPSHOT</version>
+ </parent>
+ <artifactId>dagger-interop</artifactId>
+ <dependencies>
+ <dependency>
+ <groupId>com.google.inject</groupId>
+ <artifactId>guice</artifactId>
+ <version>4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.inject.extensions</groupId>
+ <artifactId>guice-multibindings</artifactId>
+ <version>4.0-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.dagger</groupId>
+ <artifactId>dagger</artifactId>
+ <version>2.0-SNAPSHOT</version>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/extensions/dagger-adapter/src/com/google/inject/daggeradapter/DaggerAdapter.java b/extensions/dagger-adapter/src/com/google/inject/daggeradapter/DaggerAdapter.java
new file mode 100644
index 00000000..eb7aac5f
--- /dev/null
+++ b/extensions/dagger-adapter/src/com/google/inject/daggeradapter/DaggerAdapter.java
@@ -0,0 +1,90 @@
+/**
+ * Copyright (C) 2015 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 com.google.inject.daggeradapter;
+
+import com.google.common.base.Objects;
+import com.google.inject.Binder;
+import com.google.inject.Module;
+import com.google.inject.internal.ProviderMethodsModule;
+import com.google.inject.spi.ModuleAnnotatedMethodScanner;
+
+import java.util.Arrays;
+
+/**
+ * A utility to adapt classes annotated with {@link @dagger.Module} such that their
+ * {@link @dagger.Provides} methods can be properly invoked by Guice to perform their
+ * provision operations.
+ *
+ * <p>Simple example: <pre>{@code
+ * Guice.createInjector(...other modules..., DaggerAdapter.from(new SomeDaggerAdapter()));
+ * }</pre>
+ *
+ * <p>Some notes on usage and compatibility.
+ * <ul>
+ * <li>Dagger provider methods have a "SET_VALUES" provision mode not supported by Guice.
+ * <li>MapBindings are not yet implemented (pending).
+ * <li>Be careful about stateful modules. In contrast to Dagger (where components are
+ * expected to be recreated on-demand with new Module instances), Guice typically
+ * has a single injector with a long lifetime, so your module instance will be used
+ * throughout the lifetime of the entire app.
+ * <li>Dagger 1.x uses {@link @Singleton} for all scopes, including shorter-lived scopes
+ * like per-request or per-activity. Using modules written with Dagger 1.x usage
+ * in mind may result in mis-scoped objects.
+ * <li>Dagger 2.x supports custom scope annotations, but for use in Guice, a custom scope
+ * implementation must be registered in order to support the custom lifetime of that
+ * annotation.
+ * </ul>
+ *
+ * @author cgruber@google.com (Christian Gruber)
+ */
+public final class DaggerAdapter {
+ /**
+ * Returns a guice module from a dagger module.
+ *
+ * <p>Note: At present, it does not honor {@code @Module(includes=...)} directives.
+ */
+ public static Module from(Object... daggerModuleObjects) {
+ // TODO(cgruber): Gather injects=, dedupe, factor out instances, instantiate the rest, and go.
+ return new DaggerCompatibilityModule(daggerModuleObjects);
+ }
+
+ /**
+ * A Module that adapts Dagger {@code @Module}-annotated types to contribute configuration
+ * to an {@link com.google.inject.Injector} using a dagger-specific
+ * {@link ModuleAnnotatedMethodScanner}.
+ */
+ private static final class DaggerCompatibilityModule implements Module {
+ private final Object[] daggerModuleObjects;
+
+ private DaggerCompatibilityModule(Object... daggerModuleObjects) {
+ this.daggerModuleObjects = daggerModuleObjects;
+ }
+
+ @Override public void configure(Binder binder) {
+ for (Object module : daggerModuleObjects) {
+ binder.install(ProviderMethodsModule.forModule(module, DaggerMethodScanner.INSTANCE));
+ }
+ }
+
+ @Override public String toString() {
+ return Objects.toStringHelper(this)
+ .add("modules", Arrays.asList(daggerModuleObjects))
+ .toString();
+ }
+ }
+
+ private DaggerAdapter() {}
+}
diff --git a/extensions/dagger-adapter/src/com/google/inject/daggeradapter/DaggerMethodScanner.java b/extensions/dagger-adapter/src/com/google/inject/daggeradapter/DaggerMethodScanner.java
new file mode 100644
index 00000000..0dbdda21
--- /dev/null
+++ b/extensions/dagger-adapter/src/com/google/inject/daggeradapter/DaggerMethodScanner.java
@@ -0,0 +1,75 @@
+/**
+ * Copyright (C) 2015 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 com.google.inject.daggeradapter;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Binder;
+import com.google.inject.Key;
+import com.google.inject.internal.UniqueAnnotations;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.ModuleAnnotatedMethodScanner;
+
+import dagger.Provides;
+import dagger.Provides.Type;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.Set;
+
+/**
+ * A scanner to process provider methods on Dagger modules.
+ *
+ * @author cgruber@google.com (Christian Gruber)
+ */
+final class DaggerMethodScanner extends ModuleAnnotatedMethodScanner {
+ static DaggerMethodScanner INSTANCE = new DaggerMethodScanner();
+
+ @Override public Set<? extends Class<? extends Annotation>> annotationClasses() {
+ return ImmutableSet.of(dagger.Provides.class);
+ }
+
+ @Override public <T> Key<T> prepareMethod(
+ Binder binder, Annotation rawAnnotation, Key<T> key, InjectionPoint injectionPoint) {
+ Method providesMethod = (Method) injectionPoint.getMember();
+ Provides annotation = (Provides) rawAnnotation;
+ switch (annotation.type()) {
+ case UNIQUE:
+ return key;
+ case MAP:
+ /* TODO(cgruber) implement map bindings */
+ binder.addError("Map bindings are not yet supported.");
+ case SET:
+ return processSetBinding(binder, key);
+ case SET_VALUES:
+ binder.addError(Type.SET_VALUES.name() + " contributions are not supported by Guice.",
+ providesMethod);
+ return key;
+ default:
+ binder.addError("Unknown @Provides type " + annotation.type() + ".", providesMethod);
+ return key;
+ }
+ }
+
+ private static <T> Key<T> processSetBinding(Binder binder, Key<T> key) {
+ Multibinder<T> setBinder = Multibinder.newSetBinder(binder, key.getTypeLiteral());
+ Key<T> newKey = Key.get(key.getTypeLiteral(), UniqueAnnotations.create());
+ setBinder.addBinding().to(newKey);
+ return newKey;
+ }
+
+ private DaggerMethodScanner() {}
+} \ No newline at end of file
diff --git a/extensions/dagger-adapter/test/com/google/inject/daggeradapter/DaggerAdapterTest.java b/extensions/dagger-adapter/test/com/google/inject/daggeradapter/DaggerAdapterTest.java
new file mode 100644
index 00000000..30e1d186
--- /dev/null
+++ b/extensions/dagger-adapter/test/com/google/inject/daggeradapter/DaggerAdapterTest.java
@@ -0,0 +1,99 @@
+/**
+ * Copyright (C) 2015 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 com.google.inject.daggeradapter;
+
+import static dagger.Provides.Type.SET;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.AbstractModule;
+import com.google.inject.Binder;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.Provides;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.util.Providers;
+
+import junit.framework.TestCase;
+
+import java.util.Set;
+
+/**
+ * Tests for {@link DaggerAdapter}.
+ *
+ * @author cgruber@google.com (Christian Gruber)
+ */
+
+public class DaggerAdapterTest extends TestCase {
+ @dagger.Module static class SimpleDaggerModule {
+ @dagger.Provides Integer anInteger() {
+ return 1;
+ }
+ }
+
+ public void testSimpleModule() {
+ Injector i = Guice.createInjector(DaggerAdapter.from(new SimpleDaggerModule()));
+ assertEquals((Integer) 1, i.getInstance(Integer.class));
+ }
+
+ static class SimpleGuiceModule extends AbstractModule {
+ @Provides String aString(Integer i) {
+ return i.toString();
+ }
+ @Override protected void configure() {}
+ }
+
+ public void testInteractionWithGuiceModules() {
+ Injector i = Guice.createInjector(
+ new SimpleGuiceModule(),
+ DaggerAdapter.from(new SimpleDaggerModule()));
+ assertEquals("1", i.getInstance(String.class));
+ }
+
+ @dagger.Module static class SetBindingDaggerModule1 {
+ @dagger.Provides(type=SET) Integer anInteger() {
+ return 5;
+ }
+ }
+
+ @dagger.Module static class SetBindingDaggerModule2 {
+ @dagger.Provides(type=SET) Integer anInteger() {
+ return 3;
+ }
+ }
+
+ public void testSetBindings() {
+ Injector i = Guice.createInjector(
+ DaggerAdapter.from(new SetBindingDaggerModule1(), new SetBindingDaggerModule2()));
+ assertEquals(ImmutableSet.of(3, 5), i.getInstance(new Key<Set<Integer>>() {}));
+ }
+
+ static class MultibindingGuiceModule implements Module {
+ @Override public void configure(Binder binder) {
+ Multibinder<Integer> mb = Multibinder.newSetBinder(binder, Integer.class);
+ mb.addBinding().toInstance(13);
+ mb.addBinding().toProvider(Providers.of(8)); // mix'n'match.
+ }
+ }
+
+ public void testSetBindingsWithGuiceModule() {
+ Injector i = Guice.createInjector(
+ new MultibindingGuiceModule(),
+ DaggerAdapter.from(new SetBindingDaggerModule1(), new SetBindingDaggerModule2()));
+ assertEquals(ImmutableSet.of(13, 3, 5, 8), i.getInstance(new Key<Set<Integer>>() {}));
+ }
+}
diff --git a/extensions/pom.xml b/extensions/pom.xml
index 084967cf..6b2c8a35 100644
--- a/extensions/pom.xml
+++ b/extensions/pom.xml
@@ -18,6 +18,7 @@
<modules>
<module>assistedinject</module>
+ <module>dagger-adapter</module>
<module>grapher</module>
<module>jmx</module>
<module>jndi</module>