Skip to content
Commits on Source (3)
Guice
====
**Latest release: [4.1](https://github.com/google/guice/wiki/Guice41)**
**Latest release: [4.2](https://github.com/google/guice/wiki/Guice42)**
**Documentation:** [User Guide](https://github.com/google/guice/wiki/Motivation), [4.1 javadocs](http://google.github.io/guice/api-docs/4.1/javadoc/index.html), [Latest javadocs](http://google.github.io/guice/api-docs/latest/javadoc/index.html) <br/>
**Documentation:** [User Guide](https://github.com/google/guice/wiki/Motivation), [4.2 javadocs](http://google.github.io/guice/api-docs/4.2/javadoc/index.html), [Latest javadocs](http://google.github.io/guice/api-docs/latest/javadoc/index.html) <br/>
**Continuous Integration:** [![Build Status](https://api.travis-ci.org/google/guice.png?branch=master)](https://travis-ci.org/google/guice) <br
/>
**Mailing Lists:** [User Mailing List](http://groups.google.com/group/google-guice) <br/>
......
......@@ -6,7 +6,7 @@
<parent>
<groupId>com.google.inject</groupId>
<artifactId>guice-parent</artifactId>
<version>4.2.0</version>
<version>4.2.1</version>
</parent>
<packaging>pom</packaging>
......
......@@ -116,11 +116,11 @@
<pathelement location="${build.dir}/dist/guice-${version}.jar"/>
<pathelement location="lib/javax.inject.jar"/>
<pathelement location="lib/aopalliance.jar"/>
<pathelement location="lib/guava-19.0.jar"/>
<pathelement location="lib/build/guava-testlib-19.0.jar"/>
<pathelement location="lib/guava-25.1-android.jar"/>
<pathelement location="lib/build/guava-testlib-25.1-android.jar"/>
<pathelement location="lib/build/junit.jar"/>
<pathelement location="lib/build/servlet-api-2.5.jar"/>
<pathelement location="lib/build/truth-0.36.jar"/>
<pathelement location="lib/build/truth-0.41.jar"/>
<pathelement location="lib/build/easymock.jar"/>
<pathelement location="lib/build/javax.inject-tck.jar"/>
<pathelement location="lib/build/bnd-0.0.384.jar"/>
......@@ -136,7 +136,7 @@
</java>
</target>
<property name="old.api" value="4.1"/>
<property name="old.api" value="4.2"/>
<property name="new.api" value="latest"/>
<target name="jdiff" depends="compile">
<property name="jdiff.home" value="lib/build/jdiff"/>
......@@ -279,13 +279,13 @@
<arg value="-DNO_AOP" />
</munge>
<replace file="build/no_aop/common.xml" value="">
<replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/asm-6.0.jar"/>]]></replacetoken>
<replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/asm-6.2.1.jar"/>]]></replacetoken>
</replace>
<replace file="build/no_aop/common.xml" value="">
<replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/cglib-3.2.6.jar"/>]]></replacetoken>
<replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/cglib-3.2.8.jar"/>]]></replacetoken>
</replace>
<replace file="build/no_aop/common.xml" value="">
<replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/cglib-3.2.6.jar"><include name="LICENSE"/><include name="NOTICE"/></zipfileset>]]></replacetoken>
<replacetoken><![CDATA[<zipfileset src="${common.basedir}/lib/build/cglib-3.2.8.jar"><include name="LICENSE"/><include name="NOTICE"/></zipfileset>]]></replacetoken>
</replace>
<replace file="build/no_aop/common.xml" value='Bundle-Name" value="$${ant.project.name} (no_aop)'>
<replacetoken><![CDATA[Bundle-Name" value="${ant.project.name}]]></replacetoken>
......
......@@ -144,8 +144,8 @@
classpath="${common.basedir}/lib/build/jarjar-1.1.jar"/>
<jarjar jarfile="${build.dir}/${ant.project.name}-with-deps.jar">
<fileset dir="${build.dir}/classes"/>
<zipfileset src="${common.basedir}/lib/build/cglib-3.2.6.jar"/>
<zipfileset src="${common.basedir}/lib/build/asm-6.0.jar"/>
<zipfileset src="${common.basedir}/lib/build/cglib-3.2.8.jar"/>
<zipfileset src="${common.basedir}/lib/build/asm-6.2.1.jar"/>
<rule pattern="net.sf.cglib.*" result="com.google.inject.internal.cglib.$@1"/>
<rule pattern="net.sf.cglib.**.*" result="com.google.inject.internal.cglib.@1.$@2"/>
<rule pattern="org.objectweb.asm.*" result="com.google.inject.internal.asm.$@1"/>
......
......@@ -6,7 +6,7 @@
<parent>
<groupId>com.google.inject</groupId>
<artifactId>guice-parent</artifactId>
<version>4.2.0</version>
<version>4.2.1</version>
</parent>
<artifactId>guice</artifactId>
......
......@@ -25,28 +25,35 @@ import java.util.List;
* reason on how does it work or not. Still I want to assure you that hundreds(?) of hours were
* thrown into making this code simple, while still maintaining Singleton contract.
*
* <p>Anyway, why is it so complex? Singleton scope does not seem to be that unique. 1) Guice has
* never truly expected to be used in multi threading environment with many Injectors working
* alongside each other. There is almost no code with Guice that propagates state between threads.
* And Singleton scope is The exception. 2) Guice supports circular dependencies and thus manages
* proxy objects. There is no interface that allows user defined Scopes to create proxies, it is
* expected to be done by Guice. Singleton scope needs to be able to detect circular dependencies
* spanning several threads, therefore Singleton scope needs to be able to create these proxies. 3)
* To make things worse, Guice has a very tricky definition for a binding resolution when Injectors
* are in in a parent/child relationship. And Scope does not have access to this information by
* design, the only real action that Scope can do is to call or not to call a creator. 4) There is
* no readily available code in Guice that can detect a potential deadlock, and no code for handling
* dependency cycles spanning several threads. This is significantly harder as all the dependencies
* in a thread at runtime can be represented with a list, where in a multi threaded environment we
* have more complex dependency trees. 5) Guice has a pretty strong contract regarding Garbage
* Collection, which often prevents us from linking objects directly. So simple domain specific code
* can not be written and intermediary id objects need to be managed. 6) Guice is relatively fast
* and we should not make things worse. We're trying our best to optimize synchronization for speed
* and memory. Happy path should be almost as fast as in a single threaded solution and should not
* take much more memory. 7) Error message generation in Guice was not meant to be used like this
* and to work around its APIs we need a lot of code. Additional complexity comes from inherent data
* races as message is only generated when failure occurs on proxy object generation. Things get
* ugly pretty fast.
* <p>Anyway, why is it so complex? Singleton scope does not seem to be that unique.
*
* <ol>
* <li>Guice has never truly expected to be used in multi threading environment with many
* Injectors working alongside each other. There is almost no code with Guice that propagates
* state between threads. And Singleton scope is The exception.
* <li>Guice supports circular dependencies and thus manages proxy objects. There is no interface
* that allows user defined Scopes to create proxies, it is expected to be done by Guice.
* Singleton scope needs to be able to detect circular dependencies spanning several threads,
* therefore Singleton scope needs to be able to create these proxies.
* <li>To make things worse, Guice has a very tricky definition for a binding resolution when
* Injectors are in in a parent/child relationship. And Scope does not have access to this
* information by design, the only real action that Scope can do is to call or not to call a
* creator.
* <li>There is no readily available code in Guice that can detect a potential deadlock, and no
* code for handling dependency cycles spanning several threads. This is significantly harder
* as all the dependencies in a thread at runtime can be represented with a list, where in a
* multi threaded environment we have more complex dependency trees.
* <li>Guice has a pretty strong contract regarding Garbage Collection, which often prevents us
* from linking objects directly. So simple domain specific code can not be written and
* intermediary id objects need to be managed.
* <li>Guice is relatively fast and we should not make things worse. We're trying our best to
* optimize synchronization for speed and memory. Happy path should be almost as fast as in a
* single threaded solution and should not take much more memory.
* <li>Error message generation in Guice was not meant to be used like this and to work around its
* APIs we need a lot of code. Additional complexity comes from inherent data races as message
* is only generated when failure occurs on proxy object generation. Things get ugly pretty
* fast.
* </ol>
*
* @see #scope(Key, Provider)
* @see CycleDetectingLock
......@@ -70,40 +77,53 @@ public class SingletonScope implements Scope {
new CycleDetectingLockFactory<Key<?>>();
/**
* Provides singleton scope with the following properties: - creates no more than one instance per
* Key as a creator is used no more than once, - result is cached and returned quickly on
* subsequent calls, - exception in a creator is not treated as instance creation and is not
* cached, - creates singletons in parallel whenever possible, - waits for dependent singletons to
* be created even across threads and when dependencies are shared as long as no circular
* dependencies are detected, - returns circular proxy only when circular dependencies are
* detected, - aside from that, blocking synchronization is only used for proxy creation and
* initialization,
* Provides singleton scope with the following properties:
*
* <ul>
* <li>creates no more than one instance per Key as a creator is used no more than once
* <li>result is cached and returned quickly on subsequent calls
* <li>exception in a creator is not treated as instance creation and is not cached
* <li>creates singletons in parallel whenever possible
* <li>waits for dependent singletons to be created even across threads and when dependencies
* are shared as long as no circular dependencies are detected
* <li>returns circular proxy only when circular dependencies are detected
* <li>aside from that, blocking synchronization is only used for proxy creation and
* initialization
* </ul>
*
* @see CycleDetectingLockFactory
*/
@Override
public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) {
/**
* Locking strategy: - volatile instance: double-checked locking for quick exit when scope is
* initialized, - constructionContext: manipulations with proxies list or instance
* initialization - creationLock: singleton instance creation, -- allows to guarantee only one
* instance per singleton, -- special type of a lock, that prevents potential deadlocks, --
* guards constructionContext for all operations except proxy creation
*/
/** Locking strategy: */
return new Provider<T>() {
/**
* The lazily initialized singleton instance. Once set, this will either have type T or will
* be equal to NULL. Would never be reset to null.
*
* <p>Locking strategy: double-checked locking for quick exit when scope is initialized.
*/
volatile Object instance;
/**
* Circular proxies are used when potential deadlocks are detected. Guarded by itself.
* ConstructionContext is not thread-safe, so each call should be synchronized.
*
* <p>Locking strategy: manipulations with proxies list or instance initialization.
*/
final ConstructionContext<T> constructionContext = new ConstructionContext<>();
/** For each binding there is a separate lock that we hold during object creation. */
/**
* For each binding there is a separate lock that we hold during object creation.
*
* <p>Locking strategy: singleton instance creation.
*
* <ul>
* <li>allows to guarantee only one instance per singleton,
* <li>special type of a lock, that prevents potential deadlocks,
* <li>guards constructionContext for all operations except proxy creation
* </ul>
*/
final CycleDetectingLock<Key<?>> creationLock = cycleDetectingLockFactory.create(key);
/**
......
......@@ -51,17 +51,24 @@ final class LineNumbers {
* Reads line number information from the given class, if available.
*
* @param type the class to read line number information from
* @throws IllegalArgumentException if the bytecode for the class cannot be found
* @throws java.io.IOException if an error occurs while reading bytecode
*/
public LineNumbers(Class type) throws IOException {
this.type = type;
if (!type.isArray()) {
InputStream in = type.getResourceAsStream("/" + type.getName().replace('.', '/') + ".class");
InputStream in = null;
try {
in = type.getResourceAsStream("/" + type.getName().replace('.', '/') + ".class");
} catch (IllegalStateException ignored) {
// Some classloaders throw IllegalStateException when they can't load a resource.
}
if (in != null) {
try {
new ClassReader(in).accept(new LineNumberReader(), ClassReader.SKIP_FRAMES);
} catch (UnsupportedOperationException ignored) {
// We may be trying to inspect classes that were compiled with a more recent version
// of javac than our ASM supports. If that happens, just ignore the class and don't
// capture line numbers.
} finally {
try {
in.close();
......
......@@ -44,8 +44,8 @@ import com.google.inject.internal.RealOptionalBinder;
* instantiated in {@code Stage.PRODUCTION}.</b>
*
* <p>If setDefault or setBinding are linked to Providers, the Provider may return {@code null}. If
* it does, the Optional bindings will be absent. Binding setBinding to a Provider that returns null
* will not cause OptionalBinder to fall back to the setDefault binding.
* it does, {@code Optional<T>} will be bound to an absent Optional. Binding setBinding to a
* Provider that returns null will not cause OptionalBinder to fall back to the setDefault binding.
*
* <p>If neither setDefault nor setBinding are called, it will try to link to a user-supplied
* binding of the same type. If no binding exists, the optionals will be absent. Otherwise, if a
......
......@@ -32,18 +32,18 @@ import java.lang.annotation.Target;
* <pre>
* {@literal @}ProvidesIntoMap
* {@literal @}StringMapKey("Foo")
* {@literal @}Named("urls")
* {@literal @}Named("plugins")
* Plugin provideFooUrl(FooManager fm) { return fm.getPlugin(); }
*
* {@literal @}ProvidesIntoMap
* {@literal @}StringMapKey("Bar")
* {@literal @}Named("urls")
* {@literal @}Named("plugins")
* Plugin provideBarUrl(BarManager bm) { return bm.getPlugin(); }
* </pre>
*
* will add two items to the {@code @Named("urls") Map<String, Plugin>} map. The key 'Foo' will map
* to the provideFooUrl method, and the key 'Bar' will map to the provideBarUrl method. The values
* are bound as providers and will be evaluated at injection time.
* will add two items to the {@code @Named("plugins") Map<String, Plugin>} map. The key 'Foo' will
* map to the provideFooUrl method, and the key 'Bar' will map to the provideBarUrl method. The
* values are bound as providers and will be evaluated at injection time.
*
* <p>Because the key is specified as an annotation, only Strings, Classes, enums, primitive types
* and annotation instances are supported as keys.
......
......@@ -504,6 +504,7 @@ public class DuplicateBindingsTest extends TestCase {
}
@Override
@SuppressWarnings("EqualsBrokenForNull") // intentionally NPE on null for the test
public boolean equals(Object obj) {
return obj.getClass() == getClass();
}
......
......@@ -43,6 +43,7 @@ public class ModuleTest extends TestCase {
}
@Override
@SuppressWarnings("EqualsBrokenForNull") // intentionally NPE on null for the test
public boolean equals(Object obj) {
return obj.getClass() == D.class; // we're all equal in the eyes of guice
}
......
......@@ -52,7 +52,7 @@ public class OSGiContainerTest extends TestCase {
/*end[AOP]*/
static final String JAVAX_INJECT_JAR =
System.getProperty("javax.inject.jar", "lib/javax.inject.jar");
static final String GUAVA_JAR = System.getProperty("guava.jar", "lib/guava-19.0.jar");
static final String GUAVA_JAR = System.getProperty("guava.jar", "lib/guava-25.1-android.jar");
// dynamically build test bundles
@Override
......
guice (4.2.1-1) unstable; urgency=medium
* Team upload.
* New upstream release
-- Emmanuel Bourg <ebourg@apache.org> Tue, 16 Oct 2018 15:51:07 +0200
guice (4.2-3) unstable; urgency=medium
* Team upload.
......
......@@ -6,7 +6,7 @@
<parent>
<groupId>com.google.inject.extensions</groupId>
<artifactId>extensions-parent</artifactId>
<version>4.2.0</version>
<version>4.2.1</version>
</parent>
<artifactId>guice-assistedinject</artifactId>
......
......@@ -314,7 +314,7 @@ public final class FactoryModuleBuilder {
@Override
protected void configure() {
Provider<F> provider = new FactoryProvider2<>(factoryInterface, bindings);
bind(factoryInterface).toProvider(provider);
binder().skipSources(this.getClass()).bind(factoryInterface).toProvider(provider);
}
};
}
......
......@@ -5,7 +5,7 @@
<parent>
<groupId>com.google.inject.extensions</groupId>
<artifactId>extensions-parent</artifactId>
<version>4.2.0</version>
<version>4.2.1</version>
</parent>
<artifactId>guice-dagger-adapter</artifactId>
<name>Google Guice - Extensions - Dagger Adapter</name>
......
......@@ -6,7 +6,7 @@
<parent>
<groupId>com.google.inject.extensions</groupId>
<artifactId>extensions-parent</artifactId>
<version>4.2.0</version>
<version>4.2.1</version>
</parent>
<artifactId>guice-grapher</artifactId>
......
......@@ -6,7 +6,7 @@
<parent>
<groupId>com.google.inject.extensions</groupId>
<artifactId>extensions-parent</artifactId>
<version>4.2.0</version>
<version>4.2.1</version>
</parent>
<artifactId>guice-jmx</artifactId>
......
......@@ -6,7 +6,7 @@
<parent>
<groupId>com.google.inject.extensions</groupId>
<artifactId>extensions-parent</artifactId>
<version>4.2.0</version>
<version>4.2.1</version>
</parent>
<artifactId>guice-jndi</artifactId>
......
......@@ -6,7 +6,7 @@
<parent>
<groupId>com.google.inject.extensions</groupId>
<artifactId>extensions-parent</artifactId>
<version>4.2.0</version>
<version>4.2.1</version>
</parent>
<artifactId>guice-multibindings</artifactId>
......