aboutsummaryrefslogtreecommitdiff
path: root/core/src/com
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2018-08-28 11:18:22 -0700
committerHaibo Huang <hhb@google.com>2018-08-28 11:20:15 -0700
commitbfaaf2b15f18ec4f73641d11539db4829f5b15e2 (patch)
treecb03f0d7b72d492f6f29457cbe0d5b5eee636f54 /core/src/com
parent9b878813d48dee9b08a1cdc8c8b607a602752659 (diff)
downloadguice-bfaaf2b15f18ec4f73641d11539db4829f5b15e2.tar.gz
Upgrade guice to 4.2
Test: m checkbuild Change-Id: I7df64e3d67f5b6c586ff444f45636cd7b2935c1f
Diffstat (limited to 'core/src/com')
-rw-r--r--core/src/com/google/inject/AbstractModule.java101
-rw-r--r--core/src/com/google/inject/Binder.java424
-rw-r--r--core/src/com/google/inject/Binding.java55
-rw-r--r--core/src/com/google/inject/BindingAnnotation.java8
-rw-r--r--core/src/com/google/inject/ConfigurationException.java27
-rw-r--r--core/src/com/google/inject/CreationException.java12
-rw-r--r--core/src/com/google/inject/Exposed.java6
-rw-r--r--core/src/com/google/inject/Guice.java50
-rw-r--r--core/src/com/google/inject/ImplementedBy.java6
-rw-r--r--core/src/com/google/inject/Inject.java47
-rw-r--r--core/src/com/google/inject/Injector.java60
-rw-r--r--core/src/com/google/inject/Key.java247
-rw-r--r--core/src/com/google/inject/MembersInjector.java1
-rw-r--r--core/src/com/google/inject/Module.java20
-rw-r--r--core/src/com/google/inject/OutOfScopeException.java6
-rw-r--r--core/src/com/google/inject/PrivateBinder.java10
-rw-r--r--core/src/com/google/inject/PrivateModule.java115
-rw-r--r--core/src/com/google/inject/ProvidedBy.java8
-rw-r--r--core/src/com/google/inject/Provider.java27
-rw-r--r--core/src/com/google/inject/Provides.java6
-rw-r--r--core/src/com/google/inject/ProvisionException.java13
-rw-r--r--core/src/com/google/inject/Scope.java38
-rw-r--r--core/src/com/google/inject/ScopeAnnotation.java8
-rw-r--r--core/src/com/google/inject/Scopes.java113
-rw-r--r--core/src/com/google/inject/Singleton.java8
-rw-r--r--core/src/com/google/inject/Stage.java10
-rw-r--r--core/src/com/google/inject/TypeLiteral.java135
-rw-r--r--core/src/com/google/inject/binder/AnnotatedBindingBuilder.java13
-rw-r--r--core/src/com/google/inject/binder/AnnotatedConstantBindingBuilder.java13
-rw-r--r--core/src/com/google/inject/binder/AnnotatedElementBuilder.java10
-rw-r--r--core/src/com/google/inject/binder/ConstantBindingBuilder.java46
-rw-r--r--core/src/com/google/inject/binder/LinkedBindingBuilder.java39
-rw-r--r--core/src/com/google/inject/binder/ScopedBindingBuilder.java16
-rw-r--r--core/src/com/google/inject/binder/package-info.java7
-rw-r--r--core/src/com/google/inject/internal/AbstractBindingBuilder.java27
-rw-r--r--core/src/com/google/inject/internal/AbstractBindingProcessor.java88
-rw-r--r--core/src/com/google/inject/internal/AbstractProcessor.java10
-rw-r--r--core/src/com/google/inject/internal/Annotations.java214
-rw-r--r--core/src/com/google/inject/internal/BindingBuilder.java53
-rw-r--r--core/src/com/google/inject/internal/BindingImpl.java32
-rw-r--r--core/src/com/google/inject/internal/BindingProcessor.java291
-rw-r--r--core/src/com/google/inject/internal/BoundProviderFactory.java54
-rw-r--r--core/src/com/google/inject/internal/BytecodeGen.java251
-rw-r--r--core/src/com/google/inject/internal/CircularDependencyProxy.java6
-rw-r--r--core/src/com/google/inject/internal/ConstantBindingBuilderImpl.java35
-rw-r--r--core/src/com/google/inject/internal/ConstantFactory.java20
-rw-r--r--core/src/com/google/inject/internal/ConstructionContext.java22
-rw-r--r--core/src/com/google/inject/internal/ConstructionProxy.java18
-rw-r--r--core/src/com/google/inject/internal/ConstructionProxyFactory.java6
-rw-r--r--core/src/com/google/inject/internal/ConstructorBindingImpl.java144
-rw-r--r--core/src/com/google/inject/internal/ConstructorInjector.java66
-rw-r--r--core/src/com/google/inject/internal/ConstructorInjectorStore.java55
-rw-r--r--core/src/com/google/inject/internal/CreationListener.java4
-rw-r--r--core/src/com/google/inject/internal/CycleDetectingLock.java297
-rw-r--r--core/src/com/google/inject/internal/DefaultConstructionProxyFactory.java161
-rw-r--r--core/src/com/google/inject/internal/DeferredLookups.java13
-rw-r--r--core/src/com/google/inject/internal/DelayedInitialize.java12
-rw-r--r--core/src/com/google/inject/internal/DelegatingInvocationHandler.java14
-rw-r--r--core/src/com/google/inject/internal/Element.java47
-rw-r--r--core/src/com/google/inject/internal/EncounterImpl.java26
-rw-r--r--core/src/com/google/inject/internal/ErrorHandler.java10
-rw-r--r--core/src/com/google/inject/internal/Errors.java657
-rw-r--r--core/src/com/google/inject/internal/ErrorsException.java5
-rw-r--r--core/src/com/google/inject/internal/Exceptions.java62
-rw-r--r--core/src/com/google/inject/internal/ExposedBindingImpl.java24
-rw-r--r--core/src/com/google/inject/internal/ExposedKeyFactory.java11
-rw-r--r--core/src/com/google/inject/internal/ExposureBuilder.java14
-rw-r--r--core/src/com/google/inject/internal/FactoryProxy.java36
-rw-r--r--core/src/com/google/inject/internal/FailableCache.java37
-rw-r--r--core/src/com/google/inject/internal/Indexer.java190
-rw-r--r--core/src/com/google/inject/internal/InheritingState.java38
-rw-r--r--core/src/com/google/inject/internal/Initializable.java8
-rw-r--r--core/src/com/google/inject/internal/Initializables.java16
-rw-r--r--core/src/com/google/inject/internal/Initializer.java227
-rw-r--r--core/src/com/google/inject/internal/InjectionRequestProcessor.java40
-rw-r--r--core/src/com/google/inject/internal/InjectorImpl.java492
-rw-r--r--core/src/com/google/inject/internal/InjectorOptionsProcessor.java7
-rw-r--r--core/src/com/google/inject/internal/InjectorShell.java83
-rw-r--r--core/src/com/google/inject/internal/InstanceBindingImpl.java45
-rw-r--r--core/src/com/google/inject/internal/InterceptorBindingProcessor.java10
-rw-r--r--core/src/com/google/inject/internal/InterceptorStackCallback.java48
-rw-r--r--core/src/com/google/inject/internal/InternalContext.java166
-rw-r--r--core/src/com/google/inject/internal/InternalFactory.java12
-rw-r--r--core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java41
-rw-r--r--core/src/com/google/inject/internal/InternalFactoryToProviderAdapter.java23
-rw-r--r--core/src/com/google/inject/internal/InternalFlags.java15
-rw-r--r--core/src/com/google/inject/internal/InternalInjectorCreator.java128
-rw-r--r--core/src/com/google/inject/internal/InternalProviderInstanceBindingImpl.java195
-rw-r--r--core/src/com/google/inject/internal/InternalProvisionException.java228
-rw-r--r--core/src/com/google/inject/internal/LinkedBindingImpl.java32
-rw-r--r--core/src/com/google/inject/internal/LinkedProviderBindingImpl.java63
-rw-r--r--core/src/com/google/inject/internal/ListenerBindingProcessor.java12
-rw-r--r--core/src/com/google/inject/internal/LookupProcessor.java12
-rw-r--r--core/src/com/google/inject/internal/Lookups.java2
-rw-r--r--core/src/com/google/inject/internal/MembersInjectorImpl.java157
-rw-r--r--core/src/com/google/inject/internal/MembersInjectorStore.java53
-rw-r--r--core/src/com/google/inject/internal/MessageProcessor.java9
-rw-r--r--core/src/com/google/inject/internal/Messages.java401
-rw-r--r--core/src/com/google/inject/internal/MethodAspect.java18
-rw-r--r--core/src/com/google/inject/internal/ModuleAnnotatedMethodScannerProcessor.java5
-rw-r--r--core/src/com/google/inject/internal/MoreTypes.java152
-rw-r--r--core/src/com/google/inject/internal/Nullability.java17
-rw-r--r--core/src/com/google/inject/internal/PrivateElementProcessor.java11
-rw-r--r--core/src/com/google/inject/internal/PrivateElementsImpl.java22
-rw-r--r--core/src/com/google/inject/internal/ProcessedBindingData.java38
-rw-r--r--core/src/com/google/inject/internal/ProvidedByInternalFactory.java66
-rw-r--r--core/src/com/google/inject/internal/ProviderInstanceBindingImpl.java49
-rw-r--r--core/src/com/google/inject/internal/ProviderInternalFactory.java67
-rw-r--r--core/src/com/google/inject/internal/ProviderMethod.java187
-rw-r--r--core/src/com/google/inject/internal/ProviderMethodsModule.java207
-rw-r--r--core/src/com/google/inject/internal/ProviderToInternalFactoryAdapter.java43
-rw-r--r--core/src/com/google/inject/internal/ProvidesMethodScanner.java182
-rw-r--r--core/src/com/google/inject/internal/ProvisionListenerCallbackStore.java59
-rw-r--r--core/src/com/google/inject/internal/ProvisionListenerStackCallback.java70
-rw-r--r--core/src/com/google/inject/internal/ProxyFactory.java96
-rw-r--r--core/src/com/google/inject/internal/RealElement.java100
-rw-r--r--core/src/com/google/inject/internal/RealMapBinder.java1344
-rw-r--r--core/src/com/google/inject/internal/RealMultibinder.java604
-rw-r--r--core/src/com/google/inject/internal/RealOptionalBinder.java844
-rw-r--r--core/src/com/google/inject/internal/ScopeBindingProcessor.java11
-rw-r--r--core/src/com/google/inject/internal/Scoping.java256
-rw-r--r--core/src/com/google/inject/internal/SingleFieldInjector.java24
-rw-r--r--core/src/com/google/inject/internal/SingleMemberInjector.java9
-rw-r--r--core/src/com/google/inject/internal/SingleMethodInjector.java64
-rw-r--r--core/src/com/google/inject/internal/SingleParameterInjector.java54
-rw-r--r--core/src/com/google/inject/internal/SingletonScope.java294
-rw-r--r--core/src/com/google/inject/internal/State.java231
-rw-r--r--core/src/com/google/inject/internal/TypeConverterBindingProcessor.java218
-rw-r--r--core/src/com/google/inject/internal/UniqueAnnotations.java29
-rw-r--r--core/src/com/google/inject/internal/UntargettedBindingImpl.java33
-rw-r--r--core/src/com/google/inject/internal/UntargettedBindingProcessor.java72
-rw-r--r--core/src/com/google/inject/internal/WeakKeySet.java31
-rw-r--r--core/src/com/google/inject/internal/package-info.java4
-rw-r--r--core/src/com/google/inject/internal/util/Classes.java27
-rw-r--r--core/src/com/google/inject/internal/util/LineNumbers.java95
-rw-r--r--core/src/com/google/inject/internal/util/SourceProvider.java21
-rw-r--r--core/src/com/google/inject/internal/util/StackTraceElements.java105
-rw-r--r--core/src/com/google/inject/internal/util/Stopwatch.java10
-rw-r--r--core/src/com/google/inject/matcher/AbstractMatcher.java24
-rw-r--r--core/src/com/google/inject/matcher/Matcher.java14
-rw-r--r--core/src/com/google/inject/matcher/Matchers.java179
-rw-r--r--core/src/com/google/inject/matcher/package-info.java7
-rw-r--r--core/src/com/google/inject/multibindings/ClassMapKey.java37
-rw-r--r--core/src/com/google/inject/multibindings/MapBinder.java214
-rw-r--r--core/src/com/google/inject/multibindings/MapBinderBinding.java114
-rw-r--r--core/src/com/google/inject/multibindings/MapKey.java60
-rw-r--r--core/src/com/google/inject/multibindings/Multibinder.java195
-rw-r--r--core/src/com/google/inject/multibindings/MultibinderBinding.java78
-rw-r--r--core/src/com/google/inject/multibindings/MultibindingsScanner.java75
-rw-r--r--core/src/com/google/inject/multibindings/MultibindingsTargetVisitor.java45
-rw-r--r--core/src/com/google/inject/multibindings/OptionalBinder.java199
-rw-r--r--core/src/com/google/inject/multibindings/OptionalBinderBinding.java73
-rw-r--r--core/src/com/google/inject/multibindings/ProvidesIntoMap.java57
-rw-r--r--core/src/com/google/inject/multibindings/ProvidesIntoOptional.java62
-rw-r--r--core/src/com/google/inject/multibindings/ProvidesIntoSet.java50
-rw-r--r--core/src/com/google/inject/multibindings/StringMapKey.java37
-rw-r--r--core/src/com/google/inject/multibindings/package-info.java (renamed from core/src/com/google/inject/internal/ContextualCallable.java)13
-rw-r--r--core/src/com/google/inject/name/Named.java5
-rw-r--r--core/src/com/google/inject/name/NamedImpl.java10
-rw-r--r--core/src/com/google/inject/name/Names.java17
-rw-r--r--core/src/com/google/inject/name/package-info.java6
-rw-r--r--core/src/com/google/inject/package-info.java34
-rw-r--r--core/src/com/google/inject/spi/BindingScopingVisitor.java17
-rw-r--r--core/src/com/google/inject/spi/BindingTargetVisitor.java18
-rw-r--r--core/src/com/google/inject/spi/ConstructorBinding.java13
-rw-r--r--core/src/com/google/inject/spi/ConvertedConstantBinding.java14
-rw-r--r--core/src/com/google/inject/spi/DefaultBindingScopingVisitor.java20
-rw-r--r--core/src/com/google/inject/spi/DefaultBindingTargetVisitor.java20
-rw-r--r--core/src/com/google/inject/spi/DefaultElementVisitor.java40
-rw-r--r--core/src/com/google/inject/spi/Dependency.java24
-rw-r--r--core/src/com/google/inject/spi/DependencyAndSource.java35
-rw-r--r--core/src/com/google/inject/spi/DisableCircularProxiesOption.java5
-rw-r--r--core/src/com/google/inject/spi/Element.java3
-rw-r--r--core/src/com/google/inject/spi/ElementSource.java156
-rw-r--r--core/src/com/google/inject/spi/ElementVisitor.java61
-rw-r--r--core/src/com/google/inject/spi/Elements.java140
-rw-r--r--core/src/com/google/inject/spi/ExposedBinding.java13
-rw-r--r--core/src/com/google/inject/spi/HasDependencies.java4
-rw-r--r--core/src/com/google/inject/spi/InjectionPoint.java361
-rw-r--r--core/src/com/google/inject/spi/InjectionRequest.java17
-rw-r--r--core/src/com/google/inject/spi/InstanceBinding.java8
-rw-r--r--core/src/com/google/inject/spi/InterceptorBinding.java22
-rw-r--r--core/src/com/google/inject/spi/LinkedKeyBinding.java5
-rw-r--r--core/src/com/google/inject/spi/MembersInjectorLookup.java31
-rw-r--r--core/src/com/google/inject/spi/Message.java34
-rw-r--r--core/src/com/google/inject/spi/ModuleAnnotatedMethodScanner.java18
-rw-r--r--core/src/com/google/inject/spi/ModuleAnnotatedMethodScannerBinding.java20
-rw-r--r--core/src/com/google/inject/spi/ModuleSource.java36
-rw-r--r--core/src/com/google/inject/spi/PrivateElements.java11
-rw-r--r--core/src/com/google/inject/spi/ProviderBinding.java4
-rw-r--r--core/src/com/google/inject/spi/ProviderInstanceBinding.java11
-rw-r--r--core/src/com/google/inject/spi/ProviderKeyBinding.java5
-rw-r--r--core/src/com/google/inject/spi/ProviderLookup.java25
-rw-r--r--core/src/com/google/inject/spi/ProviderWithDependencies.java2
-rw-r--r--core/src/com/google/inject/spi/ProviderWithExtensionVisitor.java47
-rw-r--r--core/src/com/google/inject/spi/ProvidesMethodBinding.java21
-rw-r--r--core/src/com/google/inject/spi/ProvidesMethodTargetVisitor.java11
-rw-r--r--core/src/com/google/inject/spi/ProvisionListener.java89
-rw-r--r--core/src/com/google/inject/spi/ProvisionListenerBinding.java18
-rw-r--r--core/src/com/google/inject/spi/RequireAtInjectOnConstructorsOption.java5
-rw-r--r--core/src/com/google/inject/spi/RequireExactBindingAnnotationsOption.java5
-rw-r--r--core/src/com/google/inject/spi/RequireExplicitBindingsOption.java5
-rw-r--r--core/src/com/google/inject/spi/ScopeBinding.java7
-rw-r--r--core/src/com/google/inject/spi/StaticInjectionRequest.java21
-rw-r--r--core/src/com/google/inject/spi/Toolable.java14
-rw-r--r--core/src/com/google/inject/spi/TypeConverter.java4
-rw-r--r--core/src/com/google/inject/spi/TypeConverterBinding.java30
-rw-r--r--core/src/com/google/inject/spi/TypeEncounter.java40
-rw-r--r--core/src/com/google/inject/spi/TypeListener.java16
-rw-r--r--core/src/com/google/inject/spi/TypeListenerBinding.java9
-rw-r--r--core/src/com/google/inject/spi/UntargettedBinding.java2
-rw-r--r--core/src/com/google/inject/spi/package-info.java4
-rw-r--r--core/src/com/google/inject/util/Modules.java155
-rw-r--r--core/src/com/google/inject/util/Providers.java60
-rw-r--r--core/src/com/google/inject/util/Types.java67
-rw-r--r--core/src/com/google/inject/util/package-info.java6
216 files changed, 11194 insertions, 5289 deletions
diff --git a/core/src/com/google/inject/AbstractModule.java b/core/src/com/google/inject/AbstractModule.java
index fafbd121..7fece9f8 100644
--- a/core/src/com/google/inject/AbstractModule.java
+++ b/core/src/com/google/inject/AbstractModule.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,15 +27,13 @@ import com.google.inject.spi.Message;
import com.google.inject.spi.ProvisionListener;
import com.google.inject.spi.TypeConverter;
import com.google.inject.spi.TypeListener;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
- * A support class for {@link Module}s which reduces repetition and results in
- * a more readable configuration. Simply extend this class, implement {@link
- * #configure()}, and call the inherited methods which mirror those found in
- * {@link Binder}. For example:
+ * A support class for {@link Module}s which reduces repetition and results in a more readable
+ * configuration. Simply extend this class, implement {@link #configure()}, and call the inherited
+ * methods which mirror those found in {@link Binder}. For example:
*
* <pre>
* public class MyModule extends AbstractModule {
@@ -54,84 +52,63 @@ public abstract class AbstractModule implements Module {
Binder binder;
+ @Override
public final synchronized void configure(Binder builder) {
checkState(this.binder == null, "Re-entry is not allowed.");
this.binder = checkNotNull(builder, "builder");
try {
configure();
- }
- finally {
+ } finally {
this.binder = null;
}
}
- /**
- * Configures a {@link Binder} via the exposed methods.
- */
- protected abstract void configure();
+ /** Configures a {@link Binder} via the exposed methods. */
+ protected void configure() {}
- /**
- * Gets direct access to the underlying {@code Binder}.
- */
+ /** Gets direct access to the underlying {@code Binder}. */
protected Binder binder() {
checkState(binder != null, "The binder can only be used inside configure()");
return binder;
}
- /**
- * @see Binder#bindScope(Class, Scope)
- */
- protected void bindScope(Class<? extends Annotation> scopeAnnotation,
- Scope scope) {
+ /** @see Binder#bindScope(Class, Scope) */
+ protected void bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope) {
binder().bindScope(scopeAnnotation, scope);
}
- /**
- * @see Binder#bind(Key)
- */
+ /** @see Binder#bind(Key) */
protected <T> LinkedBindingBuilder<T> bind(Key<T> key) {
return binder().bind(key);
}
- /**
- * @see Binder#bind(TypeLiteral)
- */
+ /** @see Binder#bind(TypeLiteral) */
protected <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
return binder().bind(typeLiteral);
}
- /**
- * @see Binder#bind(Class)
- */
+ /** @see Binder#bind(Class) */
protected <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) {
return binder().bind(clazz);
}
- /**
- * @see Binder#bindConstant()
- */
+ /** @see Binder#bindConstant() */
protected AnnotatedConstantBindingBuilder bindConstant() {
return binder().bindConstant();
}
- /**
- * @see Binder#install(Module)
- */
+ /** @see Binder#install(Module) */
protected void install(Module module) {
binder().install(module);
}
- /**
- * @see Binder#addError(String, Object[])
- */
+ /** @see Binder#addError(String, Object[]) */
protected void addError(String message, Object... arguments) {
binder().addError(message, arguments);
}
- /**
- * @see Binder#addError(Throwable)
- */
+ /** @see Binder#addError(Throwable) */
protected void addError(Throwable t) {
binder().addError(t);
}
@@ -152,9 +129,7 @@ public abstract class AbstractModule implements Module {
binder().requestInjection(instance);
}
- /**
- * @see Binder#requestStaticInjection(Class[])
- */
+ /** @see Binder#requestStaticInjection(Class[]) */
protected void requestStaticInjection(Class<?>... types) {
binder().requestStaticInjection(types);
}
@@ -162,10 +137,10 @@ public abstract class AbstractModule implements Module {
/*if[AOP]*/
/**
* @see Binder#bindInterceptor(com.google.inject.matcher.Matcher,
- * com.google.inject.matcher.Matcher,
- * org.aopalliance.intercept.MethodInterceptor[])
+ * com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[])
*/
- protected void bindInterceptor(Matcher<? super Class<?>> classMatcher,
+ protected void bindInterceptor(
+ Matcher<? super Class<?>> classMatcher,
Matcher<? super Method> methodMatcher,
org.aopalliance.intercept.MethodInterceptor... interceptors) {
binder().bindInterceptor(classMatcher, methodMatcher, interceptors);
@@ -173,10 +148,9 @@ public abstract class AbstractModule implements Module {
/*end[AOP]*/
/**
- * Adds a dependency from this module to {@code key}. When the injector is
- * created, Guice will report an error if {@code key} cannot be injected.
- * Note that this requirement may be satisfied by implicit binding, such as
- * a public no-arguments constructor.
+ * Adds a dependency from this module to {@code key}. When the injector is created, Guice will
+ * report an error if {@code key} cannot be injected. Note that this requirement may be satisfied
+ * by implicit binding, such as a public no-arguments constructor.
*
* @since 2.0
*/
@@ -185,10 +159,9 @@ public abstract class AbstractModule implements Module {
}
/**
- * Adds a dependency from this module to {@code type}. When the injector is
- * created, Guice will report an error if {@code type} cannot be injected.
- * Note that this requirement may be satisfied by implicit binding, such as
- * a public no-arguments constructor.
+ * Adds a dependency from this module to {@code type}. When the injector is created, Guice will
+ * report an error if {@code type} cannot be injected. Note that this requirement may be satisfied
+ * by implicit binding, such as a public no-arguments constructor.
*
* @since 2.0
*/
@@ -216,13 +189,13 @@ public abstract class AbstractModule implements Module {
* @see Binder#convertToTypes
* @since 2.0
*/
- protected void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
- TypeConverter converter) {
+ protected void convertToTypes(
+ Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter) {
binder().convertToTypes(typeMatcher, converter);
}
/**
- * @see Binder#currentStage()
+ * @see Binder#currentStage()
* @since 2.0
*/
protected Stage currentStage() {
@@ -246,21 +219,19 @@ public abstract class AbstractModule implements Module {
}
/**
- * @see Binder#bindListener(com.google.inject.matcher.Matcher,
- * com.google.inject.spi.TypeListener)
+ * @see Binder#bindListener(com.google.inject.matcher.Matcher, com.google.inject.spi.TypeListener)
* @since 2.0
*/
- protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
- TypeListener listener) {
+ protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener) {
binder().bindListener(typeMatcher, listener);
}
-
+
/**
* @see Binder#bindListener(Matcher, ProvisionListener...)
* @since 4.0
*/
- protected void bindListener(Matcher<? super Binding<?>> bindingMatcher,
- ProvisionListener... listener) {
+ protected void bindListener(
+ Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listener) {
binder().bindListener(bindingMatcher, listener);
}
}
diff --git a/core/src/com/google/inject/Binder.java b/core/src/com/google/inject/Binder.java
index e930c3be..e3fab865 100644
--- a/core/src/com/google/inject/Binder.java
+++ b/core/src/com/google/inject/Binder.java
@@ -26,129 +26,111 @@ import com.google.inject.spi.ModuleAnnotatedMethodScanner;
import com.google.inject.spi.ProvisionListener;
import com.google.inject.spi.TypeConverter;
import com.google.inject.spi.TypeListener;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
/**
- * Collects configuration information (primarily <i>bindings</i>) which will be
- * used to create an {@link Injector}. Guice provides this object to your
- * application's {@link Module} implementors so they may each contribute
- * their own bindings and other registrations.
+ * Collects configuration information (primarily <i>bindings</i>) which will be used to create an
+ * {@link Injector}. Guice provides this object to your application's {@link Module} implementors so
+ * they may each contribute their own bindings and other registrations.
*
* <h3>The Guice Binding EDSL</h3>
*
- * Guice uses an <i>embedded domain-specific language</i>, or EDSL, to help you
- * create bindings simply and readably. This approach is great for overall
- * usability, but it does come with a small cost: <b>it is difficult to
- * learn how to use the Binding EDSL by reading
- * method-level javadocs</b>. Instead, you should consult the series of
- * examples below. To save space, these examples omit the opening
- * {@code binder}, just as you will if your module extends
- * {@link AbstractModule}.
+ * Guice uses an <i>embedded domain-specific language</i>, or EDSL, to help you create bindings
+ * simply and readably. This approach is great for overall usability, but it does come with a small
+ * cost: <b>it is difficult to learn how to use the Binding EDSL by reading method-level
+ * javadocs</b>. Instead, you should consult the series of examples below. To save space, these
+ * examples omit the opening {@code binder}, just as you will if your module extends {@link
+ * AbstractModule}.
*
* <pre>
* bind(ServiceImpl.class);</pre>
*
- * This statement does essentially nothing; it "binds the {@code ServiceImpl}
- * class to itself" and does not change Guice's default behavior. You may still
- * want to use this if you prefer your {@link Module} class to serve as an
- * explicit <i>manifest</i> for the services it provides. Also, in rare cases,
- * Guice may be unable to validate a binding at injector creation time unless it
- * is given explicitly.
+ * This statement does essentially nothing; it "binds the {@code ServiceImpl} class to itself" and
+ * does not change Guice's default behavior. You may still want to use this if you prefer your
+ * {@link Module} class to serve as an explicit <i>manifest</i> for the services it provides. Also,
+ * in rare cases, Guice may be unable to validate a binding at injector creation time unless it is
+ * given explicitly.
*
* <pre>
* bind(Service.class).to(ServiceImpl.class);</pre>
*
- * Specifies that a request for a {@code Service} instance with no binding
- * annotations should be treated as if it were a request for a
- * {@code ServiceImpl} instance. This <i>overrides</i> the function of any
- * {@link ImplementedBy @ImplementedBy} or {@link ProvidedBy @ProvidedBy}
- * annotations found on {@code Service}, since Guice will have already
- * "moved on" to {@code ServiceImpl} before it reaches the point when it starts
- * looking for these annotations.
+ * Specifies that a request for a {@code Service} instance with no binding annotations should be
+ * treated as if it were a request for a {@code ServiceImpl} instance. This <i>overrides</i> the
+ * function of any {@link ImplementedBy @ImplementedBy} or {@link ProvidedBy @ProvidedBy}
+ * annotations found on {@code Service}, since Guice will have already "moved on" to {@code
+ * ServiceImpl} before it reaches the point when it starts looking for these annotations.
*
* <pre>
* bind(Service.class).toProvider(ServiceProvider.class);</pre>
*
- * In this example, {@code ServiceProvider} must extend or implement
- * {@code Provider<Service>}. This binding specifies that Guice should resolve
- * an unannotated injection request for {@code Service} by first resolving an
- * instance of {@code ServiceProvider} in the regular way, then calling
- * {@link Provider#get get()} on the resulting Provider instance to obtain the
- * {@code Service} instance.
+ * In this example, {@code ServiceProvider} must extend or implement {@code Provider<Service>}. This
+ * binding specifies that Guice should resolve an unannotated injection request for {@code Service}
+ * by first resolving an instance of {@code ServiceProvider} in the regular way, then calling {@link
+ * Provider#get get()} on the resulting Provider instance to obtain the {@code Service} instance.
*
- * <p>The {@link Provider} you use here does not have to be a "factory"; that
- * is, a provider which always <i>creates</i> each instance it provides.
- * However, this is generally a good practice to follow. You can then use
- * Guice's concept of {@link Scope scopes} to guide when creation should happen
- * -- "letting Guice work for you".
+ * <p>The {@link Provider} you use here does not have to be a "factory"; that is, a provider which
+ * always <i>creates</i> each instance it provides. However, this is generally a good practice to
+ * follow. You can then use Guice's concept of {@link Scope scopes} to guide when creation should
+ * happen -- "letting Guice work for you".
*
* <pre>
* bind(Service.class).annotatedWith(Red.class).to(ServiceImpl.class);</pre>
*
- * Like the previous example, but only applies to injection requests that use
- * the binding annotation {@code @Red}. If your module also includes bindings
- * for particular <i>values</i> of the {@code @Red} annotation (see below),
- * then this binding will serve as a "catch-all" for any values of {@code @Red}
- * that have no exact match in the bindings.
- *
+ * Like the previous example, but only applies to injection requests that use the binding annotation
+ * {@code @Red}. If your module also includes bindings for particular <i>values</i> of the
+ * {@code @Red} annotation (see below), then this binding will serve as a "catch-all" for any values
+ * of {@code @Red} that have no exact match in the bindings.
+ *
* <pre>
* bind(ServiceImpl.class).in(Singleton.class);
* // or, alternatively
* bind(ServiceImpl.class).in(Scopes.SINGLETON);</pre>
*
- * Either of these statements places the {@code ServiceImpl} class into
- * singleton scope. Guice will create only one instance of {@code ServiceImpl}
- * and will reuse it for all injection requests of this type. Note that it is
- * still possible to bind another instance of {@code ServiceImpl} if the second
- * binding is qualified by an annotation as in the previous example. Guice is
- * not overly concerned with <i>preventing</i> you from creating multiple
- * instances of your "singletons", only with <i>enabling</i> your application to
- * share only one instance if that's all you tell Guice you need.
- *
- * <p><b>Note:</b> a scope specified in this way <i>overrides</i> any scope that
- * was specified with an annotation on the {@code ServiceImpl} class.
- *
- * <p>Besides {@link Singleton}/{@link Scopes#SINGLETON}, there are
- * servlet-specific scopes available in
- * {@code com.google.inject.servlet.ServletScopes}, and your Modules can
- * contribute their own custom scopes for use here as well.
+ * Either of these statements places the {@code ServiceImpl} class into singleton scope. Guice will
+ * create only one instance of {@code ServiceImpl} and will reuse it for all injection requests of
+ * this type. Note that it is still possible to bind another instance of {@code ServiceImpl} if the
+ * second binding is qualified by an annotation as in the previous example. Guice is not overly
+ * concerned with <i>preventing</i> you from creating multiple instances of your "singletons", only
+ * with <i>enabling</i> your application to share only one instance if that's all you tell Guice you
+ * need.
+ *
+ * <p><b>Note:</b> a scope specified in this way <i>overrides</i> any scope that was specified with
+ * an annotation on the {@code ServiceImpl} class.
+ *
+ * <p>Besides {@link Singleton}/{@link Scopes#SINGLETON}, there are servlet-specific scopes
+ * available in {@code com.google.inject.servlet.ServletScopes}, and your Modules can contribute
+ * their own custom scopes for use here as well.
*
* <pre>
* bind(new TypeLiteral&lt;PaymentService&lt;CreditCard>>() {})
* .to(CreditCardPaymentService.class);</pre>
*
- * This admittedly odd construct is the way to bind a parameterized type. It
- * tells Guice how to honor an injection request for an element of type
- * {@code PaymentService<CreditCard>}. The class
- * {@code CreditCardPaymentService} must implement the
- * {@code PaymentService<CreditCard>} interface. Guice cannot currently bind or
- * inject a generic type, such as {@code Set<E>}; all type parameters must be
- * fully specified.
+ * This admittedly odd construct is the way to bind a parameterized type. It tells Guice how to
+ * honor an injection request for an element of type {@code PaymentService<CreditCard>}. The class
+ * {@code CreditCardPaymentService} must implement the {@code PaymentService<CreditCard>} interface.
+ * Guice cannot currently bind or inject a generic type, such as {@code Set<E>}; all type parameters
+ * must be fully specified.
*
* <pre>
* bind(Service.class).toInstance(new ServiceImpl());
* // or, alternatively
* bind(Service.class).toInstance(SomeLegacyRegistry.getService());</pre>
*
- * In this example, your module itself, <i>not Guice</i>, takes responsibility
- * for obtaining a {@code ServiceImpl} instance, then asks Guice to always use
- * this single instance to fulfill all {@code Service} injection requests. When
- * the {@link Injector} is created, it will automatically perform field
- * and method injection for this instance, but any injectable constructor on
- * {@code ServiceImpl} is simply ignored. Note that using this approach results
- * in "eager loading" behavior that you can't control.
+ * In this example, your module itself, <i>not Guice</i>, takes responsibility for obtaining a
+ * {@code ServiceImpl} instance, then asks Guice to always use this single instance to fulfill all
+ * {@code Service} injection requests. When the {@link Injector} is created, it will automatically
+ * perform field and method injection for this instance, but any injectable constructor on {@code
+ * ServiceImpl} is simply ignored. Note that using this approach results in "eager loading" behavior
+ * that you can't control.
*
* <pre>
* bindConstant().annotatedWith(ServerHost.class).to(args[0]);</pre>
*
- * Sets up a constant binding. Constant injections must always be annotated.
- * When a constant binding's value is a string, it is eligile for conversion to
- * all primitive types, to {@link Enum#valueOf(Class, String) all enums}, and to
- * {@link Class#forName class literals}. Conversions for other types can be
- * configured using {@link #convertToTypes(Matcher, TypeConverter)
+ * Sets up a constant binding. Constant injections must always be annotated. When a constant
+ * binding's value is a string, it is eligile for conversion to all primitive types, to {@link
+ * Enum#valueOf(Class, String) all enums}, and to {@link Class#forName class literals}. Conversions
+ * for other types can be configured using {@link #convertToTypes(Matcher, TypeConverter)
* convertToTypes()}.
*
* <pre>
@@ -157,46 +139,42 @@ import java.lang.reflect.Proxy;
* red = MyModule.class.getDeclaredField("red").getAnnotation(Color.class);
* bind(Service.class).annotatedWith(red).to(RedService.class);</pre>
*
- * If your binding annotation has parameters you can apply different bindings to
- * different specific values of your annotation. Getting your hands on the
- * right instance of the annotation is a bit of a pain -- one approach, shown
- * above, is to apply a prototype annotation to a field in your module class, so
- * that you can read this annotation instance and give it to Guice.
+ * If your binding annotation has parameters you can apply different bindings to different specific
+ * values of your annotation. Getting your hands on the right instance of the annotation is a bit of
+ * a pain -- one approach, shown above, is to apply a prototype annotation to a field in your module
+ * class, so that you can read this annotation instance and give it to Guice.
*
* <pre>
* bind(Service.class)
* .annotatedWith(Names.named("blue"))
* .to(BlueService.class);</pre>
*
- * Differentiating by names is a common enough use case that we provided a
- * standard annotation, {@link com.google.inject.name.Named @Named}. Because of
- * Guice's library support, binding by name is quite easier than in the
- * arbitrary binding annotation case we just saw. However, remember that these
- * names will live in a single flat namespace with all the other names used in
- * your application.
+ * Differentiating by names is a common enough use case that we provided a standard annotation,
+ * {@link com.google.inject.name.Named @Named}. Because of Guice's library support, binding by name
+ * is quite easier than in the arbitrary binding annotation case we just saw. However, remember that
+ * these names will live in a single flat namespace with all the other names used in your
+ * application.
*
* <pre>
* Constructor<T> loneCtor = getLoneCtorFromServiceImplViaReflection();
* bind(ServiceImpl.class)
* .toConstructor(loneCtor);</pre>
*
- * In this example, we directly tell Guice which constructor to use in a concrete
- * class implementation. It means that we do not need to place {@literal @}Inject
- * on any of the constructors and that Guice treats the provided constructor as though
- * it were annotated so. It is useful for cases where you cannot modify existing
- * classes and is a bit simpler than using a {@link Provider}.
- *
- * <p>The above list of examples is far from exhaustive. If you can think of
- * how the concepts of one example might coexist with the concepts from another,
- * you can most likely weave the two together. If the two concepts make no
- * sense with each other, you most likely won't be able to do it. In a few
- * cases Guice will let something bogus slip by, and will then inform you of
- * the problems at runtime, as soon as you try to create your Injector.
- *
- * <p>The other methods of Binder such as {@link #bindScope},
- * {@link #bindInterceptor}, {@link #install}, {@link #requestStaticInjection},
- * {@link #addError} and {@link #currentStage} are not part of the Binding EDSL;
- * you can learn how to use these in the usual way, from the method
+ * In this example, we directly tell Guice which constructor to use in a concrete class
+ * implementation. It means that we do not need to place {@literal @}Inject on any of the
+ * constructors and that Guice treats the provided constructor as though it were annotated so. It is
+ * useful for cases where you cannot modify existing classes and is a bit simpler than using a
+ * {@link Provider}.
+ *
+ * <p>The above list of examples is far from exhaustive. If you can think of how the concepts of one
+ * example might coexist with the concepts from another, you can most likely weave the two together.
+ * If the two concepts make no sense with each other, you most likely won't be able to do it. In a
+ * few cases Guice will let something bogus slip by, and will then inform you of the problems at
+ * runtime, as soon as you try to create your Injector.
+ *
+ * <p>The other methods of Binder such as {@link #bindScope}, {@link #bindInterceptor}, {@link
+ * #install}, {@link #requestStaticInjection}, {@link #addError} and {@link #currentStage} are not
+ * part of the Binding EDSL; you can learn how to use these in the usual way, from the method
* documentation.
*
* @author crazybob@google.com (Bob Lee)
@@ -211,51 +189,41 @@ public interface Binder {
* eligible for interception if:
*
* <ul>
- * <li>Guice created the instance the method is on</li>
- * <li>Neither the enclosing type nor the method is final</li>
- * <li>And the method is package-private, protected, or public</li>
+ * <li>Guice created the instance the method is on
+ * <li>Neither the enclosing type nor the method is final
+ * <li>And the method is package-private, protected, or public
* </ul>
*
- * @param classMatcher matches classes the interceptor should apply to. For
- * example: {@code only(Runnable.class)}.
- * @param methodMatcher matches methods the interceptor should apply to. For
- * example: {@code annotatedWith(Transactional.class)}.
- * @param interceptors to bind. The interceptors are called in the order they
- * are given.
+ * @param classMatcher matches classes the interceptor should apply to. For example: {@code
+ * only(Runnable.class)}.
+ * @param methodMatcher matches methods the interceptor should apply to. For example: {@code
+ * annotatedWith(Transactional.class)}.
+ * @param interceptors to bind. The interceptors are called in the order they are given.
*/
- void bindInterceptor(Matcher<? super Class<?>> classMatcher,
+ void bindInterceptor(
+ Matcher<? super Class<?>> classMatcher,
Matcher<? super Method> methodMatcher,
org.aopalliance.intercept.MethodInterceptor... interceptors);
/*end[AOP]*/
- /**
- * Binds a scope to an annotation.
- */
+ /** Binds a scope to an annotation. */
void bindScope(Class<? extends Annotation> annotationType, Scope scope);
- /**
- * See the EDSL examples at {@link Binder}.
- */
+ /** See the EDSL examples at {@link Binder}. */
<T> LinkedBindingBuilder<T> bind(Key<T> key);
- /**
- * See the EDSL examples at {@link Binder}.
- */
+ /** See the EDSL examples at {@link Binder}. */
<T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral);
- /**
- * See the EDSL examples at {@link Binder}.
- */
+ /** See the EDSL examples at {@link Binder}. */
<T> AnnotatedBindingBuilder<T> bind(Class<T> type);
- /**
- * See the EDSL examples at {@link Binder}.
- */
+ /** See the EDSL examples at {@link Binder}. */
AnnotatedConstantBindingBuilder bindConstant();
/**
- * Upon successful creation, the {@link Injector} will inject instance fields
- * and methods of the given object.
+ * Upon successful creation, the {@link Injector} will inject instance fields and methods of the
+ * given object.
*
* @param type of instance
* @param instance for which members will be injected
@@ -264,8 +232,8 @@ public interface Binder {
<T> void requestInjection(TypeLiteral<T> type, T instance);
/**
- * Upon successful creation, the {@link Injector} will inject instance fields
- * and methods of the given object.
+ * Upon successful creation, the {@link Injector} will inject instance fields and methods of the
+ * given object.
*
* @param instance for which members will be injected
* @since 2.0
@@ -273,37 +241,30 @@ public interface Binder {
void requestInjection(Object instance);
/**
- * Upon successful creation, the {@link Injector} will inject static fields
- * and methods in the given classes.
+ * Upon successful creation, the {@link Injector} will inject static fields and methods in the
+ * given classes.
*
* @param types for which static members will be injected
*/
void requestStaticInjection(Class<?>... types);
- /**
- * Uses the given module to configure more bindings.
- */
+ /** Uses the given module to configure more bindings. */
void install(Module module);
- /**
- * Gets the current stage.
- */
+ /** Gets the current stage. */
Stage currentStage();
/**
- * Records an error message which will be presented to the user at a later
- * time. Unlike throwing an exception, this enable us to continue
- * configuring the Injector and discover more errors. Uses {@link
- * String#format(String, Object[])} to insert the arguments into the
- * message.
+ * Records an error message which will be presented to the user at a later time. Unlike throwing
+ * an exception, this enable us to continue configuring the Injector and discover more errors.
+ * Uses {@link String#format(String, Object[])} to insert the arguments into the message.
*/
void addError(String message, Object... arguments);
/**
- * Records an exception, the full details of which will be logged, and the
- * message of which will be presented to the user at a later
- * time. If your Module calls something that you worry may fail, you should
- * catch the exception and pass it into this.
+ * Records an exception, the full details of which will be logged, and the message of which will
+ * be presented to the user at a later time. If your Module calls something that you worry may
+ * fail, you should catch the exception and pass it into this.
*/
void addError(Throwable t);
@@ -315,32 +276,29 @@ public interface Binder {
void addError(Message message);
/**
- * Returns the provider used to obtain instances for the given injection key.
- * The returned provider will not be valid until the {@link Injector} has been
- * created. The provider will throw an {@code IllegalStateException} if you
- * try to use it beforehand.
+ * Returns the provider used to obtain instances for the given injection key. The returned
+ * provider will not be valid until the {@link Injector} has been created. The provider will throw
+ * an {@code IllegalStateException} if you try to use it beforehand.
*
* @since 2.0
*/
<T> Provider<T> getProvider(Key<T> key);
/**
- * Returns the provider used to obtain instances for the given injection key.
- * The returned provider will be attached to the injection point and will
- * follow the nullability specified in the dependency.
- * Additionally, the returned provider will not be valid until the {@link Injector}
- * has been created. The provider will throw an {@code IllegalStateException} if you
- * try to use it beforehand.
+ * Returns the provider used to obtain instances for the given injection key. The returned
+ * provider will be attached to the injection point and will follow the nullability specified in
+ * the dependency. Additionally, the returned provider will not be valid until the {@link
+ * Injector} has been created. The provider will throw an {@code IllegalStateException} if you try
+ * to use it beforehand.
*
* @since 4.0
*/
<T> Provider<T> getProvider(Dependency<T> dependency);
/**
- * Returns the provider used to obtain instances for the given injection type.
- * The returned provider will not be valid until the {@link Injector} has been
- * created. The provider will throw an {@code IllegalStateException} if you
- * try to use it beforehand.
+ * Returns the provider used to obtain instances for the given injection type. The returned
+ * provider will not be valid until the {@link Injector} has been created. The provider will throw
+ * an {@code IllegalStateException} if you try to use it beforehand.
*
* @since 2.0
*/
@@ -369,15 +327,14 @@ public interface Binder {
<T> MembersInjector<T> getMembersInjector(Class<T> type);
/**
- * Binds a type converter. The injector will use the given converter to
- * convert string constants to matching types as needed.
+ * Binds a type converter. The injector will use the given converter to convert string constants
+ * to matching types as needed.
*
* @param typeMatcher matches types the converter can handle
* @param converter converts values
* @since 2.0
*/
- void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
- TypeConverter converter);
+ void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter);
/**
* Registers a listener for injectable types. Guice will notify the listener when it encounters
@@ -387,43 +344,38 @@ public interface Binder {
* @param listener for injectable types matched by typeMatcher
* @since 2.0
*/
- void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
- TypeListener listener);
+ void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener);
/**
- * Registers listeners for provisioned objects. Guice will notify the
- * listeners just before and after the object is provisioned. Provisioned
- * objects that are also injectable (everything except objects provided
- * through Providers) can also be notified through TypeListeners registered in
- * {@link #bindListener}.
- *
- * @param bindingMatcher that matches bindings of provisioned objects the listener
- * should be notified of
- * @param listeners for provisioned objects matched by bindingMatcher
+ * Registers listeners for provisioned objects. Guice will notify the listeners just before and
+ * after the object is provisioned. Provisioned objects that are also injectable (everything
+ * except objects provided through Providers) can also be notified through TypeListeners
+ * registered in {@link #bindListener}.
+ *
+ * @param bindingMatcher that matches bindings of provisioned objects the listener should be
+ * notified of
+ * @param listeners for provisioned objects matched by bindingMatcher
* @since 4.0
*/
void bindListener(Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listeners);
/**
- * Returns a binder that uses {@code source} as the reference location for
- * configuration errors. This is typically a {@link StackTraceElement}
- * for {@code .java} source but it could any binding source, such as the
- * path to a {@code .properties} file.
+ * Returns a binder that uses {@code source} as the reference location for configuration errors.
+ * This is typically a {@link StackTraceElement} for {@code .java} source but it could any binding
+ * source, such as the path to a {@code .properties} file.
*
- * @param source any object representing the source location and has a
- * concise {@link Object#toString() toString()} value
+ * @param source any object representing the source location and has a concise {@link
+ * Object#toString() toString()} value
* @return a binder that shares its configuration with this binder
* @since 2.0
*/
Binder withSource(Object source);
/**
- * Returns a binder that skips {@code classesToSkip} when identify the
- * calling code. The caller's {@link StackTraceElement} is used to locate
- * the source of configuration errors.
+ * Returns a binder that skips {@code classesToSkip} when identify the calling code. The caller's
+ * {@link StackTraceElement} is used to locate the source of configuration errors.
*
- * @param classesToSkip library classes that create bindings on behalf of
- * their clients.
+ * @param classesToSkip library classes that create bindings on behalf of their clients.
* @return a binder that shares its configuration with this binder.
* @since 2.0
*/
@@ -435,75 +387,69 @@ public interface Binder {
* PrivateModule} for details.
*
* @return a binder that inherits configuration from this binder. Only exposed configuration on
- * the returned binder will be visible to this binder.
+ * the returned binder will be visible to this binder.
* @since 2.0
*/
PrivateBinder newPrivateBinder();
/**
- * Instructs the Injector that bindings must be listed in a Module in order to
- * be injected. Classes that are not explicitly bound in a module cannot be
- * injected. Bindings created through a linked binding
- * (<code>bind(Foo.class).to(FooImpl.class)</code>) are allowed, but the
- * implicit binding (<code>FooImpl</code>) cannot be directly injected unless
- * it is also explicitly bound (<code>bind(FooImpl.class)</code>).
- * <p>
- * Tools can still retrieve bindings for implicit bindings (bindings created
- * through a linked binding) if explicit bindings are required, however
- * {@link Binding#getProvider} will fail.
- * <p>
- * By default, explicit bindings are not required.
- * <p>
- * If a parent injector requires explicit bindings, then all child injectors
- * (and private modules within that injector) also require explicit bindings.
- * If a parent does not require explicit bindings, a child injector or private
- * module may optionally declare itself as requiring explicit bindings. If it
- * does, the behavior is limited only to that child or any grandchildren. No
- * siblings of the child will require explicit bindings.
- * <p>
- * In the absence of an explicit binding for the target, linked bindings in
- * child injectors create a binding for the target in the parent. Since this
- * behavior can be surprising, it causes an error instead if explicit bindings
- * are required. To avoid this error, add an explicit binding for the target,
- * either in the child or the parent.
- *
+ * Instructs the Injector that bindings must be listed in a Module in order to be injected.
+ * Classes that are not explicitly bound in a module cannot be injected. Bindings created through
+ * a linked binding (<code>bind(Foo.class).to(FooImpl.class)</code>) are allowed, but the implicit
+ * binding (<code>FooImpl</code>) cannot be directly injected unless it is also explicitly bound (
+ * <code>bind(FooImpl.class)</code>).
+ *
+ * <p>Tools can still retrieve bindings for implicit bindings (bindings created through a linked
+ * binding) if explicit bindings are required, however {@link Binding#getProvider} will fail.
+ *
+ * <p>By default, explicit bindings are not required.
+ *
+ * <p>If a parent injector requires explicit bindings, then all child injectors (and private
+ * modules within that injector) also require explicit bindings. If a parent does not require
+ * explicit bindings, a child injector or private module may optionally declare itself as
+ * requiring explicit bindings. If it does, the behavior is limited only to that child or any
+ * grandchildren. No siblings of the child will require explicit bindings.
+ *
+ * <p>In the absence of an explicit binding for the target, linked bindings in child injectors
+ * create a binding for the target in the parent. Since this behavior can be surprising, it causes
+ * an error instead if explicit bindings are required. To avoid this error, add an explicit
+ * binding for the target, either in the child or the parent.
+ *
* @since 3.0
*/
void requireExplicitBindings();
-
+
/**
- * Prevents Guice from constructing a {@link Proxy} when a circular dependency
- * is found. By default, circular proxies are not disabled.
- * <p>
- * If a parent injector disables circular proxies, then all child injectors
- * (and private modules within that injector) also disable circular proxies.
- * If a parent does not disable circular proxies, a child injector or private
- * module may optionally declare itself as disabling circular proxies. If it
- * does, the behavior is limited only to that child or any grandchildren. No
- * siblings of the child will disable circular proxies.
- *
+ * Prevents Guice from injecting dependencies that form a cycle, unless broken by a {@link
+ * Provider}. By default, circular dependencies are not disabled.
+ *
+ * <p>If a parent injector disables circular dependencies, then all child injectors (and private
+ * modules within that injector) also disable circular dependencies. If a parent does not disable
+ * circular dependencies, a child injector or private module may optionally declare itself as
+ * disabling circular dependencies. If it does, the behavior is limited only to that child or any
+ * grandchildren. No siblings of the child will disable circular dependencies.
+ *
* @since 3.0
*/
void disableCircularProxies();
-
+
/**
* Requires that a {@literal @}{@link Inject} annotation exists on a constructor in order for
* Guice to consider it an eligible injectable class. By default, Guice will inject classes that
* have a no-args constructor if no {@literal @}{@link Inject} annotation exists on any
* constructor.
- * <p>
- * If the class is bound using {@link LinkedBindingBuilder#toConstructor}, Guice will still inject
- * that constructor regardless of annotations.
+ *
+ * <p>If the class is bound using {@link LinkedBindingBuilder#toConstructor}, Guice will still
+ * inject that constructor regardless of annotations.
*
* @since 4.0
*/
void requireAtInjectOnConstructors();
/**
- * Requires that Guice finds an exactly matching binding annotation. This disables the
- * error-prone feature in Guice where it can substitute a binding for
- * <code>{@literal @}Named Foo</code> when attempting to inject
- * <code>{@literal @}Named("foo") Foo</code>.
+ * Requires that Guice finds an exactly matching binding annotation. This disables the error-prone
+ * feature in Guice where it can substitute a binding for <code>{@literal @}Named Foo</code> when
+ * attempting to inject <code>{@literal @}Named("foo") Foo</code>.
*
* @since 4.0
*/
diff --git a/core/src/com/google/inject/Binding.java b/core/src/com/google/inject/Binding.java
index 332237e6..caf52f0a 100644
--- a/core/src/com/google/inject/Binding.java
+++ b/core/src/com/google/inject/Binding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,55 +22,50 @@ import com.google.inject.spi.Element;
/**
* A mapping from a key (type and optional annotation) to the strategy for getting instances of the
- * type. This interface is part of the introspection API and is intended primarily for use by
- * tools.
+ * type. This interface is part of the introspection API and is intended primarily for use by tools.
*
* <p>Bindings are created in several ways:
+ *
* <ul>
- * <li>Explicitly in a module, via {@code bind()} and {@code bindConstant()}
- * statements:
- * <pre>
+ * <li>Explicitly in a module, via {@code bind()} and {@code bindConstant()} statements:
+ * <pre>
* bind(Service.class).annotatedWith(Red.class).to(ServiceImpl.class);
- * bindConstant().annotatedWith(ServerHost.class).to(args[0]);</pre></li>
- * <li>Implicitly by the Injector by following a type's {@link ImplementedBy
- * pointer} {@link ProvidedBy annotations} or by using its {@link Inject annotated} or
- * default constructor.</li>
- * <li>By converting a bound instance to a different type.</li>
- * <li>For {@link Provider providers}, by delegating to the binding for the provided type.</li>
- * </ul>
+ * bindConstant().annotatedWith(ServerHost.class).to(args[0]);</pre>
*
+ * <li>Implicitly by the Injector by following a type's {@link ImplementedBy pointer} {@link
+ * ProvidedBy annotations} or by using its {@link Inject annotated} or default constructor.
+ * <li>By converting a bound instance to a different type.
+ * <li>For {@link Provider providers}, by delegating to the binding for the provided type.
+ * </ul>
*
* <p>They exist on both modules and on injectors, and their behaviour is different for each:
+ *
* <ul>
- * <li><strong>Module bindings</strong> are incomplete and cannot be used to provide instances.
- * This is because the applicable scopes and interceptors may not be known until an injector
- * is created. From a tool's perspective, module bindings are like the injector's source
- * code. They can be inspected or rewritten, but this analysis must be done statically.</li>
- * <li><strong>Injector bindings</strong> are complete and valid and can be used to provide
- * instances. From a tools' perspective, injector bindings are like reflection for an
- * injector. They have full runtime information, including the complete graph of injections
- * necessary to satisfy a binding.</li>
+ * <li><strong>Module bindings</strong> are incomplete and cannot be used to provide instances. This
+ * is because the applicable scopes and interceptors may not be known until an injector is
+ * created. From a tool's perspective, module bindings are like the injector's source code. They
+ * can be inspected or rewritten, but this analysis must be done statically.
+ * <li><strong>Injector bindings</strong> are complete and valid and can be used to provide
+ * instances. From a tools' perspective, injector bindings are like reflection for an injector.
+ * They have full runtime information, including the complete graph of injections necessary to
+ * satisfy a binding.
* </ul>
*
* @param <T> the bound type. The injected is always assignable to this type.
- *
* @author crazybob@google.com (Bob Lee)
* @author jessewilson@google.com (Jesse Wilson)
*/
public interface Binding<T> extends Element {
- /**
- * Returns the key for this binding.
- */
+ /** Returns the key for this binding. */
Key<T> getKey();
/**
- * Returns the scoped provider guice uses to fulfill requests for this
- * binding.
+ * Returns the scoped provider guice uses to fulfill requests for this binding.
*
- * @throws UnsupportedOperationException when invoked on a {@link Binding}
- * created via {@link com.google.inject.spi.Elements#getElements}. This
- * method is only supported on {@link Binding}s returned from an injector.
+ * @throws UnsupportedOperationException when invoked on a {@link Binding} created via {@link
+ * com.google.inject.spi.Elements#getElements}. This method is only supported on {@link
+ * Binding}s returned from an injector.
*/
Provider<T> getProvider();
diff --git a/core/src/com/google/inject/BindingAnnotation.java b/core/src/com/google/inject/BindingAnnotation.java
index 2d373e43..5a2050e9 100644
--- a/core/src/com/google/inject/BindingAnnotation.java
+++ b/core/src/com/google/inject/BindingAnnotation.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,9 +23,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
- * Annotates annotations which are used for binding. Only one such annotation
- * may apply to a single injection point. You must also annotate binder
- * annotations with {@code @Retention(RUNTIME)}. For example:
+ * Annotates annotations which are used for binding. Only one such annotation may apply to a single
+ * injection point. You must also annotate binder annotations with {@code @Retention(RUNTIME)}. For
+ * example:
*
* <pre>
* {@code @}Retention(RUNTIME)
diff --git a/core/src/com/google/inject/ConfigurationException.java b/core/src/com/google/inject/ConfigurationException.java
index e298cff8..3d3b73cc 100644
--- a/core/src/com/google/inject/ConfigurationException.java
+++ b/core/src/com/google/inject/ConfigurationException.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,8 @@ package com.google.inject;
import static com.google.common.base.Preconditions.checkState;
-import com.google.common.collect.ImmutableSet;
-import com.google.inject.internal.Errors;
+import com.google.inject.internal.Messages;
import com.google.inject.spi.Message;
-
import java.util.Collection;
/**
@@ -33,13 +31,13 @@ import java.util.Collection;
*/
public final class ConfigurationException extends RuntimeException {
- private final ImmutableSet<Message> messages;
+ private final com.google.common.collect.ImmutableSet<Message> messages;
private Object partialValue = null;
/** Creates a ConfigurationException containing {@code messages}. */
public ConfigurationException(Iterable<Message> messages) {
- this.messages = ImmutableSet.copyOf(messages);
- initCause(Errors.getOnlyCause(this.messages));
+ this.messages = com.google.common.collect.ImmutableSet.copyOf(messages);
+ initCause(Messages.getOnlyCause(this.messages));
}
/** Returns a copy of this configuration exception with the specified partial value. */
@@ -57,20 +55,23 @@ public final class ConfigurationException extends RuntimeException {
}
/**
- * Returns a value that was only partially computed due to this exception. The caller can use
- * this while collecting additional configuration problems.
+ * Returns a value that was only partially computed due to this exception. The caller can use this
+ * while collecting additional configuration problems.
*
* @return the partial value, or {@code null} if none was set. The type of the partial value is
- * specified by the throwing method.
+ * specified by the throwing method.
*/
- @SuppressWarnings("unchecked") // this is *extremely* unsafe. We trust the caller here.
+ @SuppressWarnings({
+ "unchecked",
+ "TypeParameterUnusedInFormals"
+ }) // this is *extremely* unsafe. We trust the caller here.
public <E> E getPartialValue() {
return (E) partialValue;
}
@Override public String getMessage() {
- return Errors.format("Guice configuration errors", messages);
+ return Messages.formatMessages("Guice configuration errors", messages);
}
private static final long serialVersionUID = 0;
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/CreationException.java b/core/src/com/google/inject/CreationException.java
index 4f84c22c..38e82819 100644
--- a/core/src/com/google/inject/CreationException.java
+++ b/core/src/com/google/inject/CreationException.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,9 +19,8 @@ package com.google.inject;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.collect.ImmutableSet;
-import com.google.inject.internal.Errors;
+import com.google.inject.internal.Messages;
import com.google.inject.spi.Message;
-
import java.util.Collection;
/**
@@ -38,7 +37,7 @@ public class CreationException extends RuntimeException {
public CreationException(Collection<Message> messages) {
this.messages = ImmutableSet.copyOf(messages);
checkArgument(!this.messages.isEmpty());
- initCause(Errors.getOnlyCause(this.messages));
+ initCause(Messages.getOnlyCause(this.messages));
}
/** Returns messages for the errors that caused this exception. */
@@ -46,8 +45,9 @@ public class CreationException extends RuntimeException {
return messages;
}
- @Override public String getMessage() {
- return Errors.format("Unable to create injector, see the following errors", messages);
+ @Override
+ public String getMessage() {
+ return Messages.formatMessages("Unable to create injector, see the following errors", messages);
}
private static final long serialVersionUID = 0;
diff --git a/core/src/com/google/inject/Exposed.java b/core/src/com/google/inject/Exposed.java
index 45a448fe..9e2e4418 100644
--- a/core/src/com/google/inject/Exposed.java
+++ b/core/src/com/google/inject/Exposed.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,5 +30,7 @@ import java.lang.annotation.Target;
* @author jessewilson@google.com (Jesse Wilson)
* @since 2.0
*/
-@Target(ElementType.METHOD) @Retention(RUNTIME) @Documented
+@Target(ElementType.METHOD)
+@Retention(RUNTIME)
+@Documented
public @interface Exposed {}
diff --git a/core/src/com/google/inject/Guice.java b/core/src/com/google/inject/Guice.java
index 703187f8..ae8d43b2 100644
--- a/core/src/com/google/inject/Guice.java
+++ b/core/src/com/google/inject/Guice.java
@@ -17,19 +17,17 @@
package com.google.inject;
import com.google.inject.internal.InternalInjectorCreator;
-
import java.util.Arrays;
/**
- * The entry point to the Guice framework. Creates {@link Injector}s from
- * {@link Module}s.
+ * The entry point to the Guice framework. Creates {@link Injector}s from {@link Module}s.
+ *
+ * <p>Guice supports a model of development that draws clear boundaries between APIs,
+ * Implementations of these APIs, Modules which configure these implementations, and finally
+ * Applications which consist of a collection of Modules. It is the Application, which typically
+ * defines your {@code main()} method, that bootstraps the Guice Injector using the {@code Guice}
+ * class, as in this example:
*
- * <p>Guice supports a model of development that draws clear boundaries between
- * APIs, Implementations of these APIs, Modules which configure these
- * implementations, and finally Applications which consist of a collection of
- * Modules. It is the Application, which typically defines your {@code main()}
- * method, that bootstraps the Guice Injector using the {@code Guice} class, as
- * in this example:
* <pre>
* public class FooApplication {
* public static void main(String[] args) {
@@ -52,50 +50,40 @@ public final class Guice {
private Guice() {}
/**
- * Creates an injector for the given set of modules. This is equivalent to
- * calling {@link #createInjector(Stage, Module...)} with Stage.DEVELOPMENT.
+ * Creates an injector for the given set of modules. This is equivalent to calling {@link
+ * #createInjector(Stage, Module...)} with Stage.DEVELOPMENT.
*
- * @throws CreationException if one or more errors occur during injector
- * construction
+ * @throws CreationException if one or more errors occur during injector construction
*/
public static Injector createInjector(Module... modules) {
return createInjector(Arrays.asList(modules));
}
/**
- * Creates an injector for the given set of modules. This is equivalent to
- * calling {@link #createInjector(Stage, Iterable)} with Stage.DEVELOPMENT.
+ * Creates an injector for the given set of modules. This is equivalent to calling {@link
+ * #createInjector(Stage, Iterable)} with Stage.DEVELOPMENT.
*
- * @throws CreationException if one or more errors occur during injector
- * creation
+ * @throws CreationException if one or more errors occur during injector creation
*/
public static Injector createInjector(Iterable<? extends Module> modules) {
return createInjector(Stage.DEVELOPMENT, modules);
}
/**
- * Creates an injector for the given set of modules, in a given development
- * stage.
+ * Creates an injector for the given set of modules, in a given development stage.
*
- * @throws CreationException if one or more errors occur during injector
- * creation.
+ * @throws CreationException if one or more errors occur during injector creation.
*/
public static Injector createInjector(Stage stage, Module... modules) {
return createInjector(stage, Arrays.asList(modules));
}
/**
- * Creates an injector for the given set of modules, in a given development
- * stage.
+ * Creates an injector for the given set of modules, in a given development stage.
*
- * @throws CreationException if one or more errors occur during injector
- * construction
+ * @throws CreationException if one or more errors occur during injector construction
*/
- public static Injector createInjector(Stage stage,
- Iterable<? extends Module> modules) {
- return new InternalInjectorCreator()
- .stage(stage)
- .addModules(modules)
- .build();
+ public static Injector createInjector(Stage stage, Iterable<? extends Module> modules) {
+ return new InternalInjectorCreator().stage(stage).addModules(modules).build();
}
}
diff --git a/core/src/com/google/inject/ImplementedBy.java b/core/src/com/google/inject/ImplementedBy.java
index 464a279e..f19bb860 100644
--- a/core/src/com/google/inject/ImplementedBy.java
+++ b/core/src/com/google/inject/ImplementedBy.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,8 +31,6 @@ import java.lang.annotation.Target;
@Target(TYPE)
public @interface ImplementedBy {
- /**
- * The implementation type.
- */
+ /** The implementation type. */
Class<?> value();
}
diff --git a/core/src/com/google/inject/Inject.java b/core/src/com/google/inject/Inject.java
index 535c0a42..3c4b396a 100644
--- a/core/src/com/google/inject/Inject.java
+++ b/core/src/com/google/inject/Inject.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,44 +26,37 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
- * Annotates members of your implementation class (constructors, methods
- * and fields) into which the {@link Injector} should inject values.
- * The Injector fulfills injection requests for:
+ * Annotates members of your implementation class (constructors, methods and fields) into which the
+ * {@link Injector} should inject values. The Injector fulfills injection requests for:
*
* <ul>
- * <li>Every instance it constructs. The class being constructed must have
- * exactly one of its constructors marked with {@code @Inject} or must have a
- * constructor taking no parameters. The Injector then proceeds to perform
- * field and method injections.
- *
- * <li>Pre-constructed instances passed to {@link Injector#injectMembers},
- * {@link com.google.inject.binder.LinkedBindingBuilder#toInstance(Object)} and
- * {@link com.google.inject.binder.LinkedBindingBuilder#toProvider(javax.inject.Provider)}.
- * In this case all constructors are, of course, ignored.
- *
- * <li>Static fields and methods of classes which any {@link Module} has
- * specifically requested static injection for, using
- * {@link Binder#requestStaticInjection}.
+ * <li>Every instance it constructs. The class being constructed must have exactly one of its
+ * constructors marked with {@code @Inject} or must have a constructor taking no parameters. The
+ * Injector then proceeds to perform field and method injections.
+ * <li>Pre-constructed instances passed to {@link Injector#injectMembers}, {@link
+ * com.google.inject.binder.LinkedBindingBuilder#toInstance(Object)} and {@link
+ * com.google.inject.binder.LinkedBindingBuilder#toProvider(javax.inject.Provider)}. In this
+ * case all constructors are, of course, ignored.
+ * <li>Static fields and methods of classes which any {@link Module} has specifically requested
+ * static injection for, using {@link Binder#requestStaticInjection}.
* </ul>
*
- * In all cases, a member can be injected regardless of its Java access
- * specifier (private, default, protected, public).
+ * In all cases, a member can be injected regardless of its Java access specifier (private, default,
+ * protected, public).
*
* @author crazybob@google.com (Bob Lee)
*/
-@Target({ METHOD, CONSTRUCTOR, FIELD })
+@Target({METHOD, CONSTRUCTOR, FIELD})
@Retention(RUNTIME)
@Documented
public @interface Inject {
/**
- * If true, and the appropriate binding is not found,
- * the Injector will skip injection of this method or field rather than
- * produce an error. When applied to a field, any default value already
- * assigned to the field will remain (guice will not actively null out the
- * field). When applied to a method, the method will only be invoked if
- * bindings for <i>all</i> parameters are found. When applied to a
- * constructor, an error will result upon Injector creation.
+ * If true, and the appropriate binding is not found, the Injector will skip injection of this
+ * method or field rather than produce an error. When applied to a field, any default value
+ * already assigned to the field will remain (guice will not actively null out the field). When
+ * applied to a method, the method will only be invoked if bindings for <i>all</i> parameters are
+ * found. When applied to a constructor, an error will result upon Injector creation.
*/
boolean optional() default false;
}
diff --git a/core/src/com/google/inject/Injector.java b/core/src/com/google/inject/Injector.java
index 42c7331d..d2ac4980 100644
--- a/core/src/com/google/inject/Injector.java
+++ b/core/src/com/google/inject/Injector.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,6 @@
package com.google.inject;
import com.google.inject.spi.TypeConverterBinding;
-
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
@@ -64,9 +63,8 @@ public interface Injector {
* you, you'll never need to use this method.
*
* @param instance to inject members on
- *
* @see Binder#getMembersInjector(Class) for a preferred alternative that supports checks before
- * run time
+ * run time
*/
void injectMembers(Object instance);
@@ -76,7 +74,7 @@ public interface Injector {
*
* @param typeLiteral type to get members injector for
* @see Binder#getMembersInjector(TypeLiteral) for an alternative that offers up front error
- * detection
+ * detection
* @since 2.0
*/
<T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral);
@@ -87,8 +85,7 @@ public interface Injector {
* instead to get increased up front error detection.
*
* @param type type to get members injector for
- * @see Binder#getMembersInjector(Class) for an alternative that offers up front error
- * detection
+ * @see Binder#getMembersInjector(Class) for an alternative that offers up front error detection
* @since 2.0
*/
<T> MembersInjector<T> getMembersInjector(Class<T> type);
@@ -97,9 +94,9 @@ public interface Injector {
* Returns this injector's <strong>explicit</strong> bindings.
*
* <p>The returned map does not include bindings inherited from a {@link #getParent() parent
- * injector}, should one exist. The returned map is guaranteed to iterate (for example, with
- * its {@link Map#entrySet()} iterator) in the order of insertion. In other words, the order in
- * which bindings appear in user Modules.
+ * injector}, should one exist. The returned map is guaranteed to iterate (for example, with its
+ * {@link Map#entrySet()} iterator) in the order of insertion. In other words, the order in which
+ * bindings appear in user Modules.
*
* <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
*/
@@ -108,14 +105,15 @@ public interface Injector {
/**
* Returns a snapshot of this injector's bindings, <strong>both explicit and
* just-in-time</strong>. The returned map is immutable; it contains only the bindings that were
- * present when {@code getAllBindings()} was invoked. Subsequent calls may return a map with
- * additional just-in-time bindings.
+ * present when {@code getAllBindings()} was invoked. Just-in-time bindings are only present if
+ * they have been requested at least once. Subsequent calls may return a map with additional
+ * just-in-time bindings.
*
* <p>The returned map does not include bindings inherited from a {@link #getParent() parent
* injector}, should one exist.
*
* <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
- *
+ *
* @since 3.0
*/
Map<Key<?>, Binding<?>> getAllBindings();
@@ -142,17 +140,17 @@ public interface Injector {
* @since 2.0
*/
<T> Binding<T> getBinding(Class<T> type);
-
+
/**
- * Returns the binding if it already exists, or null if does not exist. Unlike
- * {@link #getBinding(Key)}, this does not attempt to create just-in-time bindings
- * for keys that aren't bound.
- *
- * <p> This method is part of the Guice SPI and is intended for use by tools and extensions.
- *
+ * Returns the binding if it already exists, or null if does not exist. Unlike {@link
+ * #getBinding(Key)}, this does not attempt to create just-in-time bindings for keys that aren't
+ * bound.
+ *
+ * <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
+ *
* @since 3.0
*/
- <T> Binding<T> getExistingBinding(Key<T> key);
+ <T> Binding<T> getExistingBinding(Key<T> key);
/**
* Returns all explicit bindings for {@code type}.
@@ -171,8 +169,8 @@ public interface Injector {
<T> Provider<T> getProvider(Key<T> key);
/**
- * Returns the provider used to obtain instances for the given type. When feasible, avoid
- * using this method, in favor of having Guice inject your dependencies ahead of time.
+ * Returns the provider used to obtain instances for the given type. When feasible, avoid using
+ * this method, in favor of having Guice inject your dependencies ahead of time.
*
* @throws ConfigurationException if this injector cannot find or create the provider.
* @see Binder#getProvider(Class) for an alternative that offers up front error detection
@@ -213,9 +211,9 @@ public interface Injector {
*
* <p>Just-in-time bindings created for child injectors will be created in an ancestor injector
* whenever possible. This allows for scoped instances to be shared between injectors. Use
- * explicit bindings to prevent bindings from being shared with the parent injector. Optional
- * injections in just-in-time bindings (created in the parent injector) may be silently
- * ignored if the optional dependencies are from the child injector.
+ * explicit bindings to prevent bindings from being shared with the parent injector. Optional
+ * injections in just-in-time bindings (created in the parent injector) may be silently ignored if
+ * the optional dependencies are from the child injector.
*
* <p>No key may be bound by both an injector and one of its ancestors. This includes just-in-time
* bindings. The lone exception is the key for {@code Injector.class}, which is bound by each
@@ -243,12 +241,12 @@ public interface Injector {
Injector createChildInjector(Module... modules);
/**
- * Returns a map containing all scopes in the injector. The maps keys are scoping annotations
- * like {@code Singleton.class}, and the values are scope instances, such as {@code
- * Scopes.SINGLETON}. The returned map is immutable.
+ * Returns a map containing all scopes in the injector. The maps keys are scoping annotations like
+ * {@code Singleton.class}, and the values are scope instances, such as {@code Scopes.SINGLETON}.
+ * The returned map is immutable.
*
* <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
- *
+ *
* @since 3.0
*/
Map<Class<? extends Annotation>, Scope> getScopeBindings();
@@ -258,7 +256,7 @@ public interface Injector {
* immutable.
*
* <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
- *
+ *
* @since 3.0
*/
Set<TypeConverterBinding> getTypeConverterBindings();
diff --git a/core/src/com/google/inject/Key.java b/core/src/com/google/inject/Key.java
index c93dabfe..55779f3b 100644
--- a/core/src/com/google/inject/Key.java
+++ b/core/src/com/google/inject/Key.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,20 +21,16 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.inject.internal.Annotations.generateAnnotation;
import static com.google.inject.internal.Annotations.isAllDefaultMethods;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
import com.google.inject.internal.Annotations;
import com.google.inject.internal.MoreTypes;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
/**
- * Binding key consisting of an injection type and an optional annotation.
- * Matches the type and annotation at a point of injection.
+ * Binding key consisting of an injection type and an optional annotation. Matches the type and
+ * annotation at a point of injection.
*
- * <p>For example, {@code Key.get(Service.class, Transactional.class)} will
- * match:
+ * <p>For example, {@code Key.get(Service.class, Transactional.class)} will match:
*
* <pre>
* {@literal @}Inject
@@ -43,12 +39,11 @@ import java.lang.reflect.Type;
* }
* </pre>
*
- * <p>{@code Key} supports generic types via subclassing just like {@link
- * TypeLiteral}.
+ * <p>{@code Key} supports generic types via subclassing just like {@link TypeLiteral}.
*
- * <p>Keys do not differentiate between primitive types (int, char, etc.) and
- * their corresponding wrapper types (Integer, Character, etc.). Primitive
- * types will be replaced with their wrapper types when keys are created.
+ * <p>Keys do not differentiate between primitive types (int, char, etc.) and their corresponding
+ * wrapper types (Integer, Character, etc.). Primitive types will be replaced with their wrapper
+ * types when keys are created.
*
* @author crazybob@google.com (Bob Lee)
*/
@@ -58,38 +53,37 @@ public class Key<T> {
private final TypeLiteral<T> typeLiteral;
private final int hashCode;
- private final Supplier<String> toStringSupplier;
+ // This field is updated using the 'Data-Race-Ful' lazy intialization pattern
+ // See http://jeremymanson.blogspot.com/2008/12/benign-data-races-in-java.html for a detailed
+ // explanation.
+ private String toString;
/**
* Constructs a new key. Derives the type from this class's type parameter.
*
- * <p>Clients create an empty anonymous subclass. Doing so embeds the type
- * parameter in the anonymous class's type hierarchy so we can reconstitute it
- * at runtime despite erasure.
+ * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
+ * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
*
- * <p>Example usage for a binding of type {@code Foo} annotated with
- * {@code @Bar}:
+ * <p>Example usage for a binding of type {@code Foo} annotated with {@code @Bar}:
*
* <p>{@code new Key<Foo>(Bar.class) {}}.
*/
@SuppressWarnings("unchecked")
protected Key(Class<? extends Annotation> annotationType) {
this.annotationStrategy = strategyFor(annotationType);
- this.typeLiteral = MoreTypes.canonicalizeForKey(
- (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
+ this.typeLiteral =
+ MoreTypes.canonicalizeForKey(
+ (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
this.hashCode = computeHashCode();
- this.toStringSupplier = createToStringSupplier();
}
/**
* Constructs a new key. Derives the type from this class's type parameter.
*
- * <p>Clients create an empty anonymous subclass. Doing so embeds the type
- * parameter in the anonymous class's type hierarchy so we can reconstitute it
- * at runtime despite erasure.
+ * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
+ * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
*
- * <p>Example usage for a binding of type {@code Foo} annotated with
- * {@code @Bar}:
+ * <p>Example usage for a binding of type {@code Foo} annotated with {@code @Bar}:
*
* <p>{@code new Key<Foo>(new Bar()) {}}.
*/
@@ -97,18 +91,17 @@ public class Key<T> {
protected Key(Annotation annotation) {
// no usages, not test-covered
this.annotationStrategy = strategyFor(annotation);
- this.typeLiteral = MoreTypes.canonicalizeForKey(
- (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
+ this.typeLiteral =
+ MoreTypes.canonicalizeForKey(
+ (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
this.hashCode = computeHashCode();
- this.toStringSupplier = createToStringSupplier();
}
/**
* Constructs a new key. Derives the type from this class's type parameter.
*
- * <p>Clients create an empty anonymous subclass. Doing so embeds the type
- * parameter in the anonymous class's type hierarchy so we can reconstitute it
- * at runtime despite erasure.
+ * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
+ * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
*
* <p>Example usage for a binding of type {@code Foo}:
*
@@ -117,21 +110,18 @@ public class Key<T> {
@SuppressWarnings("unchecked")
protected Key() {
this.annotationStrategy = NullAnnotationStrategy.INSTANCE;
- this.typeLiteral = MoreTypes.canonicalizeForKey(
- (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
+ this.typeLiteral =
+ MoreTypes.canonicalizeForKey(
+ (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
this.hashCode = computeHashCode();
- this.toStringSupplier = createToStringSupplier();
}
- /**
- * Unsafe. Constructs a key from a manually specified type.
- */
+ /** Unsafe. Constructs a key from a manually specified type. */
@SuppressWarnings("unchecked")
private Key(Type type, AnnotationStrategy annotationStrategy) {
this.annotationStrategy = annotationStrategy;
this.typeLiteral = MoreTypes.canonicalizeForKey((TypeLiteral<T>) TypeLiteral.get(type));
this.hashCode = computeHashCode();
- this.toStringSupplier = createToStringSupplier();
}
/** Constructs a key from a manually specified type. */
@@ -139,46 +129,24 @@ public class Key<T> {
this.annotationStrategy = annotationStrategy;
this.typeLiteral = MoreTypes.canonicalizeForKey(typeLiteral);
this.hashCode = computeHashCode();
- this.toStringSupplier = createToStringSupplier();
}
- /**
- * Computes the hash code for this key.
- */
+ /** Computes the hash code for this key. */
private int computeHashCode() {
return typeLiteral.hashCode() * 31 + annotationStrategy.hashCode();
}
- /**
- * @return a {@link Supplier} which memoizes the value for lazy initialization.
- */
- private Supplier<String> createToStringSupplier() {
- // The performance hit on access is acceptable since the intended use is for non-performance-
- // critical applications such as debugging and logging.
- return Suppliers.memoize(new Supplier<String>() {
- @Override public String get() {
- return "Key[type=" + typeLiteral + ", annotation=" + annotationStrategy + "]";
- }
- });
- }
-
- /**
- * Gets the key type.
- */
+ /** Gets the key type. */
public final TypeLiteral<T> getTypeLiteral() {
return typeLiteral;
}
- /**
- * Gets the annotation type.
- */
+ /** Gets the annotation type. */
public final Class<? extends Annotation> getAnnotationType() {
return annotationStrategy.getAnnotationType();
}
- /**
- * Gets the annotation.
- */
+ /** Gets the annotation. */
public final Annotation getAnnotation() {
return annotationStrategy.getAnnotation();
}
@@ -201,14 +169,13 @@ public class Key<T> {
return typeLiteral.getRawType();
}
- /**
- * Gets the key of this key's provider.
- */
+ /** Gets the key of this key's provider. */
Key<Provider<T>> providerKey() {
return ofType(typeLiteral.providerType());
}
- @Override public final boolean equals(Object o) {
+ @Override
+ public final boolean equals(Object o) {
if (o == this) {
return true;
}
@@ -220,92 +187,76 @@ public class Key<T> {
&& typeLiteral.equals(other.typeLiteral);
}
- @Override public final int hashCode() {
+ @Override
+ public final int hashCode() {
return this.hashCode;
}
- @Override public final String toString() {
- return toStringSupplier.get();
+ @Override
+ public final String toString() {
+ // Note: to not introduce dangerous data races the field should only be read once in this
+ // method.
+ String local = toString;
+ if (local == null) {
+ local = "Key[type=" + typeLiteral + ", annotation=" + annotationStrategy + "]";
+ toString = local;
+ }
+ return local;
}
- /**
- * Gets a key for an injection type and an annotation strategy.
- */
- static <T> Key<T> get(Class<T> type,
- AnnotationStrategy annotationStrategy) {
+ /** Gets a key for an injection type and an annotation strategy. */
+ static <T> Key<T> get(Class<T> type, AnnotationStrategy annotationStrategy) {
return new Key<T>(type, annotationStrategy);
}
- /**
- * Gets a key for an injection type.
- */
+ /** Gets a key for an injection type. */
public static <T> Key<T> get(Class<T> type) {
return new Key<T>(type, NullAnnotationStrategy.INSTANCE);
}
- /**
- * Gets a key for an injection type and an annotation type.
- */
- public static <T> Key<T> get(Class<T> type,
- Class<? extends Annotation> annotationType) {
+ /** Gets a key for an injection type and an annotation type. */
+ public static <T> Key<T> get(Class<T> type, Class<? extends Annotation> annotationType) {
return new Key<T>(type, strategyFor(annotationType));
}
- /**
- * Gets a key for an injection type and an annotation.
- */
+ /** Gets a key for an injection type and an annotation. */
public static <T> Key<T> get(Class<T> type, Annotation annotation) {
return new Key<T>(type, strategyFor(annotation));
}
- /**
- * Gets a key for an injection type.
- */
+ /** Gets a key for an injection type. */
public static Key<?> get(Type type) {
return new Key<Object>(type, NullAnnotationStrategy.INSTANCE);
}
- /**
- * Gets a key for an injection type and an annotation type.
- */
- public static Key<?> get(Type type,
- Class<? extends Annotation> annotationType) {
+ /** Gets a key for an injection type and an annotation type. */
+ public static Key<?> get(Type type, Class<? extends Annotation> annotationType) {
return new Key<Object>(type, strategyFor(annotationType));
}
- /**
- * Gets a key for an injection type and an annotation.
- */
+ /** Gets a key for an injection type and an annotation. */
public static Key<?> get(Type type, Annotation annotation) {
return new Key<Object>(type, strategyFor(annotation));
}
- /**
- * Gets a key for an injection type.
- */
+ /** Gets a key for an injection type. */
public static <T> Key<T> get(TypeLiteral<T> typeLiteral) {
return new Key<T>(typeLiteral, NullAnnotationStrategy.INSTANCE);
}
- /**
- * Gets a key for an injection type and an annotation type.
- */
- public static <T> Key<T> get(TypeLiteral<T> typeLiteral,
- Class<? extends Annotation> annotationType) {
+ /** Gets a key for an injection type and an annotation type. */
+ public static <T> Key<T> get(
+ TypeLiteral<T> typeLiteral, Class<? extends Annotation> annotationType) {
return new Key<T>(typeLiteral, strategyFor(annotationType));
}
- /**
- * Gets a key for an injection type and an annotation.
- */
- public static <T> Key<T> get(TypeLiteral<T> typeLiteral,
- Annotation annotation) {
+ /** Gets a key for an injection type and an annotation. */
+ public static <T> Key<T> get(TypeLiteral<T> typeLiteral, Annotation annotation) {
return new Key<T>(typeLiteral, strategyFor(annotation));
}
/**
- * Returns a new key of the specified type with the same annotation as this
- * key.
+ * Returns a new key of the specified type with the same annotation as this key.
*
* @since 3.0
*/
@@ -314,8 +265,7 @@ public class Key<T> {
}
/**
- * Returns a new key of the specified type with the same annotation as this
- * key.
+ * Returns a new key of the specified type with the same annotation as this key.
*
* @since 3.0
*/
@@ -324,8 +274,7 @@ public class Key<T> {
}
/**
- * Returns a new key of the specified type with the same annotation as this
- * key.
+ * Returns a new key of the specified type with the same annotation as this key.
*
* @since 3.0
*/
@@ -343,8 +292,7 @@ public class Key<T> {
}
/**
- * Returns this key without annotation attributes, i.e. with only the
- * annotation type.
+ * Returns this key without annotation attributes, i.e. with only the annotation type.
*
* @since 3.0
*/
@@ -354,14 +302,15 @@ public class Key<T> {
interface AnnotationStrategy {
Annotation getAnnotation();
+
Class<? extends Annotation> getAnnotationType();
+
boolean hasAttributes();
+
AnnotationStrategy withoutAttributes();
}
- /**
- * Gets the strategy for an annotation.
- */
+ /** Gets the strategy for an annotation. */
static AnnotationStrategy strategyFor(Annotation annotation) {
checkNotNull(annotation, "annotation");
Class<? extends Annotation> annotationType = annotation.annotationType();
@@ -375,9 +324,7 @@ public class Key<T> {
return new AnnotationInstanceStrategy(Annotations.canonicalizeIfNamed(annotation));
}
- /**
- * Gets the strategy for an annotation type.
- */
+ /** Gets the strategy for an annotation type. */
static AnnotationStrategy strategyFor(Class<? extends Annotation> annotationType) {
annotationType = Annotations.canonicalizeIfNamed(annotationType);
if (isAllDefaultMethods(annotationType)) {
@@ -388,18 +335,18 @@ public class Key<T> {
ensureRetainedAtRuntime(annotationType);
ensureIsBindingAnnotation(annotationType);
return new AnnotationTypeStrategy(annotationType, null);
-
}
- private static void ensureRetainedAtRuntime(
- Class<? extends Annotation> annotationType) {
- checkArgument(Annotations.isRetainedAtRuntime(annotationType),
+ private static void ensureRetainedAtRuntime(Class<? extends Annotation> annotationType) {
+ checkArgument(
+ Annotations.isRetainedAtRuntime(annotationType),
"%s is not retained at runtime. Please annotate it with @Retention(RUNTIME).",
annotationType.getName());
}
private static void ensureIsBindingAnnotation(Class<? extends Annotation> annotationType) {
- checkArgument(Annotations.isBindingAnnotation(annotationType),
+ checkArgument(
+ Annotations.isBindingAnnotation(annotationType),
"%s is not a binding annotation. Please annotate it with @BindingAnnotation.",
annotationType.getName());
}
@@ -407,23 +354,28 @@ public class Key<T> {
static enum NullAnnotationStrategy implements AnnotationStrategy {
INSTANCE;
+ @Override
public boolean hasAttributes() {
return false;
}
+ @Override
public AnnotationStrategy withoutAttributes() {
throw new UnsupportedOperationException("Key already has no attributes.");
}
+ @Override
public Annotation getAnnotation() {
return null;
}
+ @Override
public Class<? extends Annotation> getAnnotationType() {
return null;
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "[none]";
}
}
@@ -437,23 +389,28 @@ public class Key<T> {
this.annotation = checkNotNull(annotation, "annotation");
}
+ @Override
public boolean hasAttributes() {
return true;
}
+ @Override
public AnnotationStrategy withoutAttributes() {
return new AnnotationTypeStrategy(getAnnotationType(), annotation);
}
+ @Override
public Annotation getAnnotation() {
return annotation;
}
+ @Override
public Class<? extends Annotation> getAnnotationType() {
return annotation.annotationType();
}
- @Override public boolean equals(Object o) {
+ @Override
+ public boolean equals(Object o) {
if (!(o instanceof AnnotationInstanceStrategy)) {
return false;
}
@@ -462,11 +419,13 @@ public class Key<T> {
return annotation.equals(other.annotation);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return annotation.hashCode();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return annotation.toString();
}
}
@@ -478,29 +437,33 @@ public class Key<T> {
// Keep the instance around if we have it so the client can request it.
final Annotation annotation;
- AnnotationTypeStrategy(Class<? extends Annotation> annotationType,
- Annotation annotation) {
+ AnnotationTypeStrategy(Class<? extends Annotation> annotationType, Annotation annotation) {
this.annotationType = checkNotNull(annotationType, "annotation type");
this.annotation = annotation;
}
+ @Override
public boolean hasAttributes() {
return false;
}
+ @Override
public AnnotationStrategy withoutAttributes() {
throw new UnsupportedOperationException("Key already has no attributes.");
}
+ @Override
public Annotation getAnnotation() {
return annotation;
}
+ @Override
public Class<? extends Annotation> getAnnotationType() {
return annotationType;
}
- @Override public boolean equals(Object o) {
+ @Override
+ public boolean equals(Object o) {
if (!(o instanceof AnnotationTypeStrategy)) {
return false;
}
@@ -509,11 +472,13 @@ public class Key<T> {
return annotationType.equals(other.annotationType);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return annotationType.hashCode();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "@" + annotationType.getName();
}
}
diff --git a/core/src/com/google/inject/MembersInjector.java b/core/src/com/google/inject/MembersInjector.java
index b50dedbe..349eb0da 100644
--- a/core/src/com/google/inject/MembersInjector.java
+++ b/core/src/com/google/inject/MembersInjector.java
@@ -21,7 +21,6 @@ package com.google.inject;
* presence or absence of an injectable constructor.
*
* @param <T> type to inject members of
- *
* @author crazybob@google.com (Bob Lee)
* @author jessewilson@google.com (Jesse Wilson)
* @since 2.0
diff --git a/core/src/com/google/inject/Module.java b/core/src/com/google/inject/Module.java
index f22d93f8..52cdd306 100644
--- a/core/src/com/google/inject/Module.java
+++ b/core/src/com/google/inject/Module.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,16 @@
package com.google.inject;
/**
- * A module contributes configuration information, typically interface
- * bindings, which will be used to create an {@link Injector}. A Guice-based
- * application is ultimately composed of little more than a set of
- * {@code Module}s and some bootstrapping code.
+ * A module contributes configuration information, typically interface bindings, which will be used
+ * to create an {@link Injector}. A Guice-based application is ultimately composed of little more
+ * than a set of {@code Module}s and some bootstrapping code.
*
- * <p>Your Module classes can use a more streamlined syntax by extending
- * {@link AbstractModule} rather than implementing this interface directly.
+ * <p>Your Module classes can use a more streamlined syntax by extending {@link AbstractModule}
+ * rather than implementing this interface directly.
*
- * <p>In addition to the bindings configured via {@link #configure}, bindings
- * will be created for all methods annotated with {@literal @}{@link Provides}.
- * Use scope and binding annotations on these methods to configure the
- * bindings.
+ * <p>In addition to the bindings configured via {@link #configure}, bindings will be created for
+ * all methods annotated with {@literal @}{@link Provides}. Use scope and binding annotations on
+ * these methods to configure the bindings.
*/
public interface Module {
diff --git a/core/src/com/google/inject/OutOfScopeException.java b/core/src/com/google/inject/OutOfScopeException.java
index 430fa237..7199b6b6 100644
--- a/core/src/com/google/inject/OutOfScopeException.java
+++ b/core/src/com/google/inject/OutOfScopeException.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,8 +17,8 @@
package com.google.inject;
/**
- * Thrown from {@link Provider#get} when an attempt is made to access a scoped
- * object while the scope in question is not currently active.
+ * Thrown from {@link Provider#get} when an attempt is made to access a scoped object while the
+ * scope in question is not currently active.
*
* @author kevinb@google.com (Kevin Bourrillion)
* @since 2.0
diff --git a/core/src/com/google/inject/PrivateBinder.java b/core/src/com/google/inject/PrivateBinder.java
index 21a833f6..9e7fcd36 100644
--- a/core/src/com/google/inject/PrivateBinder.java
+++ b/core/src/com/google/inject/PrivateBinder.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,7 +21,7 @@ import com.google.inject.binder.AnnotatedElementBuilder;
/**
* Returns a binder whose configuration information is hidden from its environment by default. See
* {@link com.google.inject.PrivateModule PrivateModule} for details.
- *
+ *
* @author jessewilson@google.com (Jesse Wilson)
* @since 2.0
*/
@@ -32,8 +32,8 @@ public interface PrivateBinder extends Binder {
/**
* Makes a binding for {@code type} available to the enclosing environment. Use {@link
- * com.google.inject.binder.AnnotatedElementBuilder#annotatedWith(Class) annotatedWith()} to expose {@code type} with a
- * binding annotation.
+ * com.google.inject.binder.AnnotatedElementBuilder#annotatedWith(Class) annotatedWith()} to
+ * expose {@code type} with a binding annotation.
*/
AnnotatedElementBuilder expose(Class<?> type);
@@ -44,7 +44,9 @@ public interface PrivateBinder extends Binder {
*/
AnnotatedElementBuilder expose(TypeLiteral<?> type);
+ @Override
PrivateBinder withSource(Object source);
+ @Override
PrivateBinder skipSources(Class... classesToSkip);
}
diff --git a/core/src/com/google/inject/PrivateModule.java b/core/src/com/google/inject/PrivateModule.java
index ba2f7223..e43e1f94 100644
--- a/core/src/com/google/inject/PrivateModule.java
+++ b/core/src/com/google/inject/PrivateModule.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,7 +27,6 @@ import com.google.inject.spi.Message;
import com.google.inject.spi.ProvisionListener;
import com.google.inject.spi.TypeConverter;
import com.google.inject.spi.TypeListener;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
@@ -37,14 +36,14 @@ import java.lang.reflect.Method;
* This module may expose the bindings it creates and the bindings of the modules it installs.
*
* <p>A private module can be nested within a regular module or within another private module using
- * {@link Binder#install install()}. Its bindings live in a new environment that inherits bindings,
- * type converters, scopes, and interceptors from the surrounding ("parent") environment. When you
+ * {@link Binder#install install()}. Its bindings live in a new environment that inherits bindings,
+ * type converters, scopes, and interceptors from the surrounding ("parent") environment. When you
* nest multiple private modules, the result is a tree of environments where the injector's
* environment is the root.
*
* <p>Guice EDSL bindings can be exposed with {@link #expose(Class) expose()}. {@literal @}{@link
- * com.google.inject.Provides Provides} bindings can be exposed with the {@literal @}{@link
- * Exposed} annotation:
+ * com.google.inject.Provides Provides} bindings can be exposed with the {@literal @}{@link Exposed}
+ * annotation:
*
* <pre>
* public class FooBarBazModule extends PrivateModule {
@@ -69,7 +68,7 @@ import java.lang.reflect.Method;
* <p>Private modules are implemented using {@link Injector#createChildInjector(Module[]) parent
* injectors}. When it can satisfy their dependencies, just-in-time bindings will be created in the
* root environment. Such bindings are shared among all environments in the tree.
- *
+ *
* <p>The scope of a binding is constrained to its environment. A singleton bound in a private
* module will be unique to its environment. But a binding for the same type in a different private
* module will yield a different instance.
@@ -79,6 +78,7 @@ import java.lang.reflect.Method;
* gets access to all bindings in the child environment.
*
* <p>To promote a just-in-time binding to an explicit binding, bind it:
+ *
* <pre>
* bind(FooImpl.class);
* </pre>
@@ -91,6 +91,7 @@ public abstract class PrivateModule implements Module {
/** Like abstract module, the binder of the current private module */
private PrivateBinder binder;
+ @Override
public final synchronized void configure(Binder binder) {
checkState(this.binder == null, "Re-entry is not allowed.");
@@ -134,155 +135,120 @@ public abstract class PrivateModule implements Module {
// everything below is copied from AbstractModule
- /**
- * Returns the current binder.
- */
+ /** Returns the current binder. */
protected final PrivateBinder binder() {
checkState(binder != null, "The binder can only be used inside configure()");
return binder;
}
- /**
- * @see Binder#bindScope(Class, Scope)
- */
+ /** @see Binder#bindScope(Class, Scope) */
protected final void bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope) {
binder().bindScope(scopeAnnotation, scope);
}
- /**
- * @see Binder#bind(Key)
- */
+ /** @see Binder#bind(Key) */
protected final <T> LinkedBindingBuilder<T> bind(Key<T> key) {
return binder().bind(key);
}
- /**
- * @see Binder#bind(TypeLiteral)
- */
+ /** @see Binder#bind(TypeLiteral) */
protected final <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
return binder().bind(typeLiteral);
}
- /**
- * @see Binder#bind(Class)
- */
+ /** @see Binder#bind(Class) */
protected final <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) {
return binder().bind(clazz);
}
- /**
- * @see Binder#bindConstant()
- */
+ /** @see Binder#bindConstant() */
protected final AnnotatedConstantBindingBuilder bindConstant() {
return binder().bindConstant();
}
- /**
- * @see Binder#install(Module)
- */
+ /** @see Binder#install(Module) */
protected final void install(Module module) {
binder().install(module);
}
- /**
- * @see Binder#addError(String, Object[])
- */
+ /** @see Binder#addError(String, Object[]) */
protected final void addError(String message, Object... arguments) {
binder().addError(message, arguments);
}
- /**
- * @see Binder#addError(Throwable)
- */
+ /** @see Binder#addError(Throwable) */
protected final void addError(Throwable t) {
binder().addError(t);
}
- /**
- * @see Binder#addError(Message)
- */
+ /** @see Binder#addError(Message) */
protected final void addError(Message message) {
binder().addError(message);
}
- /**
- * @see Binder#requestInjection(Object)
- */
+ /** @see Binder#requestInjection(Object) */
protected final void requestInjection(Object instance) {
binder().requestInjection(instance);
}
- /**
- * @see Binder#requestStaticInjection(Class[])
- */
+ /** @see Binder#requestStaticInjection(Class[]) */
protected final void requestStaticInjection(Class<?>... types) {
binder().requestStaticInjection(types);
}
/*if[AOP]*/
/**
- * @see Binder#bindInterceptor(com.google.inject.matcher.Matcher, com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[])
+ * @see Binder#bindInterceptor(com.google.inject.matcher.Matcher,
+ * com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[])
*/
- protected final void bindInterceptor(Matcher<? super Class<?>> classMatcher,
+ protected final void bindInterceptor(
+ Matcher<? super Class<?>> classMatcher,
Matcher<? super Method> methodMatcher,
org.aopalliance.intercept.MethodInterceptor... interceptors) {
binder().bindInterceptor(classMatcher, methodMatcher, interceptors);
}
/*end[AOP]*/
- /**
- * Instructs Guice to require a binding to the given key.
- */
+ /** Instructs Guice to require a binding to the given key. */
protected final void requireBinding(Key<?> key) {
binder().getProvider(key);
}
- /**
- * Instructs Guice to require a binding to the given type.
- */
+ /** Instructs Guice to require a binding to the given type. */
protected final void requireBinding(Class<?> type) {
binder().getProvider(type);
}
- /**
- * @see Binder#getProvider(Key)
- */
+ /** @see Binder#getProvider(Key) */
protected final <T> Provider<T> getProvider(Key<T> key) {
return binder().getProvider(key);
}
-
- /**
- * @see Binder#getProvider(Class)
- */
+
+ /** @see Binder#getProvider(Class) */
protected final <T> Provider<T> getProvider(Class<T> type) {
return binder().getProvider(type);
}
/**
- * @see Binder#convertToTypes(com.google.inject.matcher.Matcher, com.google.inject.spi.TypeConverter)
+ * @see Binder#convertToTypes(com.google.inject.matcher.Matcher,
+ * com.google.inject.spi.TypeConverter)
*/
- protected final void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
- TypeConverter converter) {
+ protected final void convertToTypes(
+ Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter) {
binder().convertToTypes(typeMatcher, converter);
}
- /**
- * @see Binder#currentStage()
- */
+ /** @see Binder#currentStage() */
protected final Stage currentStage() {
return binder().currentStage();
}
- /**
- * @see Binder#getMembersInjector(Class)
- */
+ /** @see Binder#getMembersInjector(Class) */
protected <T> MembersInjector<T> getMembersInjector(Class<T> type) {
return binder().getMembersInjector(type);
}
- /**
- * @see Binder#getMembersInjector(TypeLiteral)
- */
+ /** @see Binder#getMembersInjector(TypeLiteral) */
protected <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) {
return binder().getMembersInjector(type);
}
@@ -290,17 +256,16 @@ public abstract class PrivateModule implements Module {
/**
* @see Binder#bindListener(com.google.inject.matcher.Matcher, com.google.inject.spi.TypeListener)
*/
- protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
- TypeListener listener) {
+ protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener) {
binder().bindListener(typeMatcher, listener);
}
-
+
/**
* @see Binder#bindListener(Matcher, ProvisionListener...)
* @since 4.0
*/
- protected void bindListener(Matcher<? super Binding<?>> bindingMatcher,
- ProvisionListener... listeners) {
+ protected void bindListener(
+ Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listeners) {
binder().bindListener(bindingMatcher, listeners);
}
}
diff --git a/core/src/com/google/inject/ProvidedBy.java b/core/src/com/google/inject/ProvidedBy.java
index 7ad12f78..bb924314 100644
--- a/core/src/com/google/inject/ProvidedBy.java
+++ b/core/src/com/google/inject/ProvidedBy.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,8 +31,6 @@ import java.lang.annotation.Target;
@Target(TYPE)
public @interface ProvidedBy {
- /**
- * The implementation type.
- */
- Class<? extends Provider<?>> value();
+ /** The implementation type. */
+ Class<? extends javax.inject.Provider<?>> value();
}
diff --git a/core/src/com/google/inject/Provider.java b/core/src/com/google/inject/Provider.java
index 3295a2b0..4ce1e315 100644
--- a/core/src/com/google/inject/Provider.java
+++ b/core/src/com/google/inject/Provider.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,35 +22,32 @@ package com.google.inject;
*
* <ul>
* <li>When the default means for obtaining instances (an injectable or parameterless constructor)
- * is insufficient for a particular binding, the module can specify a custom {@code Provider}
- * instead, to control exactly how Guice creates or obtains instances for the binding.
- *
+ * is insufficient for a particular binding, the module can specify a custom {@code Provider}
+ * instead, to control exactly how Guice creates or obtains instances for the binding.
* <li>An implementation class may always choose to have a {@code Provider<T>} instance injected,
- * rather than having a {@code T} injected directly. This may give you access to multiple
- * instances, instances you wish to safely mutate and discard, instances which are out of scope
- * (e.g. using a {@code @RequestScoped} object from within a {@code @SessionScoped} object), or
- * instances that will be initialized lazily.
- *
+ * rather than having a {@code T} injected directly. This may give you access to multiple
+ * instances, instances you wish to safely mutate and discard, instances which are out of scope
+ * (e.g. using a {@code @RequestScoped} object from within a {@code @SessionScoped} object), or
+ * instances that will be initialized lazily.
* <li>A custom {@link Scope} is implemented as a decorator of {@code Provider<T>}, which decides
- * when to delegate to the backing provider and when to provide the instance some other way.
- *
- * <li>The {@link Injector} offers access to the {@code Provider<T>} it uses to fulfill requests
- * for a given key, via the {@link Injector#getProvider} methods.
+ * when to delegate to the backing provider and when to provide the instance some other way.
+ * <li>The {@link Injector} offers access to the {@code Provider<T>} it uses to fulfill requests for
+ * a given key, via the {@link Injector#getProvider} methods.
* </ul>
*
* @param <T> the type of object this provides
- *
* @author crazybob@google.com (Bob Lee)
*/
public interface Provider<T> extends javax.inject.Provider<T> {
/**
- * Provides an instance of {@code T}. Must never return {@code null}.
+ * Provides an instance of {@code T}.
*
* @throws OutOfScopeException when an attempt is made to access a scoped object while the scope
* in question is not currently active
* @throws ProvisionException if an instance cannot be provided. Such exceptions include messages
* and throwables to describe why provision failed.
*/
+ @Override
T get();
}
diff --git a/core/src/com/google/inject/Provides.java b/core/src/com/google/inject/Provides.java
index c66a428a..ba8f72b2 100644
--- a/core/src/com/google/inject/Provides.java
+++ b/core/src/com/google/inject/Provides.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,5 +30,7 @@ import java.lang.annotation.Target;
* @author crazybob@google.com (Bob Lee)
* @since 2.0
*/
-@Documented @Target(METHOD) @Retention(RUNTIME)
+@Documented
+@Target(METHOD)
+@Retention(RUNTIME)
public @interface Provides {}
diff --git a/core/src/com/google/inject/ProvisionException.java b/core/src/com/google/inject/ProvisionException.java
index 3c590b99..0c132c5e 100644
--- a/core/src/com/google/inject/ProvisionException.java
+++ b/core/src/com/google/inject/ProvisionException.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,14 +19,14 @@ package com.google.inject;
import static com.google.common.base.Preconditions.checkArgument;
import com.google.common.collect.ImmutableSet;
-import com.google.inject.internal.Errors;
+import com.google.inject.internal.Messages;
import com.google.inject.spi.Message;
-
import java.util.Collection;
/**
* Indicates that there was a runtime failure while providing an instance.
*
+ *
* @author kevinb@google.com (Kevin Bourrillion)
* @author jessewilson@google.com (Jesse Wilson)
* @since 2.0
@@ -39,7 +39,7 @@ public final class ProvisionException extends RuntimeException {
public ProvisionException(Iterable<Message> messages) {
this.messages = ImmutableSet.copyOf(messages);
checkArgument(!this.messages.isEmpty());
- initCause(Errors.getOnlyCause(this.messages));
+ initCause(Messages.getOnlyCause(this.messages));
}
public ProvisionException(String message, Throwable cause) {
@@ -56,8 +56,9 @@ public final class ProvisionException extends RuntimeException {
return messages;
}
- @Override public String getMessage() {
- return Errors.format("Unable to provision, see the following errors", messages);
+ @Override
+ public String getMessage() {
+ return Messages.formatMessages("Unable to provision, see the following errors", messages);
}
private static final long serialVersionUID = 0;
diff --git a/core/src/com/google/inject/Scope.java b/core/src/com/google/inject/Scope.java
index 949270c8..331d9c34 100644
--- a/core/src/com/google/inject/Scope.java
+++ b/core/src/com/google/inject/Scope.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,13 +17,11 @@
package com.google.inject;
/**
- * A scope is a level of visibility that instances provided by Guice may have.
- * By default, an instance created by the {@link Injector} has <i>no scope</i>,
- * meaning it has no state from the framework's perspective -- the
- * {@code Injector} creates it, injects it once into the class that required it,
- * and then immediately forgets it. Associating a scope with a particular
- * binding allows the created instance to be "remembered" and possibly used
- * again for other injections.
+ * A scope is a level of visibility that instances provided by Guice may have. By default, an
+ * instance created by the {@link Injector} has <i>no scope</i>, meaning it has no state from the
+ * framework's perspective -- the {@code Injector} creates it, injects it once into the class that
+ * required it, and then immediately forgets it. Associating a scope with a particular binding
+ * allows the created instance to be "remembered" and possibly used again for other injections.
*
* <p>An example of a scope is {@link Scopes#SINGLETON}.
*
@@ -32,28 +30,24 @@ package com.google.inject;
public interface Scope {
/**
- * Scopes a provider. The returned provider returns objects from this scope.
- * If an object does not exist in this scope, the provider can use the given
- * unscoped provider to retrieve one.
+ * Scopes a provider. The returned provider returns objects from this scope. If an object does not
+ * exist in this scope, the provider can use the given unscoped provider to retrieve one.
*
- * <p>Scope implementations are strongly encouraged to override
- * {@link Object#toString} in the returned provider and include the backing
- * provider's {@code toString()} output.
+ * <p>Scope implementations are strongly encouraged to override {@link Object#toString} in the
+ * returned provider and include the backing provider's {@code toString()} output.
*
* @param key binding key
- * @param unscoped locates an instance when one doesn't already exist in this
- * scope.
- * @return a new provider which only delegates to the given unscoped provider
- * when an instance of the requested object doesn't already exist in this
- * scope
+ * @param unscoped locates an instance when one doesn't already exist in this scope.
+ * @return a new provider which only delegates to the given unscoped provider when an instance of
+ * the requested object doesn't already exist in this scope
*/
public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped);
/**
- * A short but useful description of this scope. For comparison, the standard
- * scopes that ship with guice use the descriptions
- * {@code "Scopes.SINGLETON"}, {@code "ServletScopes.SESSION"} and
+ * A short but useful description of this scope. For comparison, the standard scopes that ship
+ * with guice use the descriptions {@code "Scopes.SINGLETON"}, {@code "ServletScopes.SESSION"} and
* {@code "ServletScopes.REQUEST"}.
*/
+ @Override
String toString();
}
diff --git a/core/src/com/google/inject/ScopeAnnotation.java b/core/src/com/google/inject/ScopeAnnotation.java
index 8f869a09..c0b651a2 100644
--- a/core/src/com/google/inject/ScopeAnnotation.java
+++ b/core/src/com/google/inject/ScopeAnnotation.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,9 +23,9 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
- * Annotates annotations which are used for scoping. Only one such annotation
- * may apply to a single implementation class. You must also annotate scope
- * annotations with {@code @Retention(RUNTIME)}. For example:
+ * Annotates annotations which are used for scoping. Only one such annotation may apply to a single
+ * implementation class. You must also annotate scope annotations with {@code @Retention(RUNTIME)}.
+ * For example:
*
* <pre>
* {@code @}Retention(RUNTIME)
diff --git a/core/src/com/google/inject/Scopes.java b/core/src/com/google/inject/Scopes.java
index 6c893e52..20be1022 100644
--- a/core/src/com/google/inject/Scopes.java
+++ b/core/src/com/google/inject/Scopes.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,7 +21,6 @@ import com.google.inject.internal.LinkedBindingImpl;
import com.google.inject.internal.SingletonScope;
import com.google.inject.spi.BindingScopingVisitor;
import com.google.inject.spi.ExposedBinding;
-
import java.lang.annotation.Annotation;
/**
@@ -33,47 +32,51 @@ public class Scopes {
private Scopes() {}
- /**
- * One instance per {@link Injector}. Also see {@code @}{@link Singleton}.
- */
+ /** One instance per {@link Injector}. Also see {@code @}{@link Singleton}. */
public static final Scope SINGLETON = new SingletonScope();
/**
- * No scope; the same as not applying any scope at all. Each time the
- * Injector obtains an instance of an object with "no scope", it injects this
- * instance then immediately forgets it. When the next request for the same
- * binding arrives it will need to obtain the instance over again.
+ * No scope; the same as not applying any scope at all. Each time the Injector obtains an instance
+ * of an object with "no scope", it injects this instance then immediately forgets it. When the
+ * next request for the same binding arrives it will need to obtain the instance over again.
*
- * <p>This exists only in case a class has been annotated with a scope
- * annotation such as {@link Singleton @Singleton}, and you need to override
- * this to "no scope" in your binding.
+ * <p>This exists only in case a class has been annotated with a scope annotation such as {@link
+ * Singleton @Singleton}, and you need to override this to "no scope" in your binding.
*
* @since 2.0
*/
- public static final Scope NO_SCOPE = new Scope() {
- public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
- return unscoped;
- }
- @Override public String toString() {
- return "Scopes.NO_SCOPE";
- }
- };
-
- private static final BindingScopingVisitor<Boolean> IS_SINGLETON_VISITOR
- = new BindingScopingVisitor<Boolean>() {
+ public static final Scope NO_SCOPE =
+ new Scope() {
+ @Override
+ public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
+ return unscoped;
+ }
+
+ @Override
+ public String toString() {
+ return "Scopes.NO_SCOPE";
+ }
+ };
+
+ private static final BindingScopingVisitor<Boolean> IS_SINGLETON_VISITOR =
+ new BindingScopingVisitor<Boolean>() {
+ @Override
public Boolean visitNoScoping() {
return false;
}
+ @Override
public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
return scopeAnnotation == Singleton.class
|| scopeAnnotation == javax.inject.Singleton.class;
}
+ @Override
public Boolean visitScope(Scope scope) {
return scope == Scopes.SINGLETON;
}
+ @Override
public Boolean visitEagerSingleton() {
return true;
}
@@ -101,8 +104,8 @@ public class Scopes {
binding = injector.getBinding(linkedBinding.getLinkedKey());
continue;
}
- } else if(binding instanceof ExposedBinding) {
- ExposedBinding<?> exposedBinding = (ExposedBinding)binding;
+ } else if (binding instanceof ExposedBinding) {
+ ExposedBinding<?> exposedBinding = (ExposedBinding) binding;
Injector injector = exposedBinding.getPrivateElements().getInjector();
if (injector != null) {
binding = injector.getBinding(exposedBinding.getKey());
@@ -115,7 +118,6 @@ public class Scopes {
}
/**
-
* Returns true if {@code binding} has the given scope. If the binding is a {@link
* com.google.inject.spi.LinkedKeyBinding linked key binding} and belongs to an injector (ie. it
* was retrieved via {@link Injector#getBinding Injector.getBinding()}), then this method will
@@ -126,26 +128,32 @@ public class Scopes {
* @param scopeAnnotation scope annotation class
* @since 4.0
*/
- public static boolean isScoped(Binding<?> binding, final Scope scope,
- final Class<? extends Annotation> scopeAnnotation) {
+ public static boolean isScoped(
+ Binding<?> binding, final Scope scope, final Class<? extends Annotation> scopeAnnotation) {
do {
- boolean matches = binding.acceptScopingVisitor(new BindingScopingVisitor<Boolean>() {
- public Boolean visitNoScoping() {
- return false;
- }
-
- public Boolean visitScopeAnnotation(Class<? extends Annotation> visitedAnnotation) {
- return visitedAnnotation == scopeAnnotation;
- }
-
- public Boolean visitScope(Scope visitedScope) {
- return visitedScope == scope;
- }
-
- public Boolean visitEagerSingleton() {
- return false;
- }
- });
+ boolean matches =
+ binding.acceptScopingVisitor(
+ new BindingScopingVisitor<Boolean>() {
+ @Override
+ public Boolean visitNoScoping() {
+ return false;
+ }
+
+ @Override
+ public Boolean visitScopeAnnotation(Class<? extends Annotation> visitedAnnotation) {
+ return visitedAnnotation == scopeAnnotation;
+ }
+
+ @Override
+ public Boolean visitScope(Scope visitedScope) {
+ return visitedScope == scope;
+ }
+
+ @Override
+ public Boolean visitEagerSingleton() {
+ return false;
+ }
+ });
if (matches) {
return true;
@@ -158,8 +166,8 @@ public class Scopes {
binding = injector.getBinding(linkedBinding.getLinkedKey());
continue;
}
- } else if(binding instanceof ExposedBinding) {
- ExposedBinding<?> exposedBinding = (ExposedBinding)binding;
+ } else if (binding instanceof ExposedBinding) {
+ ExposedBinding<?> exposedBinding = (ExposedBinding) binding;
Injector injector = exposedBinding.getPrivateElements().getInjector();
if (injector != null) {
binding = injector.getBinding(exposedBinding.getKey());
@@ -172,12 +180,11 @@ public class Scopes {
}
/**
- * Returns true if the object is a proxy for a circular dependency,
- * constructed by Guice because it encountered a circular dependency. Scope
- * implementations should be careful to <b>not cache circular proxies</b>,
- * because the proxies are not intended for general purpose use. (They are
- * designed just to fulfill the immediate injection, not all injections.
- * Caching them can lead to IllegalArgumentExceptions or ClassCastExceptions.)
+ * Returns true if the object is a proxy for a circular dependency, constructed by Guice because
+ * it encountered a circular dependency. Scope implementations should be careful to <b>not cache
+ * circular proxies</b>, because the proxies are not intended for general purpose use. (They are
+ * designed just to fulfill the immediate injection, not all injections. Caching them can lead to
+ * IllegalArgumentExceptions or ClassCastExceptions.)
*
* @since 4.0
*/
diff --git a/core/src/com/google/inject/Singleton.java b/core/src/com/google/inject/Singleton.java
index 0ea9a14d..59a2b44d 100644
--- a/core/src/com/google/inject/Singleton.java
+++ b/core/src/com/google/inject/Singleton.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,12 +23,12 @@ import java.lang.annotation.Retention;
import java.lang.annotation.Target;
/**
- * Apply this to implementation classes when you want only one instance
- * (per {@link Injector}) to be reused for all injections for that binding.
+ * Apply this to implementation classes when you want only one instance (per {@link Injector}) to be
+ * reused for all injections for that binding.
*
* @author crazybob@google.com (Bob Lee)
*/
-@Target({ ElementType.TYPE, ElementType.METHOD })
+@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RUNTIME)
@ScopeAnnotation
public @interface Singleton {}
diff --git a/core/src/com/google/inject/Stage.java b/core/src/com/google/inject/Stage.java
index f9b4e357..19f256e0 100644
--- a/core/src/com/google/inject/Stage.java
+++ b/core/src/com/google/inject/Stage.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,8 +26,8 @@ public enum Stage {
/**
* We're running in a tool (an IDE plugin for example). We need binding meta data but not a
* functioning Injector. Do not inject members of instances. Do not load eager singletons. Do as
- * little as possible so our tools run nice and snappy. Injectors created in this stage cannot
- * be used to satisfy injections.
+ * little as possible so our tools run nice and snappy. Injectors created in this stage cannot be
+ * used to satisfy injections.
*/
TOOL,
@@ -37,8 +37,6 @@ public enum Stage {
*/
DEVELOPMENT,
- /**
- * We want to catch errors as early as possible and take performance hits up front.
- */
+ /** We want to catch errors as early as possible and take performance hits up front. */
PRODUCTION
}
diff --git a/core/src/com/google/inject/TypeLiteral.java b/core/src/com/google/inject/TypeLiteral.java
index d18087d2..0f928da5 100644
--- a/core/src/com/google/inject/TypeLiteral.java
+++ b/core/src/com/google/inject/TypeLiteral.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@ import static com.google.inject.internal.MoreTypes.canonicalize;
import com.google.common.collect.ImmutableList;
import com.google.inject.internal.MoreTypes;
import com.google.inject.util.Types;
-
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
@@ -36,26 +35,25 @@ import java.lang.reflect.WildcardType;
import java.util.List;
/**
- * Represents a generic type {@code T}. Java doesn't yet provide a way to
- * represent generic types, so this class does. Forces clients to create a
- * subclass of this class which enables retrieval the type information even at
- * runtime.
+ * Represents a generic type {@code T}. Java doesn't yet provide a way to represent generic types,
+ * so this class does. Forces clients to create a subclass of this class which enables retrieval of
+ * the type information even at runtime.
*
- * <p>For example, to create a type literal for {@code List<String>}, you can
- * create an empty anonymous inner class:
+ * <p>For example, to create a type literal for {@code List<String>}, you can create an empty
+ * anonymous inner class:
*
- * <p>
- * {@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};}
+ * <p>{@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};}
*
- * <p>Along with modeling generic types, this class can resolve type parameters.
- * For example, to figure out what type {@code keySet()} returns on a {@code
- * Map<Integer, String>}, use this code:<pre> {@code
+ * <p>Along with modeling generic types, this class can resolve type parameters. For example, to
+ * figure out what type {@code keySet()} returns on a {@code Map<Integer, String>}, use this code:
*
- * TypeLiteral<Map<Integer, String>> mapType
- * = new TypeLiteral<Map<Integer, String>>() {};
- * TypeLiteral<?> keySetType
- * = mapType.getReturnType(Map.class.getMethod("keySet"));
- * System.out.println(keySetType); // prints "Set<Integer>"}</pre>
+ * <pre>{@code
+ * TypeLiteral<Map<Integer, String>> mapType
+ * = new TypeLiteral<Map<Integer, String>>() {};
+ * TypeLiteral<?> keySetType
+ * = mapType.getReturnType(Map.class.getMethod("keySet"));
+ * System.out.println(keySetType); // prints "Set<Integer>"
+ * }</pre>
*
* @author crazybob@google.com (Bob Lee)
* @author jessewilson@google.com (Jesse Wilson)
@@ -67,12 +65,10 @@ public class TypeLiteral<T> {
final int hashCode;
/**
- * Constructs a new type literal. Derives represented class from type
- * parameter.
+ * Constructs a new type literal. Derives represented class from type parameter.
*
- * <p>Clients create an empty anonymous subclass. Doing so embeds the type
- * parameter in the anonymous class's type hierarchy so we can reconstitute it
- * at runtime despite erasure.
+ * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
+ * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
*/
@SuppressWarnings("unchecked")
protected TypeLiteral() {
@@ -81,9 +77,7 @@ public class TypeLiteral<T> {
this.hashCode = type.hashCode();
}
- /**
- * Unsafe. Constructs a type literal manually.
- */
+ /** Unsafe. Constructs a type literal manually. */
@SuppressWarnings("unchecked")
TypeLiteral(Type type) {
this.type = canonicalize(checkNotNull(type, "type"));
@@ -104,32 +98,26 @@ public class TypeLiteral<T> {
return canonicalize(parameterized.getActualTypeArguments()[0]);
}
- /**
- * Gets type literal from super class's type parameter.
- */
+ /** Gets type literal from super class's type parameter. */
static TypeLiteral<?> fromSuperclassTypeParameter(Class<?> subclass) {
return new TypeLiteral<Object>(getSuperclassTypeParameter(subclass));
}
/**
* Returns the raw (non-generic) type for this type.
- *
+ *
* @since 2.0
*/
public final Class<? super T> getRawType() {
return rawType;
}
- /**
- * Gets underlying {@code Type} instance.
- */
+ /** Gets underlying {@code Type} instance. */
public final Type getType() {
return type;
}
- /**
- * Gets the type of this type's provider.
- */
+ /** Gets the type of this type's provider. */
@SuppressWarnings("unchecked")
final TypeLiteral<Provider<T>> providerType() {
// This cast is safe and wouldn't generate a warning if Type had a type
@@ -137,34 +125,31 @@ public class TypeLiteral<T> {
return (TypeLiteral<Provider<T>>) get(Types.providerOf(getType()));
}
- @Override public final int hashCode() {
+ @Override
+ public final int hashCode() {
return this.hashCode;
}
- @Override public final boolean equals(Object o) {
- return o instanceof TypeLiteral<?>
- && MoreTypes.equals(type, ((TypeLiteral) o).type);
+ @Override
+ public final boolean equals(Object o) {
+ return o instanceof TypeLiteral<?> && MoreTypes.equals(type, ((TypeLiteral) o).type);
}
- @Override public final String toString() {
+ @Override
+ public final String toString() {
return MoreTypes.typeToString(type);
}
- /**
- * Gets type literal for the given {@code Type} instance.
- */
+ /** Gets type literal for the given {@code Type} instance. */
public static TypeLiteral<?> get(Type type) {
return new TypeLiteral<Object>(type);
}
- /**
- * Gets type literal for the given {@code Class} instance.
- */
+ /** Gets type literal for the given {@code Class} instance. */
public static <T> TypeLiteral<T> get(Class<T> type) {
return new TypeLiteral<T>(type);
}
-
/** Returns an immutable list of the resolved types. */
private List<TypeLiteral<?>> resolveAll(Type[] types) {
TypeLiteral<?>[] result = new TypeLiteral<?>[types.length];
@@ -174,9 +159,7 @@ public class TypeLiteral<T> {
return ImmutableList.copyOf(result);
}
- /**
- * Resolves known type parameters in {@code toResolve} and returns the result.
- */
+ /** Resolves known type parameters in {@code toResolve} and returns the result. */
TypeLiteral<?> resolve(Type toResolve) {
return TypeLiteral.get(resolveType(toResolve));
}
@@ -195,9 +178,7 @@ public class TypeLiteral<T> {
GenericArrayType original = (GenericArrayType) toResolve;
Type componentType = original.getGenericComponentType();
Type newComponentType = resolveType(componentType);
- return componentType == newComponentType
- ? original
- : Types.arrayOf(newComponentType);
+ return componentType == newComponentType ? original : Types.arrayOf(newComponentType);
} else if (toResolve instanceof ParameterizedType) {
ParameterizedType original = (ParameterizedType) toResolve;
@@ -254,8 +235,8 @@ public class TypeLiteral<T> {
* @since 2.0
*/
public TypeLiteral<?> getSupertype(Class<?> supertype) {
- checkArgument(supertype.isAssignableFrom(rawType),
- "%s is not a supertype of %s", supertype, this.type);
+ checkArgument(
+ supertype.isAssignableFrom(rawType), "%s is not a supertype of %s", supertype, this.type);
return resolve(MoreTypes.getGenericSupertype(type, rawType, supertype));
}
@@ -266,8 +247,11 @@ public class TypeLiteral<T> {
* @since 2.0
*/
public TypeLiteral<?> getFieldType(Field field) {
- checkArgument(field.getDeclaringClass().isAssignableFrom(rawType),
- "%s is not defined by a supertype of %s", field, type);
+ checkArgument(
+ field.getDeclaringClass().isAssignableFrom(rawType),
+ "%s is not defined by a supertype of %s",
+ field,
+ type);
return resolve(field.getGenericType());
}
@@ -282,14 +266,20 @@ public class TypeLiteral<T> {
if (methodOrConstructor instanceof Method) {
Method method = (Method) methodOrConstructor;
- checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
- "%s is not defined by a supertype of %s", method, type);
+ checkArgument(
+ method.getDeclaringClass().isAssignableFrom(rawType),
+ "%s is not defined by a supertype of %s",
+ method,
+ type);
genericParameterTypes = method.getGenericParameterTypes();
} else if (methodOrConstructor instanceof Constructor) {
Constructor<?> constructor = (Constructor<?>) methodOrConstructor;
- checkArgument(constructor.getDeclaringClass().isAssignableFrom(rawType),
- "%s does not construct a supertype of %s", constructor, type);
+ checkArgument(
+ constructor.getDeclaringClass().isAssignableFrom(rawType),
+ "%s does not construct a supertype of %s",
+ constructor,
+ type);
genericParameterTypes = constructor.getGenericParameterTypes();
} else {
@@ -310,14 +300,20 @@ public class TypeLiteral<T> {
if (methodOrConstructor instanceof Method) {
Method method = (Method) methodOrConstructor;
- checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
- "%s is not defined by a supertype of %s", method, type);
+ checkArgument(
+ method.getDeclaringClass().isAssignableFrom(rawType),
+ "%s is not defined by a supertype of %s",
+ method,
+ type);
genericExceptionTypes = method.getGenericExceptionTypes();
} else if (methodOrConstructor instanceof Constructor) {
Constructor<?> constructor = (Constructor<?>) methodOrConstructor;
- checkArgument(constructor.getDeclaringClass().isAssignableFrom(rawType),
- "%s does not construct a supertype of %s", constructor, type);
+ checkArgument(
+ constructor.getDeclaringClass().isAssignableFrom(rawType),
+ "%s does not construct a supertype of %s",
+ constructor,
+ type);
genericExceptionTypes = constructor.getGenericExceptionTypes();
} else {
@@ -334,8 +330,11 @@ public class TypeLiteral<T> {
* @since 2.0
*/
public TypeLiteral<?> getReturnType(Method method) {
- checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
- "%s is not defined by a supertype of %s", method, type);
+ checkArgument(
+ method.getDeclaringClass().isAssignableFrom(rawType),
+ "%s is not defined by a supertype of %s",
+ method,
+ type);
return resolve(method.getGenericReturnType());
}
}
diff --git a/core/src/com/google/inject/binder/AnnotatedBindingBuilder.java b/core/src/com/google/inject/binder/AnnotatedBindingBuilder.java
index 5b430c38..62ac3d4b 100644
--- a/core/src/com/google/inject/binder/AnnotatedBindingBuilder.java
+++ b/core/src/com/google/inject/binder/AnnotatedBindingBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,14 +25,9 @@ import java.lang.annotation.Annotation;
*/
public interface AnnotatedBindingBuilder<T> extends LinkedBindingBuilder<T> {
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
- LinkedBindingBuilder<T> annotatedWith(
- Class<? extends Annotation> annotationType);
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
+ LinkedBindingBuilder<T> annotatedWith(Class<? extends Annotation> annotationType);
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
LinkedBindingBuilder<T> annotatedWith(Annotation annotation);
}
diff --git a/core/src/com/google/inject/binder/AnnotatedConstantBindingBuilder.java b/core/src/com/google/inject/binder/AnnotatedConstantBindingBuilder.java
index 417027f3..fa57d781 100644
--- a/core/src/com/google/inject/binder/AnnotatedConstantBindingBuilder.java
+++ b/core/src/com/google/inject/binder/AnnotatedConstantBindingBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,14 +25,9 @@ import java.lang.annotation.Annotation;
*/
public interface AnnotatedConstantBindingBuilder {
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
- ConstantBindingBuilder annotatedWith(
- Class<? extends Annotation> annotationType);
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
+ ConstantBindingBuilder annotatedWith(Class<? extends Annotation> annotationType);
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
ConstantBindingBuilder annotatedWith(Annotation annotation);
}
diff --git a/core/src/com/google/inject/binder/AnnotatedElementBuilder.java b/core/src/com/google/inject/binder/AnnotatedElementBuilder.java
index f6feddf4..04b22812 100644
--- a/core/src/com/google/inject/binder/AnnotatedElementBuilder.java
+++ b/core/src/com/google/inject/binder/AnnotatedElementBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,13 +26,9 @@ import java.lang.annotation.Annotation;
*/
public interface AnnotatedElementBuilder {
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
void annotatedWith(Class<? extends Annotation> annotationType);
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
void annotatedWith(Annotation annotation);
}
diff --git a/core/src/com/google/inject/binder/ConstantBindingBuilder.java b/core/src/com/google/inject/binder/ConstantBindingBuilder.java
index 7ddbcf9d..cf1274bd 100644
--- a/core/src/com/google/inject/binder/ConstantBindingBuilder.java
+++ b/core/src/com/google/inject/binder/ConstantBindingBuilder.java
@@ -16,65 +16,43 @@
package com.google.inject.binder;
-/**
- * Binds to a constant value.
- */
+/** Binds to a constant value. */
public interface ConstantBindingBuilder {
- /**
- * Binds constant to the given value.
- */
+ /** Binds constant to the given value. */
void to(String value);
- /**
- * Binds constant to the given value.
- */
+ /** Binds constant to the given value. */
void to(int value);
- /**
- * Binds constant to the given value.
- */
+ /** Binds constant to the given value. */
void to(long value);
- /**
- * Binds constant to the given value.
- */
+ /** Binds constant to the given value. */
void to(boolean value);
- /**
- * Binds constant to the given value.
- */
+ /** Binds constant to the given value. */
void to(double value);
- /**
- * Binds constant to the given value.
- */
+ /** Binds constant to the given value. */
void to(float value);
- /**
- * Binds constant to the given value.
- */
+ /** Binds constant to the given value. */
void to(short value);
- /**
- * Binds constant to the given value.
- */
+ /** Binds constant to the given value. */
void to(char value);
/**
* Binds constant to the given value.
- *
+ *
* @since 3.0
*/
void to(byte value);
- /**
- * Binds constant to the given value.
- */
+ /** Binds constant to the given value. */
void to(Class<?> value);
- /**
- * Binds constant to the given value.
- */
+ /** Binds constant to the given value. */
<E extends Enum<E>> void to(E value);
}
diff --git a/core/src/com/google/inject/binder/LinkedBindingBuilder.java b/core/src/com/google/inject/binder/LinkedBindingBuilder.java
index 99ea1854..219e145a 100644
--- a/core/src/com/google/inject/binder/LinkedBindingBuilder.java
+++ b/core/src/com/google/inject/binder/LinkedBindingBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,6 @@ package com.google.inject.binder;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
-
import java.lang.reflect.Constructor;
/**
@@ -29,19 +28,13 @@ import java.lang.reflect.Constructor;
*/
public interface LinkedBindingBuilder<T> extends ScopedBindingBuilder {
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
ScopedBindingBuilder to(Class<? extends T> implementation);
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
ScopedBindingBuilder to(TypeLiteral<? extends T> implementation);
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
ScopedBindingBuilder to(Key<? extends T> targetKey);
/**
@@ -57,7 +50,7 @@ public interface LinkedBindingBuilder<T> extends ScopedBindingBuilder {
* @see com.google.inject.Injector#injectMembers
*/
ScopedBindingBuilder toProvider(Provider<? extends T> provider);
-
+
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*
@@ -66,34 +59,26 @@ public interface LinkedBindingBuilder<T> extends ScopedBindingBuilder {
*/
ScopedBindingBuilder toProvider(javax.inject.Provider<? extends T> provider);
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
- ScopedBindingBuilder toProvider(
- Class<? extends javax.inject.Provider<? extends T>> providerType);
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
+ ScopedBindingBuilder toProvider(Class<? extends javax.inject.Provider<? extends T>> providerType);
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
ScopedBindingBuilder toProvider(
TypeLiteral<? extends javax.inject.Provider<? extends T>> providerType);
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
- ScopedBindingBuilder toProvider(
- Key<? extends javax.inject.Provider<? extends T>> providerKey);
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
+ ScopedBindingBuilder toProvider(Key<? extends javax.inject.Provider<? extends T>> providerKey);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
- *
+ *
* @since 3.0
*/
<S extends T> ScopedBindingBuilder toConstructor(Constructor<S> constructor);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
- *
+ *
* @since 3.0
*/
<S extends T> ScopedBindingBuilder toConstructor(
diff --git a/core/src/com/google/inject/binder/ScopedBindingBuilder.java b/core/src/com/google/inject/binder/ScopedBindingBuilder.java
index ceb8497d..e907362d 100644
--- a/core/src/com/google/inject/binder/ScopedBindingBuilder.java
+++ b/core/src/com/google/inject/binder/ScopedBindingBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,6 @@
package com.google.inject.binder;
import com.google.inject.Scope;
-
import java.lang.annotation.Annotation;
/**
@@ -27,20 +26,15 @@ import java.lang.annotation.Annotation;
*/
public interface ScopedBindingBuilder {
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
void in(Class<? extends Annotation> scopeAnnotation);
- /**
- * See the EDSL examples at {@link com.google.inject.Binder}.
- */
+ /** See the EDSL examples at {@link com.google.inject.Binder}. */
void in(Scope scope);
/**
- * Instructs the {@link com.google.inject.Injector} to eagerly initialize this
- * singleton-scoped binding upon creation. Useful for application
- * initialization logic. See the EDSL examples at
+ * Instructs the {@link com.google.inject.Injector} to eagerly initialize this singleton-scoped
+ * binding upon creation. Useful for application initialization logic. See the EDSL examples at
* {@link com.google.inject.Binder}.
*/
void asEagerSingleton();
diff --git a/core/src/com/google/inject/binder/package-info.java b/core/src/com/google/inject/binder/package-info.java
index 57ed8754..14e701fa 100644
--- a/core/src/com/google/inject/binder/package-info.java
+++ b/core/src/com/google/inject/binder/package-info.java
@@ -14,8 +14,5 @@
* limitations under the License.
*/
-/**
- * Interfaces which make up {@link com.google.inject.Binder}'s
- * expression language.
- */
-package com.google.inject.binder; \ No newline at end of file
+/** Interfaces which make up {@link com.google.inject.Binder}'s expression language. */
+package com.google.inject.binder;
diff --git a/core/src/com/google/inject/internal/AbstractBindingBuilder.java b/core/src/com/google/inject/internal/AbstractBindingBuilder.java
index e803b75a..6eb07e70 100644
--- a/core/src/com/google/inject/internal/AbstractBindingBuilder.java
+++ b/core/src/com/google/inject/internal/AbstractBindingBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@ import com.google.inject.Key;
import com.google.inject.Scope;
import com.google.inject.spi.Element;
import com.google.inject.spi.InstanceBinding;
-
import java.lang.annotation.Annotation;
import java.util.List;
@@ -35,14 +34,15 @@ import java.util.List;
public abstract class AbstractBindingBuilder<T> {
public static final String IMPLEMENTATION_ALREADY_SET = "Implementation is set more than once.";
- public static final String SINGLE_INSTANCE_AND_SCOPE
- = "Setting the scope is not permitted when binding to a single instance.";
+ public static final String SINGLE_INSTANCE_AND_SCOPE =
+ "Setting the scope is not permitted when binding to a single instance.";
public static final String SCOPE_ALREADY_SET = "Scope is set more than once.";
- public static final String BINDING_TO_NULL = "Binding to null instances is not allowed. "
- + "Use toProvider(Providers.of(null)) if this is your intended behaviour.";
+ public static final String BINDING_TO_NULL =
+ "Binding to null instances is not allowed. "
+ + "Use toProvider(Providers.of(null)) if this is your intended behaviour.";
public static final String CONSTANT_VALUE_ALREADY_SET = "Constant value is set more than once.";
- public static final String ANNOTATION_ALREADY_SPECIFIED
- = "More than one annotation is specified for this binding.";
+ public static final String ANNOTATION_ALREADY_SPECIFIED =
+ "More than one annotation is specified for this binding.";
protected static final Key<?> NULL_KEY = Key.get(Void.class);
@@ -55,7 +55,7 @@ public abstract class AbstractBindingBuilder<T> {
this.binder = binder;
this.elements = elements;
this.position = elements.size();
- this.binding = new UntargettedBindingImpl<T>(source, key, Scoping.UNSCOPED);
+ this.binding = new UntargettedBindingImpl<>(source, key, Scoping.UNSCOPED);
elements.add(position, this.binding);
}
@@ -73,16 +73,15 @@ public abstract class AbstractBindingBuilder<T> {
protected BindingImpl<T> annotatedWithInternal(Class<? extends Annotation> annotationType) {
checkNotNull(annotationType, "annotationType");
checkNotAnnotated();
- return setBinding(binding.withKey(
- Key.get(this.binding.getKey().getTypeLiteral(), annotationType)));
+ return setBinding(
+ binding.withKey(Key.get(this.binding.getKey().getTypeLiteral(), annotationType)));
}
/** Sets the binding to a copy with the specified annotation on the bound key */
protected BindingImpl<T> annotatedWithInternal(Annotation annotation) {
checkNotNull(annotation, "annotation");
checkNotAnnotated();
- return setBinding(binding.withKey(
- Key.get(this.binding.getKey().getTypeLiteral(), annotation)));
+ return setBinding(binding.withKey(Key.get(this.binding.getKey().getTypeLiteral(), annotation)));
}
public void in(final Class<? extends Annotation> scopeAnnotation) {
@@ -129,4 +128,4 @@ public abstract class AbstractBindingBuilder<T> {
binder.addError(SCOPE_ALREADY_SET);
}
}
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/internal/AbstractBindingProcessor.java b/core/src/com/google/inject/internal/AbstractBindingProcessor.java
index e1a0bba9..5d2640de 100644
--- a/core/src/com/google/inject/internal/AbstractBindingProcessor.java
+++ b/core/src/com/google/inject/internal/AbstractBindingProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,11 +30,9 @@ import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.DefaultBindingTargetVisitor;
-import java.util.Set;
-
/**
* Guarantees that processing of Binding elements happens in a sane way.
- *
+ *
* @author sameb@google.com (Sam Berlin)
*/
abstract class AbstractBindingProcessor extends AbstractProcessor {
@@ -42,21 +40,22 @@ abstract class AbstractBindingProcessor extends AbstractProcessor {
// It's unfortunate that we have to maintain a blacklist of specific
// classes, but we can't easily block the whole package because of
// all our unit tests.
- private static final Set<Class<?>> FORBIDDEN_TYPES = ImmutableSet.<Class<?>>of(
- AbstractModule.class,
- Binder.class,
- Binding.class,
- Injector.class,
- Key.class,
- MembersInjector.class,
- Module.class,
- Provider.class,
- Scope.class,
- Stage.class,
- TypeLiteral.class);
-
+ private static final ImmutableSet<Class<?>> FORBIDDEN_TYPES =
+ ImmutableSet.<Class<?>>of(
+ AbstractModule.class,
+ Binder.class,
+ Binding.class,
+ Injector.class,
+ Key.class,
+ MembersInjector.class,
+ Module.class,
+ Provider.class,
+ Scope.class,
+ Stage.class,
+ TypeLiteral.class);
+
protected final ProcessedBindingData bindingData;
-
+
AbstractBindingProcessor(Errors errors, ProcessedBindingData bindingData) {
super(errors);
this.bindingData = bindingData;
@@ -66,7 +65,7 @@ abstract class AbstractBindingProcessor extends AbstractProcessor {
InjectorImpl injector, Key<T> key, Object source) {
return new UntargettedBindingImpl<T>(injector, key, source);
}
-
+
protected void putBinding(BindingImpl<?> binding) {
Key<?> key = binding.getKey();
@@ -81,11 +80,11 @@ abstract class AbstractBindingProcessor extends AbstractProcessor {
// If it failed because of an explicit duplicate binding...
if (injector.state.getExplicitBinding(key) != null) {
try {
- if(!isOkayDuplicate(original, binding, injector.state)) {
+ if (!isOkayDuplicate(original, binding, injector.state)) {
errors.bindingAlreadySet(key, original.getSource());
return;
}
- } catch(Throwable t) {
+ } catch (Throwable t) {
errors.errorCheckingDuplicateBinding(key, original.getSource(), t);
return;
}
@@ -103,8 +102,8 @@ abstract class AbstractBindingProcessor extends AbstractProcessor {
}
/**
- * We tolerate duplicate bindings if one exposes the other or if the two bindings
- * are considered duplicates (see {@link Bindings#areDuplicates(BindingImpl, BindingImpl)}.
+ * We tolerate duplicate bindings if one exposes the other or if the two bindings are considered
+ * duplicates (see {@link Bindings#areDuplicates(BindingImpl, BindingImpl)}.
*
* @param original the binding in the parent injector (candidate for an exposing binding)
* @param binding the binding to check (candidate for the exposed binding)
@@ -115,46 +114,63 @@ abstract class AbstractBindingProcessor extends AbstractProcessor {
InjectorImpl exposedFrom = (InjectorImpl) exposed.getPrivateElements().getInjector();
return (exposedFrom == binding.getInjector());
} else {
- original = (BindingImpl<?>)state.getExplicitBindingsThisLevel().get(binding.getKey());
+ original = (BindingImpl<?>) state.getExplicitBindingsThisLevel().get(binding.getKey());
// If no original at this level, the original was on a parent, and we don't
// allow deduplication between parents & children.
- if(original == null) {
+ if (original == null) {
return false;
} else {
return original.equals(binding);
}
}
}
-
+
private <T> void validateKey(Object source, Key<T> key) {
Annotations.checkForMisplacedScopeAnnotations(
key.getTypeLiteral().getRawType(), source, errors);
}
-
- /**
- * Processor for visiting bindings. Each overriden method that wants to
- * actually process the binding should call prepareBinding first.
+
+ /**
+ * Processor for visiting bindings. Each overriden method that wants to actually process the
+ * binding should call prepareBinding first.
*/
abstract class Processor<T, V> extends DefaultBindingTargetVisitor<T, V> {
final Object source;
final Key<T> key;
final Class<? super T> rawType;
Scoping scoping;
-
+
Processor(BindingImpl<T> binding) {
source = binding.getSource();
key = binding.getKey();
rawType = key.getTypeLiteral().getRawType();
scoping = binding.getScoping();
}
-
- protected void prepareBinding() {
+
+ protected void prepareBinding() {
validateKey(source, key);
scoping = Scoping.makeInjectable(scoping, injector, errors);
}
- protected void scheduleInitialization(final BindingImpl<?> binding) {
- bindingData.addUninitializedBinding(new Runnable() {
+ /**
+ * Schedule initialization of this binding to occur immediately after all bindings have been
+ * initialially processed.
+ */
+ protected void scheduleInitialization(BindingImpl<?> binding) {
+ bindingData.addUninitializedBinding(asRunnable(binding));
+ }
+
+ /**
+ * Schedule initialization for this binding to occur after all other static initialization of
+ * bindings.
+ */
+ protected void scheduleDelayedInitialization(BindingImpl<?> binding) {
+ bindingData.addDelayedUninitializedBinding(asRunnable(binding));
+ }
+
+ private Runnable asRunnable(final BindingImpl<?> binding) {
+ return new Runnable() {
+ @Override
public void run() {
try {
binding.getInjector().initializeBinding(binding, errors.withSource(source));
@@ -162,7 +178,7 @@ abstract class AbstractBindingProcessor extends AbstractProcessor {
errors.merge(e.getErrors());
}
}
- });
+ };
}
}
}
diff --git a/core/src/com/google/inject/internal/AbstractProcessor.java b/core/src/com/google/inject/internal/AbstractProcessor.java
index 2697a99c..6132dd36 100644
--- a/core/src/com/google/inject/internal/AbstractProcessor.java
+++ b/core/src/com/google/inject/internal/AbstractProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,16 +18,14 @@ package com.google.inject.internal;
import com.google.inject.spi.DefaultElementVisitor;
import com.google.inject.spi.Element;
-
import java.util.Iterator;
import java.util.List;
/**
* Abstract base class for creating an injector from module elements.
*
- * <p>Extending classes must return {@code true} from any overridden
- * {@code visit*()} methods, in order for the element processor to remove the
- * handled element.
+ * <p>Extending classes must return {@code true} from any overridden {@code visit*()} methods, in
+ * order for the element processor to remove the handled element.
*
* @author jessewilson@google.com (Jesse Wilson)
*/
@@ -63,7 +61,7 @@ abstract class AbstractProcessor extends DefaultElementVisitor<Boolean> {
this.injector = null;
}
}
-
+
@Override
protected Boolean visitOther(Element element) {
return false;
diff --git a/core/src/com/google/inject/internal/Annotations.java b/core/src/com/google/inject/internal/Annotations.java
index 4c994a95..c8159732 100644
--- a/core/src/com/google/inject/internal/Annotations.java
+++ b/core/src/com/google/inject/internal/Annotations.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,8 @@
package com.google.inject.internal;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Joiner.MapJoiner;
@@ -32,7 +34,6 @@ import com.google.inject.TypeLiteral;
import com.google.inject.internal.util.Classes;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
-
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -43,7 +44,6 @@ import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
-
import javax.inject.Qualifier;
/**
@@ -53,9 +53,7 @@ import javax.inject.Qualifier;
*/
public class Annotations {
- /**
- * Returns {@code true} if the given annotation type has no attributes.
- */
+ /** Returns {@code true} if the given annotation type has no attributes. */
public static boolean isMarker(Class<? extends Annotation> annotationType) {
return annotationType.getDeclaredMethods().length == 0;
}
@@ -72,13 +70,15 @@ public class Annotations {
}
private static final LoadingCache<Class<? extends Annotation>, Annotation> cache =
- CacheBuilder.newBuilder().weakKeys().build(
- new CacheLoader<Class<? extends Annotation>, Annotation>() {
- @Override
- public Annotation load(Class<? extends Annotation> input) {
- return generateAnnotationImpl(input);
- }
- });
+ CacheBuilder.newBuilder()
+ .weakKeys()
+ .build(
+ new CacheLoader<Class<? extends Annotation>, Annotation>() {
+ @Override
+ public Annotation load(Class<? extends Annotation> input) {
+ return generateAnnotationImpl(input);
+ }
+ });
/**
* Generates an Annotation for the annotation class. Requires that the annotation is all
@@ -87,31 +87,32 @@ public class Annotations {
public static <T extends Annotation> T generateAnnotation(Class<T> annotationType) {
Preconditions.checkState(
isAllDefaultMethods(annotationType), "%s is not all default methods", annotationType);
- return (T)cache.getUnchecked(annotationType);
+ return (T) cache.getUnchecked(annotationType);
}
private static <T extends Annotation> T generateAnnotationImpl(final Class<T> annotationType) {
final Map<String, Object> members = resolveMembers(annotationType);
- return annotationType.cast(Proxy.newProxyInstance(
- annotationType.getClassLoader(),
- new Class<?>[] { annotationType },
- new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
- String name = method.getName();
- if (name.equals("annotationType")) {
- return annotationType;
- } else if (name.equals("toString")) {
- return annotationToString(annotationType, members);
- } else if (name.equals("hashCode")) {
- return annotationHashCode(annotationType, members);
- } else if (name.equals("equals")) {
- return annotationEquals(annotationType, members, args[0]);
- } else {
- return members.get(name);
- }
- }
- }));
+ return annotationType.cast(
+ Proxy.newProxyInstance(
+ annotationType.getClassLoader(),
+ new Class<?>[] {annotationType},
+ new InvocationHandler() {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
+ String name = method.getName();
+ if (name.equals("annotationType")) {
+ return annotationType;
+ } else if (name.equals("toString")) {
+ return annotationToString(annotationType, members);
+ } else if (name.equals("hashCode")) {
+ return annotationHashCode(annotationType, members);
+ } else if (name.equals("equals")) {
+ return annotationEquals(annotationType, members, args[0]);
+ } else {
+ return members.get(name);
+ }
+ }
+ }));
}
private static ImmutableMap<String, Object> resolveMembers(
@@ -124,8 +125,9 @@ public class Annotations {
}
/** Implements {@link Annotation#equals}. */
- private static boolean annotationEquals(Class<? extends Annotation> type,
- Map<String, Object> members, Object other) throws Exception {
+ private static boolean annotationEquals(
+ Class<? extends Annotation> type, Map<String, Object> members, Object other)
+ throws Exception {
if (!type.isInstance(other)) {
return false;
}
@@ -140,8 +142,8 @@ public class Annotations {
}
/** Implements {@link Annotation#hashCode}. */
- private static int annotationHashCode(Class<? extends Annotation> type,
- Map<String, Object> members) throws Exception {
+ private static int annotationHashCode(
+ Class<? extends Annotation> type, Map<String, Object> members) throws Exception {
int result = 0;
for (Method method : type.getDeclaredMethods()) {
String name = method.getName();
@@ -153,25 +155,24 @@ public class Annotations {
private static final MapJoiner JOINER = Joiner.on(", ").withKeyValueSeparator("=");
- private static final Function<Object, String> DEEP_TO_STRING_FN = new Function<Object, String>() {
- @Override
- public String apply(Object arg) {
- String s = Arrays.deepToString(new Object[] {arg});
- return s.substring(1, s.length() - 1); // cut off brackets
- }
- };
+ private static final Function<Object, String> DEEP_TO_STRING_FN =
+ new Function<Object, String>() {
+ @Override
+ public String apply(Object arg) {
+ String s = Arrays.deepToString(new Object[] {arg});
+ return s.substring(1, s.length() - 1); // cut off brackets
+ }
+ };
/** Implements {@link Annotation#toString}. */
- private static String annotationToString(Class<? extends Annotation> type,
- Map<String, Object> members) throws Exception {
+ private static String annotationToString(
+ Class<? extends Annotation> type, Map<String, Object> members) throws Exception {
StringBuilder sb = new StringBuilder().append("@").append(type.getName()).append("(");
JOINER.appendTo(sb, Maps.transformValues(members, DEEP_TO_STRING_FN));
return sb.append(")").toString();
}
- /**
- * Returns true if the given annotation is retained at runtime.
- */
+ /** Returns true if the given annotation is retained at runtime. */
public static boolean isRetainedAtRuntime(Class<? extends Annotation> annotationType) {
Retention retention = annotationType.getAnnotation(Retention.class);
return retention != null && retention.value() == RetentionPolicy.RUNTIME;
@@ -184,7 +185,8 @@ public class Annotations {
}
/** Returns the scoping annotation, or null if there isn't one. */
- public static Class<? extends Annotation> findScopeAnnotation(Errors errors, Annotation[] annotations) {
+ public static Class<? extends Annotation> findScopeAnnotation(
+ Errors errors, Annotation[] annotations) {
Class<? extends Annotation> found = null;
for (Annotation annotation : annotations) {
@@ -212,53 +214,77 @@ public class Annotations {
return false;
}
+ private static final boolean QUOTE_MEMBER_VALUES = determineWhetherToQuote();
+
/**
- * Checks for the presence of annotations. Caches results because Android doesn't.
+ * Returns {@code value}, quoted if annotation implementations quote their member values. In Java
+ * 9, annotations quote their string members.
*/
+ public static String memberValueString(String value) {
+ return QUOTE_MEMBER_VALUES ? "\"" + value + "\"" : value;
+ }
+
+ @Retention(RUNTIME)
+ private @interface TestAnnotation {
+ String value();
+ }
+
+ @TestAnnotation("determineWhetherToQuote")
+ private static boolean determineWhetherToQuote() {
+ try {
+ String annotation =
+ Annotations.class
+ .getDeclaredMethod("determineWhetherToQuote")
+ .getAnnotation(TestAnnotation.class)
+ .toString();
+ return annotation.contains("\"determineWhetherToQuote\"");
+ } catch (NoSuchMethodException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ /** Checks for the presence of annotations. Caches results because Android doesn't. */
static class AnnotationChecker {
private final Collection<Class<? extends Annotation>> annotationTypes;
/** Returns true if the given class has one of the desired annotations. */
private CacheLoader<Class<? extends Annotation>, Boolean> hasAnnotations =
new CacheLoader<Class<? extends Annotation>, Boolean>() {
- public Boolean load(Class<? extends Annotation> annotationType) {
- for (Annotation annotation : annotationType.getAnnotations()) {
- if (annotationTypes.contains(annotation.annotationType())) {
- return true;
+ @Override
+ public Boolean load(Class<? extends Annotation> annotationType) {
+ for (Annotation annotation : annotationType.getAnnotations()) {
+ if (annotationTypes.contains(annotation.annotationType())) {
+ return true;
+ }
+ }
+ return false;
}
- }
- return false;
- }
- };
+ };
- final LoadingCache<Class<? extends Annotation>, Boolean> cache = CacheBuilder.newBuilder().weakKeys()
- .build(hasAnnotations);
+ final LoadingCache<Class<? extends Annotation>, Boolean> cache =
+ CacheBuilder.newBuilder().weakKeys().build(hasAnnotations);
- /**
- * Constructs a new checker that looks for annotations of the given types.
- */
+ /** Constructs a new checker that looks for annotations of the given types. */
AnnotationChecker(Collection<Class<? extends Annotation>> annotationTypes) {
this.annotationTypes = annotationTypes;
}
- /**
- * Returns true if the given type has one of the desired annotations.
- */
+ /** Returns true if the given type has one of the desired annotations. */
boolean hasAnnotations(Class<? extends Annotation> annotated) {
return cache.getUnchecked(annotated);
}
}
- private static final AnnotationChecker scopeChecker = new AnnotationChecker(
- Arrays.asList(ScopeAnnotation.class, javax.inject.Scope.class));
+ private static final AnnotationChecker scopeChecker =
+ new AnnotationChecker(Arrays.asList(ScopeAnnotation.class, javax.inject.Scope.class));
public static boolean isScopeAnnotation(Class<? extends Annotation> annotationType) {
return scopeChecker.hasAnnotations(annotationType);
}
/**
- * Adds an error if there is a misplaced annotations on {@code type}. Scoping
- * annotations are not allowed on abstract classes or interfaces.
+ * Adds an error if there is a misplaced annotations on {@code type}. Scoping annotations are not
+ * allowed on abstract classes or interfaces.
*/
public static void checkForMisplacedScopeAnnotations(
Class<?> type, Object source, Errors errors) {
@@ -274,18 +300,20 @@ public class Annotations {
}
}
+ // NOTE: getKey/findBindingAnnotation are used by Gin which is abandoned. So changing this API
+ // will prevent Gin users from upgrading Guice version.
+
/** Gets a key for the given type, member and annotations. */
- public static Key<?> getKey(TypeLiteral<?> type, Member member, Annotation[] annotations,
- Errors errors) throws ErrorsException {
+ public static Key<?> getKey(
+ TypeLiteral<?> type, Member member, Annotation[] annotations, Errors errors)
+ throws ErrorsException {
int numErrorsBefore = errors.size();
Annotation found = findBindingAnnotation(errors, member, annotations);
errors.throwIfNewErrors(numErrorsBefore);
return found == null ? Key.get(type) : Key.get(type, found);
}
- /**
- * Returns the binding annotation on {@code member}, or null if there isn't one.
- */
+ /** Returns the binding annotation on {@code member}, or null if there isn't one. */
public static Annotation findBindingAnnotation(
Errors errors, Member member, Annotation[] annotations) {
Annotation found = null;
@@ -304,23 +332,21 @@ public class Annotations {
return found;
}
- private static final AnnotationChecker bindingAnnotationChecker = new AnnotationChecker(
- Arrays.asList(BindingAnnotation.class, Qualifier.class));
+ private static final AnnotationChecker bindingAnnotationChecker =
+ new AnnotationChecker(Arrays.asList(BindingAnnotation.class, Qualifier.class));
- /**
- * Returns true if annotations of the specified type are binding annotations.
- */
+ /** Returns true if annotations of the specified type are binding annotations. */
public static boolean isBindingAnnotation(Class<? extends Annotation> annotationType) {
return bindingAnnotationChecker.hasAnnotations(annotationType);
}
/**
* If the annotation is an instance of {@code javax.inject.Named}, canonicalizes to
- * com.google.guice.name.Named. Returns the given annotation otherwise.
+ * com.google.guice.name.Named. Returns the given annotation otherwise.
*/
public static Annotation canonicalizeIfNamed(Annotation annotation) {
- if(annotation instanceof javax.inject.Named) {
- return Names.named(((javax.inject.Named)annotation).value());
+ if (annotation instanceof javax.inject.Named) {
+ return Names.named(((javax.inject.Named) annotation).value());
} else {
return annotation;
}
@@ -338,4 +364,22 @@ public class Annotations {
return annotationType;
}
}
+
+ /**
+ * Returns the name the binding should use. This is based on the annotation. If the annotation has
+ * an instance and is not a marker annotation, we ask the annotation for its toString. If it was a
+ * marker annotation or just an annotation type, we use the annotation's name. Otherwise, the name
+ * is the empty string.
+ */
+ public static String nameOf(Key<?> key) {
+ Annotation annotation = key.getAnnotation();
+ Class<? extends Annotation> annotationType = key.getAnnotationType();
+ if (annotation != null && !isMarker(annotationType)) {
+ return key.getAnnotation().toString();
+ } else if (key.getAnnotationType() != null) {
+ return "@" + key.getAnnotationType().getName();
+ } else {
+ return "";
+ }
+ }
}
diff --git a/core/src/com/google/inject/internal/BindingBuilder.java b/core/src/com/google/inject/internal/BindingBuilder.java
index 36c31ffa..100137e1 100644
--- a/core/src/com/google/inject/internal/BindingBuilder.java
+++ b/core/src/com/google/inject/internal/BindingBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,7 +29,6 @@ import com.google.inject.binder.ScopedBindingBuilder;
import com.google.inject.spi.Element;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.Message;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.List;
@@ -47,33 +46,39 @@ public class BindingBuilder<T> extends AbstractBindingBuilder<T>
super(binder, elements, source, key);
}
+ @Override
public BindingBuilder<T> annotatedWith(Class<? extends Annotation> annotationType) {
annotatedWithInternal(annotationType);
return this;
}
+ @Override
public BindingBuilder<T> annotatedWith(Annotation annotation) {
annotatedWithInternal(annotation);
return this;
}
+ @Override
public BindingBuilder<T> to(Class<? extends T> implementation) {
return to(Key.get(implementation));
}
+ @Override
public BindingBuilder<T> to(TypeLiteral<? extends T> implementation) {
return to(Key.get(implementation));
}
+ @Override
public BindingBuilder<T> to(Key<? extends T> linkedKey) {
checkNotNull(linkedKey, "linkedKey");
checkNotTargetted();
BindingImpl<T> base = getBinding();
- setBinding(new LinkedBindingImpl<T>(
- base.getSource(), base.getKey(), base.getScoping(), linkedKey));
+ setBinding(
+ new LinkedBindingImpl<T>(base.getSource(), base.getKey(), base.getScoping(), linkedKey));
return this;
}
+ @Override
public void toInstance(T instance) {
checkNotTargetted();
@@ -92,14 +97,17 @@ public class BindingBuilder<T> extends AbstractBindingBuilder<T>
}
BindingImpl<T> base = getBinding();
- setBinding(new InstanceBindingImpl<T>(
- base.getSource(), base.getKey(), Scoping.EAGER_SINGLETON, injectionPoints, instance));
+ setBinding(
+ new InstanceBindingImpl<T>(
+ base.getSource(), base.getKey(), Scoping.EAGER_SINGLETON, injectionPoints, instance));
}
+ @Override
public BindingBuilder<T> toProvider(Provider<? extends T> provider) {
return toProvider((javax.inject.Provider<T>) provider);
}
+ @Override
public BindingBuilder<T> toProvider(javax.inject.Provider<? extends T> provider) {
checkNotNull(provider, "provider");
checkNotTargetted();
@@ -114,38 +122,45 @@ public class BindingBuilder<T> extends AbstractBindingBuilder<T>
}
BindingImpl<T> base = getBinding();
- setBinding(new ProviderInstanceBindingImpl<T>(
- base.getSource(), base.getKey(), base.getScoping(), injectionPoints, provider));
+ setBinding(
+ new ProviderInstanceBindingImpl<T>(
+ base.getSource(), base.getKey(), base.getScoping(), injectionPoints, provider));
return this;
}
+ @Override
public BindingBuilder<T> toProvider(
Class<? extends javax.inject.Provider<? extends T>> providerType) {
return toProvider(Key.get(providerType));
}
+ @Override
public BindingBuilder<T> toProvider(
TypeLiteral<? extends javax.inject.Provider<? extends T>> providerType) {
return toProvider(Key.get(providerType));
}
+ @Override
public BindingBuilder<T> toProvider(
Key<? extends javax.inject.Provider<? extends T>> providerKey) {
checkNotNull(providerKey, "providerKey");
checkNotTargetted();
BindingImpl<T> base = getBinding();
- setBinding(new LinkedProviderBindingImpl<T>(
- base.getSource(), base.getKey(), base.getScoping(), providerKey));
+ setBinding(
+ new LinkedProviderBindingImpl<T>(
+ base.getSource(), base.getKey(), base.getScoping(), providerKey));
return this;
}
+ @Override
public <S extends T> ScopedBindingBuilder toConstructor(Constructor<S> constructor) {
return toConstructor(constructor, TypeLiteral.get(constructor.getDeclaringClass()));
}
- public <S extends T> ScopedBindingBuilder toConstructor(Constructor<S> constructor,
- TypeLiteral<? extends S> type) {
+ @Override
+ public <S extends T> ScopedBindingBuilder toConstructor(
+ Constructor<S> constructor, TypeLiteral<? extends S> type) {
checkNotNull(constructor, "constructor");
checkNotNull(type, "type");
checkNotTargetted();
@@ -162,16 +177,22 @@ public class BindingBuilder<T> extends AbstractBindingBuilder<T>
try {
InjectionPoint constructorPoint = InjectionPoint.forConstructor(constructor, type);
- setBinding(new ConstructorBindingImpl<T>(base.getKey(), base.getSource(), base.getScoping(),
- constructorPoint, injectionPoints));
+ setBinding(
+ new ConstructorBindingImpl<T>(
+ base.getKey(),
+ base.getSource(),
+ base.getScoping(),
+ constructorPoint,
+ injectionPoints));
} catch (ConfigurationException e) {
copyErrorsToBinder(e);
}
return this;
}
-
- @Override public String toString() {
+
+ @Override
+ public String toString() {
return "BindingBuilder<" + getBinding().getKey().getTypeLiteral() + ">";
}
diff --git a/core/src/com/google/inject/internal/BindingImpl.java b/core/src/com/google/inject/internal/BindingImpl.java
index 3228e3d1..42592962 100644
--- a/core/src/com/google/inject/internal/BindingImpl.java
+++ b/core/src/com/google/inject/internal/BindingImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
package com.google.inject.internal;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
import com.google.inject.Binding;
import com.google.inject.Key;
import com.google.inject.Provider;
@@ -24,9 +24,7 @@ import com.google.inject.spi.BindingScopingVisitor;
import com.google.inject.spi.ElementVisitor;
import com.google.inject.spi.InstanceBinding;
-/**
- * @author crazybob@google.com (Bob Lee)
- */
+/** @author crazybob@google.com (Bob Lee) */
public abstract class BindingImpl<T> implements Binding<T> {
private final InjectorImpl injector;
@@ -35,8 +33,12 @@ public abstract class BindingImpl<T> implements Binding<T> {
private final Scoping scoping;
private final InternalFactory<? extends T> internalFactory;
- public BindingImpl(InjectorImpl injector, Key<T> key, Object source,
- InternalFactory<? extends T> internalFactory, Scoping scoping) {
+ public BindingImpl(
+ InjectorImpl injector,
+ Key<T> key,
+ Object source,
+ InternalFactory<? extends T> internalFactory,
+ Scoping scoping) {
this.injector = injector;
this.key = key;
this.source = source;
@@ -52,16 +54,19 @@ public abstract class BindingImpl<T> implements Binding<T> {
this.scoping = scoping;
}
+ @Override
public Key<T> getKey() {
return key;
}
+ @Override
public Object getSource() {
return source;
}
private volatile Provider<T> provider;
+ @Override
public Provider<T> getProvider() {
if (provider == null) {
if (injector == null) {
@@ -82,17 +87,19 @@ public abstract class BindingImpl<T> implements Binding<T> {
}
/**
- * Is this a constant binding? This returns true for constant bindings as
- * well as toInstance() bindings.
+ * Is this a constant binding? This returns true for constant bindings as well as toInstance()
+ * bindings.
*/
public boolean isConstant() {
return this instanceof InstanceBinding;
}
+ @Override
public <V> V acceptVisitor(ElementVisitor<V> visitor) {
return visitor.visit(this);
}
+ @Override
public <V> V acceptScopingVisitor(BindingScopingVisitor<V> visitor) {
return scoping.acceptVisitor(visitor);
}
@@ -104,9 +111,10 @@ public abstract class BindingImpl<T> implements Binding<T> {
protected BindingImpl<T> withKey(Key<T> key) {
throw new AssertionError();
}
-
- @Override public String toString() {
- return Objects.toStringHelper(Binding.class)
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(Binding.class)
.add("key", key)
.add("scope", scoping)
.add("source", source)
diff --git a/core/src/com/google/inject/internal/BindingProcessor.java b/core/src/com/google/inject/internal/BindingProcessor.java
index b3c869e3..e9c52b4c 100644
--- a/core/src/com/google/inject/internal/BindingProcessor.java
+++ b/core/src/com/google/inject/internal/BindingProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,7 +31,6 @@ import com.google.inject.spi.ProviderBinding;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.ProviderKeyBinding;
import com.google.inject.spi.UntargettedBinding;
-
import java.util.Set;
/**
@@ -49,7 +48,8 @@ final class BindingProcessor extends AbstractBindingProcessor {
this.initializer = initializer;
}
- @Override public <T> Boolean visit(Binding<T> command) {
+ @Override
+ public <T> Boolean visit(Binding<T> command) {
Class<?> rawType = command.getKey().getTypeLiteral().getRawType();
if (Void.class.equals(rawType)) {
if (command instanceof ProviderInstanceBinding
@@ -61,127 +61,183 @@ final class BindingProcessor extends AbstractBindingProcessor {
}
return true;
}
-
+
if (rawType == Provider.class) {
errors.bindingToProvider();
return true;
}
-
- return command.acceptTargetVisitor(new Processor<T, Boolean>((BindingImpl<T>)command) {
- @Override
- public Boolean visit(ConstructorBinding<? extends T> binding) {
- prepareBinding();
- try {
- ConstructorBindingImpl<T> onInjector = ConstructorBindingImpl.create(injector, key,
- binding.getConstructor(), source, scoping, errors, false, false);
- scheduleInitialization(onInjector);
- putBinding(onInjector);
- } catch (ErrorsException e) {
- errors.merge(e.getErrors());
- putBinding(invalidBinding(injector, key, source));
- }
- return true;
- }
- @Override
- public Boolean visit(InstanceBinding<? extends T> binding) {
- prepareBinding();
- Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
- T instance = binding.getInstance();
- @SuppressWarnings("unchecked") // safe to cast to binding<T> because
- // the processor was constructed w/ it
- Initializable<T> ref = initializer.requestInjection(
- injector, instance, (Binding<T>) binding, source, injectionPoints);
- ConstantFactory<? extends T> factory = new ConstantFactory<T>(ref);
- InternalFactory<? extends T> scopedFactory
- = Scoping.scope(key, injector, factory, source, scoping);
- putBinding(new InstanceBindingImpl<T>(injector, key, source, scopedFactory, injectionPoints,
- instance));
- return true;
- }
+ return command.acceptTargetVisitor(
+ new Processor<T, Boolean>((BindingImpl<T>) command) {
+ @Override
+ public Boolean visit(ConstructorBinding<? extends T> binding) {
+ prepareBinding();
+ try {
+ ConstructorBindingImpl<T> onInjector =
+ ConstructorBindingImpl.create(
+ injector,
+ key,
+ binding.getConstructor(),
+ source,
+ scoping,
+ errors,
+ false,
+ false);
+ scheduleInitialization(onInjector);
+ putBinding(onInjector);
+ } catch (ErrorsException e) {
+ errors.merge(e.getErrors());
+ putBinding(invalidBinding(injector, key, source));
+ }
+ return true;
+ }
- @Override
- public Boolean visit(ProviderInstanceBinding<? extends T> binding) {
- prepareBinding();
- javax.inject.Provider<? extends T> provider = binding.getUserSuppliedProvider();
- Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
- Initializable<? extends javax.inject.Provider<? extends T>> initializable =
- initializer.<javax.inject.Provider<? extends T>>requestInjection(
- injector, provider, null, source, injectionPoints);
- // always visited with Binding<T>
- @SuppressWarnings("unchecked")
- InternalFactory<T> factory = new InternalFactoryToInitializableAdapter<T>(
- initializable, source,
- injector.provisionListenerStore.get((ProviderInstanceBinding<T>)binding));
- InternalFactory<? extends T> scopedFactory
- = Scoping.scope(key, injector, factory, source, scoping);
- putBinding(new ProviderInstanceBindingImpl<T>(injector, key, source, scopedFactory, scoping,
- provider, injectionPoints));
- return true;
- }
+ @Override
+ public Boolean visit(InstanceBinding<? extends T> binding) {
+ prepareBinding();
+ Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
+ T instance = binding.getInstance();
+ @SuppressWarnings("unchecked") // safe to cast to binding<T> because
+ // the processor was constructed w/ it
+ Initializable<T> ref =
+ initializer.requestInjection(
+ injector, instance, (Binding<T>) binding, source, injectionPoints);
+ ConstantFactory<? extends T> factory = new ConstantFactory<>(ref);
+ InternalFactory<? extends T> scopedFactory =
+ Scoping.scope(key, injector, factory, source, scoping);
+ putBinding(
+ new InstanceBindingImpl<T>(
+ injector, key, source, scopedFactory, injectionPoints, instance));
+ return true;
+ }
- @Override
- public Boolean visit(ProviderKeyBinding<? extends T> binding) {
- prepareBinding();
- Key<? extends javax.inject.Provider<? extends T>> providerKey = binding.getProviderKey();
- // always visited with Binding<T>
- @SuppressWarnings("unchecked")
- BoundProviderFactory<T> boundProviderFactory = new BoundProviderFactory<T>(
- injector, providerKey, source,
- injector.provisionListenerStore.get((ProviderKeyBinding<T>) binding));
- bindingData.addCreationListener(boundProviderFactory);
- InternalFactory<? extends T> scopedFactory = Scoping.scope(
- key, injector, (InternalFactory<? extends T>) boundProviderFactory, source, scoping);
- putBinding(new LinkedProviderBindingImpl<T>(
- injector, key, source, scopedFactory, scoping, providerKey));
- return true;
- }
+ @Override
+ public Boolean visit(ProviderInstanceBinding<? extends T> binding) {
+ prepareBinding();
+ javax.inject.Provider<? extends T> provider = binding.getUserSuppliedProvider();
+ if (provider instanceof InternalProviderInstanceBindingImpl.Factory) {
+ @SuppressWarnings("unchecked")
+ InternalProviderInstanceBindingImpl.Factory<T> asProviderMethod =
+ (InternalProviderInstanceBindingImpl.Factory<T>) provider;
+ return visitInternalProviderInstanceBindingFactory(asProviderMethod);
+ }
+ Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
+ Initializable<? extends javax.inject.Provider<? extends T>> initializable =
+ initializer.<javax.inject.Provider<? extends T>>requestInjection(
+ injector, provider, null, source, injectionPoints);
+ // always visited with Binding<T>
+ @SuppressWarnings("unchecked")
+ InternalFactory<T> factory =
+ new InternalFactoryToInitializableAdapter<T>(
+ initializable,
+ source,
+ injector.provisionListenerStore.get((ProviderInstanceBinding<T>) binding));
+ InternalFactory<? extends T> scopedFactory =
+ Scoping.scope(key, injector, factory, source, scoping);
+ putBinding(
+ new ProviderInstanceBindingImpl<T>(
+ injector, key, source, scopedFactory, scoping, provider, injectionPoints));
+ return true;
+ }
- @Override
- public Boolean visit(LinkedKeyBinding<? extends T> binding) {
- prepareBinding();
- Key<? extends T> linkedKey = binding.getLinkedKey();
- if (key.equals(linkedKey)) {
- errors.recursiveBinding();
- }
-
- FactoryProxy<T> factory = new FactoryProxy<T>(injector, key, linkedKey, source);
- bindingData.addCreationListener(factory);
- InternalFactory<? extends T> scopedFactory
- = Scoping.scope(key, injector, factory, source, scoping);
- putBinding(
- new LinkedBindingImpl<T>(injector, key, source, scopedFactory, scoping, linkedKey));
- return true;
- }
+ @Override
+ public Boolean visit(ProviderKeyBinding<? extends T> binding) {
+ prepareBinding();
+ Key<? extends javax.inject.Provider<? extends T>> providerKey =
+ binding.getProviderKey();
+ // always visited with Binding<T>
+ @SuppressWarnings("unchecked")
+ BoundProviderFactory<T> boundProviderFactory =
+ new BoundProviderFactory<T>(
+ injector,
+ providerKey,
+ source,
+ injector.provisionListenerStore.get((ProviderKeyBinding<T>) binding));
+ bindingData.addCreationListener(boundProviderFactory);
+ InternalFactory<? extends T> scopedFactory =
+ Scoping.scope(
+ key,
+ injector,
+ (InternalFactory<? extends T>) boundProviderFactory,
+ source,
+ scoping);
+ putBinding(
+ new LinkedProviderBindingImpl<T>(
+ injector, key, source, scopedFactory, scoping, providerKey));
+ return true;
+ }
- @Override
- public Boolean visit(UntargettedBinding<? extends T> untargetted) {
- return false;
- }
+ @Override
+ public Boolean visit(LinkedKeyBinding<? extends T> binding) {
+ prepareBinding();
+ Key<? extends T> linkedKey = binding.getLinkedKey();
+ if (key.equals(linkedKey)) {
+ errors.recursiveBinding();
+ }
- @Override
- public Boolean visit(ExposedBinding<? extends T> binding) {
- throw new IllegalArgumentException("Cannot apply a non-module element");
- }
-
- @Override
- public Boolean visit(ConvertedConstantBinding<? extends T> binding) {
- throw new IllegalArgumentException("Cannot apply a non-module element");
- }
-
- @Override
- public Boolean visit(ProviderBinding<? extends T> binding) {
- throw new IllegalArgumentException("Cannot apply a non-module element");
- }
-
- @Override
- protected Boolean visitOther(Binding<? extends T> binding) {
- throw new IllegalStateException("BindingProcessor should override all visitations");
- }
- });
+ FactoryProxy<T> factory = new FactoryProxy<>(injector, key, linkedKey, source);
+ bindingData.addCreationListener(factory);
+ InternalFactory<? extends T> scopedFactory =
+ Scoping.scope(key, injector, factory, source, scoping);
+ putBinding(
+ new LinkedBindingImpl<T>(injector, key, source, scopedFactory, scoping, linkedKey));
+ return true;
+ }
+
+ /** Handle ProviderMethods specially. */
+ private Boolean visitInternalProviderInstanceBindingFactory(
+ InternalProviderInstanceBindingImpl.Factory<T> provider) {
+ InternalProviderInstanceBindingImpl<T> binding =
+ new InternalProviderInstanceBindingImpl<T>(
+ injector,
+ key,
+ source,
+ provider,
+ Scoping.scope(key, injector, provider, source, scoping),
+ scoping);
+ switch (binding.getInitializationTiming()) {
+ case DELAYED:
+ scheduleDelayedInitialization(binding);
+ break;
+ case EAGER:
+ scheduleInitialization(binding);
+ break;
+ default:
+ throw new AssertionError();
+ }
+ putBinding(binding);
+ return true;
+ }
+
+ @Override
+ public Boolean visit(UntargettedBinding<? extends T> untargetted) {
+ return false;
+ }
+
+ @Override
+ public Boolean visit(ExposedBinding<? extends T> binding) {
+ throw new IllegalArgumentException("Cannot apply a non-module element");
+ }
+
+ @Override
+ public Boolean visit(ConvertedConstantBinding<? extends T> binding) {
+ throw new IllegalArgumentException("Cannot apply a non-module element");
+ }
+
+ @Override
+ public Boolean visit(ProviderBinding<? extends T> binding) {
+ throw new IllegalArgumentException("Cannot apply a non-module element");
+ }
+
+ @Override
+ protected Boolean visitOther(Binding<? extends T> binding) {
+ throw new IllegalStateException("BindingProcessor should override all visitations");
+ }
+ });
}
- @Override public Boolean visit(PrivateElements privateElements) {
+ @Override
+ public Boolean visit(PrivateElements privateElements) {
for (Key<?> key : privateElements.getExposedKeys()) {
bindExposed(privateElements, key);
}
@@ -189,9 +245,14 @@ final class BindingProcessor extends AbstractBindingProcessor {
}
private <T> void bindExposed(PrivateElements privateElements, Key<T> key) {
- ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<T>(key, privateElements);
+ ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<>(key, privateElements);
bindingData.addCreationListener(exposedKeyFactory);
- putBinding(new ExposedBindingImpl<T>(
- injector, privateElements.getExposedSource(key), key, exposedKeyFactory, privateElements));
+ putBinding(
+ new ExposedBindingImpl<T>(
+ injector,
+ privateElements.getExposedSource(key),
+ key,
+ exposedKeyFactory,
+ privateElements));
}
}
diff --git a/core/src/com/google/inject/internal/BoundProviderFactory.java b/core/src/com/google/inject/internal/BoundProviderFactory.java
index 9f523dfa..eaaf7678 100644
--- a/core/src/com/google/inject/internal/BoundProviderFactory.java
+++ b/core/src/com/google/inject/internal/BoundProviderFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,12 @@
package com.google.inject.internal;
-import static com.google.common.base.Preconditions.checkNotNull;
-
import com.google.inject.Key;
import com.google.inject.internal.InjectorImpl.JitLimitation;
import com.google.inject.spi.Dependency;
-
import javax.inject.Provider;
-/**
- * Delegates to a custom factory which is also bound in the injector.
- */
+/** Delegates to a custom factory which is also bound in the injector. */
final class BoundProviderFactory<T> extends ProviderInternalFactory<T> implements CreationListener {
private final ProvisionListenerStackCallback<T> provisionCallback;
@@ -40,42 +35,53 @@ final class BoundProviderFactory<T> extends ProviderInternalFactory<T> implement
Object source,
ProvisionListenerStackCallback<T> provisionCallback) {
super(source);
- this.provisionCallback = checkNotNull(provisionCallback, "provisionCallback");
+ this.provisionCallback = provisionCallback;
this.injector = injector;
this.providerKey = providerKey;
}
+ @Override
public void notify(Errors errors) {
try {
- providerFactory = injector.getInternalFactory(providerKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT);
+ providerFactory =
+ injector.getInternalFactory(
+ providerKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
}
}
- public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
- throws ErrorsException {
+ @Override
+ public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+ throws InternalProvisionException {
context.pushState(providerKey, source);
+
try {
- errors = errors.withSource(providerKey);
- javax.inject.Provider<? extends T> provider = providerFactory.get(errors, context, dependency, true);
- return circularGet(provider, errors, context, dependency, provisionCallback);
- } finally {
- context.popState();
+ javax.inject.Provider<? extends T> provider = providerFactory.get(context, dependency, true);
+ return circularGet(provider, context, dependency, provisionCallback);
+ } catch (InternalProvisionException ipe) {
+ throw ipe.addSource(providerKey);
+ } finally {
+ context.popState();
+
}
}
-
+
@Override
- protected T provision(Provider<? extends T> provider, Errors errors, Dependency<?> dependency,
- ConstructionContext<T> constructionContext) throws ErrorsException {
+ protected T provision(
+ Provider<? extends T> provider,
+ Dependency<?> dependency,
+ ConstructionContext<T> constructionContext)
+ throws InternalProvisionException {
try {
- return super.provision(provider, errors, dependency, constructionContext);
- } catch(RuntimeException userException) {
- throw errors.errorInProvider(userException).toException();
- }
+ return super.provision(provider, dependency, constructionContext);
+ } catch (RuntimeException userException) {
+ throw InternalProvisionException.errorInProvider(userException);
+ }
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return providerKey.toString();
}
}
diff --git a/core/src/com/google/inject/internal/BytecodeGen.java b/core/src/com/google/inject/internal/BytecodeGen.java
index ed01cd10..2ec96cb3 100644
--- a/core/src/com/google/inject/internal/BytecodeGen.java
+++ b/core/src/com/google/inject/internal/BytecodeGen.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,13 +22,13 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.inject.internal.InternalFlags.CustomClassLoadingOption;
-
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
+import java.util.logging.Level;
import java.util.logging.Logger;
/**
@@ -37,24 +37,26 @@ import java.util.logging.Logger;
* interceptors} and to proxy circular dependencies.
*
* <p>When loading classes, we need to be careful of:
+ *
* <ul>
- * <li><strong>Memory leaks.</strong> Generated classes need to be garbage collected in long-lived
- * applications. Once an injector and any instances it created can be garbage collected, the
- * corresponding generated classes should be collectable.
- * <li><strong>Visibility.</strong> Containers like <code>OSGi</code> use class loader boundaries
- * to enforce modularity at runtime.
+ * <li><strong>Memory leaks.</strong> Generated classes need to be garbage collected in long-lived
+ * applications. Once an injector and any instances it created can be garbage collected, the
+ * corresponding generated classes should be collectable.
+ * <li><strong>Visibility.</strong> Containers like <code>OSGi</code> use class loader boundaries to
+ * enforce modularity at runtime.
* </ul>
*
* <p>For each generated class, there's multiple class loaders involved:
+ *
* <ul>
- * <li><strong>The related class's class loader.</strong> Every generated class services exactly
- * one user-supplied class. This class loader must be used to access members with private and
- * package visibility.
- * <li><strong>Guice's class loader.</strong>
- * <li><strong>Our bridge class loader.</strong> This is a child of the user's class loader. It
- * selectively delegates to either the user's class loader (for user classes) or the Guice
- * class loader (for internal classes that are used by the generated classes). This class
- * loader that owns the classes generated by Guice.
+ * <li><strong>The related class's class loader.</strong> Every generated class services exactly one
+ * user-supplied class. This class loader must be used to access members with protected and
+ * package visibility.
+ * <li><strong>Guice's class loader.</strong>
+ * <li><strong>Our bridge class loader.</strong> This is a child of the user's class loader. It
+ * selectively delegates to either the user's class loader (for user classes) or the Guice class
+ * loader (for internal classes that are used by the generated classes). This class loader that
+ * owns the classes generated by Guice.
* </ul>
*
* @author mcculls@gmail.com (Stuart McCulloch)
@@ -72,56 +74,57 @@ public final class BytecodeGen {
}
/** ie. "com.google.inject.internal" */
- static final String GUICE_INTERNAL_PACKAGE
- = BytecodeGen.class.getName().replaceFirst("\\.internal\\..*$", ".internal");
+ static final String GUICE_INTERNAL_PACKAGE =
+ BytecodeGen.class.getName().replaceFirst("\\.internal\\..*$", ".internal");
/*if[AOP]*/
/** either "net.sf.cglib", or "com.google.inject.internal.cglib" */
- static final String CGLIB_PACKAGE
- = net.sf.cglib.proxy.Enhancer.class.getName().replaceFirst("\\.cglib\\..*$", ".cglib");
-
- static final net.sf.cglib.core.NamingPolicy FASTCLASS_NAMING_POLICY
- = new net.sf.cglib.core.DefaultNamingPolicy() {
- @Override protected String getTag() {
- return "ByGuice";
- }
+ static final String CGLIB_PACKAGE =
+ net.sf.cglib.proxy.Enhancer.class.getName().replaceFirst("\\.cglib\\..*$", ".cglib");
+
+ static final net.sf.cglib.core.NamingPolicy FASTCLASS_NAMING_POLICY =
+ new net.sf.cglib.core.DefaultNamingPolicy() {
+ @Override
+ protected String getTag() {
+ return "ByGuice";
+ }
- @Override
- public String getClassName(String prefix, String source, Object key,
- net.sf.cglib.core.Predicate names) {
- // we explicitly set the source here to "FastClass" so that our jarjar renaming
- // to $FastClass doesn't leak into the class names. if we did not do this,
- // classes would end up looking like $$$FastClassByGuice$$, with the extra $
- // at the front.
- return super.getClassName(prefix, "FastClass", key, names);
- }
- };
+ @Override
+ public String getClassName(
+ String prefix, String source, Object key, net.sf.cglib.core.Predicate names) {
+ // we explicitly set the source here to "FastClass" so that our jarjar renaming
+ // to $FastClass doesn't leak into the class names. if we did not do this,
+ // classes would end up looking like $$$FastClassByGuice$$, with the extra $
+ // at the front.
+ return super.getClassName(prefix, "FastClass", key, names);
+ }
+ };
- static final net.sf.cglib.core.NamingPolicy ENHANCER_NAMING_POLICY
- = new net.sf.cglib.core.DefaultNamingPolicy() {
- @Override
- protected String getTag() {
- return "ByGuice";
- }
+ static final net.sf.cglib.core.NamingPolicy ENHANCER_NAMING_POLICY =
+ new net.sf.cglib.core.DefaultNamingPolicy() {
+ @Override
+ protected String getTag() {
+ return "ByGuice";
+ }
- @Override
- public String getClassName(String prefix, String source, Object key,
- net.sf.cglib.core.Predicate names) {
- // we explicitly set the source here to "Enhancer" so that our jarjar renaming
- // to $Enhancer doesn't leak into the class names. if we did not do this,
- // classes would end up looking like $$$EnhancerByGuice$$, with the extra $
- // at the front.
- return super.getClassName(prefix, "Enhancer", key, names);
- }
- };
+ @Override
+ public String getClassName(
+ String prefix, String source, Object key, net.sf.cglib.core.Predicate names) {
+ // we explicitly set the source here to "Enhancer" so that our jarjar renaming
+ // to $Enhancer doesn't leak into the class names. if we did not do this,
+ // classes would end up looking like $$$EnhancerByGuice$$, with the extra $
+ // at the front.
+ return super.getClassName(prefix, "Enhancer", key, names);
+ }
+ };
/*end[AOP]*/
/*if[NO_AOP]
private static final String CGLIB_PACKAGE = " "; // any string that's illegal in a package name
end[NO_AOP]*/
/**
- * Weak cache of bridge class loaders that make the Guice implementation
- * classes visible to various code-generated proxies of client classes.
+ * Weak cache of bridge class loaders that make the Guice implementation classes visible to
+ * various code-generated proxies of client classes.
*/
private static final LoadingCache<ClassLoader, ClassLoader> CLASS_LOADER_CACHE;
@@ -130,30 +133,32 @@ public final class BytecodeGen {
if (getCustomClassLoadingOption() == CustomClassLoadingOption.OFF) {
builder.maximumSize(0);
}
- CLASS_LOADER_CACHE = builder.build(
- new CacheLoader<ClassLoader, ClassLoader>() {
- @Override public ClassLoader load(final ClassLoader typeClassLoader) {
- logger.fine("Creating a bridge ClassLoader for " + typeClassLoader);
- return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
- public ClassLoader run() {
- return new BridgeClassLoader(typeClassLoader);
+ CLASS_LOADER_CACHE =
+ builder.build(
+ new CacheLoader<ClassLoader, ClassLoader>() {
+ @Override
+ public ClassLoader load(final ClassLoader typeClassLoader) {
+ logger.fine("Creating a bridge ClassLoader for " + typeClassLoader);
+ return AccessController.doPrivileged(
+ new PrivilegedAction<ClassLoader>() {
+ @Override
+ public ClassLoader run() {
+ return new BridgeClassLoader(typeClassLoader);
+ }
+ });
}
});
- }
- });
}
/**
- * Attempts to canonicalize null references to the system class loader.
- * May return null if for some reason the system loader is unavailable.
+ * Attempts to canonicalize null references to the system class loader. May return null if for
+ * some reason the system loader is unavailable.
*/
private static ClassLoader canonicalize(ClassLoader classLoader) {
return classLoader != null ? classLoader : SystemBridgeHolder.SYSTEM_BRIDGE.getParent();
}
- /**
- * Returns the class loader to host generated classes for {@code type}.
- */
+ /** Returns the class loader to host generated classes for {@code type}. */
public static ClassLoader getClassLoader(Class<?> type) {
return getClassLoader(type, type.getClassLoader());
}
@@ -191,19 +196,108 @@ public final class BytecodeGen {
}
/*if[AOP]*/
- // use fully-qualified names so imports don't need preprocessor statements
- public static net.sf.cglib.reflect.FastClass newFastClass(Class<?> type, Visibility visibility) {
- net.sf.cglib.reflect.FastClass.Generator generator
- = new net.sf.cglib.reflect.FastClass.Generator();
- generator.setType(type);
- if (visibility == Visibility.PUBLIC) {
+ // use fully-qualified names so imports don't need preprocessor statements
+ /**
+ * Returns a FastClass proxy for invoking the given member or {@code null} if access rules
+ * disallow it.
+ *
+ * @see #newFastClassForMember(Class, Member) for a full description
+ */
+ public static net.sf.cglib.reflect.FastClass newFastClassForMember(Member member) {
+ return newFastClassForMember(member.getDeclaringClass(), member);
+ }
+
+ /**
+ * Returns a FastClass proxy for invoking the given member or {@code null} if access rules
+ * disallow it.
+ *
+ * <p>FastClass works by generating a type in the same package as the target {@code type}. This
+ * may or may not work depending on the access level of the class/member. It breaks down into the
+ * following cases depending on accessibility:
+ *
+ * <ul>
+ * <li>Public: This always works since we can generate the type into the {@link BridgeClassLoader}
+ * which ensures there are no versioning issues.
+ * <li>Package private and Protected: This works as long as:
+ * <ul>
+ * <li>We can generate into the same classloader as the type. This is not possible for JDK
+ * types which use the 'bootstrap' loader.
+ * <li>The classloader of the type has the same version of {@code FastClass} as we do. This
+ * may be violated when running in OSGI bundles.
+ * </ul>
+ *
+ * <li>Private: This never works.
+ * </ul>
+ *
+ * If we are unable to generate the type, then we return null and callers should work around by
+ * using normal java reflection.
+ */
+ public static net.sf.cglib.reflect.FastClass newFastClassForMember(Class<?> type, Member member) {
+ if (!new net.sf.cglib.core.VisibilityPredicate(type, false).evaluate(member)) {
+ // the member cannot be indexed by fast class. Bail out.
+ return null;
+ }
+
+ boolean publiclyCallable = isPubliclyCallable(member);
+ if (!publiclyCallable && !hasSameVersionOfCglib(type.getClassLoader())) {
+ // The type is in a classloader with a different version of cglib and is not publicly visible
+ // (so we can't use the bridge classloader to work around). Bail out.
+ return null;
+ }
+ net.sf.cglib.reflect.FastClass.Generator generator =
+ new net.sf.cglib.reflect.FastClass.Generator();
+ if (publiclyCallable) {
+ // Use the bridge classloader if we can
generator.setClassLoader(getClassLoader(type));
}
+ generator.setType(type);
generator.setNamingPolicy(FASTCLASS_NAMING_POLICY);
- logger.fine("Loading " + type + " FastClass with " + generator.getClassLoader());
+ if (logger.isLoggable(Level.FINE)) {
+ logger.fine("Loading " + type + " FastClass with " + generator.getClassLoader());
+ }
return generator.create();
}
+ /**
+ * Returns true if the types classloader has the same version of cglib that BytecodeGen has. This
+ * only returns false in strange OSGI situations, but it prevents us from using FastClass for non
+ * public members.
+ */
+ private static boolean hasSameVersionOfCglib(ClassLoader classLoader) {
+ Class<?> fc = net.sf.cglib.reflect.FastClass.class;
+ try {
+ return classLoader.loadClass(fc.getName()) == fc;
+ } catch (ClassNotFoundException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Returns true if the member can be called by a fast class generated in a different classloader.
+ */
+ private static boolean isPubliclyCallable(Member member) {
+ if (!Modifier.isPublic(member.getModifiers())) {
+ return false;
+ }
+ Class<?>[] parameterTypes;
+ if (member instanceof Constructor) {
+ parameterTypes = ((Constructor) member).getParameterTypes();
+ } else {
+ Method method = (Method) member;
+ if (!Modifier.isPublic(method.getReturnType().getModifiers())) {
+ return false;
+ }
+ parameterTypes = method.getParameterTypes();
+ }
+
+ for (Class<?> type : parameterTypes) {
+ if (!Modifier.isPublic(type.getModifiers())) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public static net.sf.cglib.proxy.Enhancer newEnhancer(Class<?> type, Visibility visibility) {
net.sf.cglib.proxy.Enhancer enhancer = new net.sf.cglib.proxy.Enhancer();
enhancer.setSuperclass(type);
@@ -298,10 +392,10 @@ public final class BytecodeGen {
super(usersClassLoader);
}
- @Override protected Class<?> loadClass(String name, boolean resolve)
- throws ClassNotFoundException {
+ @Override
+ protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
- if (name.startsWith("sun.reflect")) {
+ if (name.startsWith("sun.reflect") || name.startsWith("jdk.internal.reflect")) {
// these reflection classes must be loaded from bootstrap class loader
return SystemBridgeHolder.SYSTEM_BRIDGE.classicLoadClass(name, resolve);
}
@@ -326,8 +420,7 @@ public final class BytecodeGen {
}
// make the classic delegating loadClass method visible
- Class<?> classicLoadClass(String name, boolean resolve)
- throws ClassNotFoundException {
+ Class<?> classicLoadClass(String name, boolean resolve) throws ClassNotFoundException {
return super.loadClass(name, resolve);
}
}
diff --git a/core/src/com/google/inject/internal/CircularDependencyProxy.java b/core/src/com/google/inject/internal/CircularDependencyProxy.java
index fe894a40..dc127480 100644
--- a/core/src/com/google/inject/internal/CircularDependencyProxy.java
+++ b/core/src/com/google/inject/internal/CircularDependencyProxy.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,7 @@
package com.google.inject.internal;
-/**
- * @author jessewilson@google.com (Jesse Wilson)
- */
+/** @author jessewilson@google.com (Jesse Wilson) */
public interface CircularDependencyProxy {
// marker interface
}
diff --git a/core/src/com/google/inject/internal/ConstantBindingBuilderImpl.java b/core/src/com/google/inject/internal/ConstantBindingBuilderImpl.java
index 8a0c5c6a..1c11cfe4 100644
--- a/core/src/com/google/inject/internal/ConstantBindingBuilderImpl.java
+++ b/core/src/com/google/inject/internal/ConstantBindingBuilderImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@ import com.google.inject.binder.AnnotatedConstantBindingBuilder;
import com.google.inject.binder.ConstantBindingBuilder;
import com.google.inject.spi.Element;
import com.google.inject.spi.InjectionPoint;
-
import java.lang.annotation.Annotation;
import java.util.List;
@@ -32,8 +31,7 @@ import java.util.List;
*
* @author jessewilson@google.com (Jesse Wilson)
*/
-public final class ConstantBindingBuilderImpl<T>
- extends AbstractBindingBuilder<T>
+public final class ConstantBindingBuilderImpl<T> extends AbstractBindingBuilder<T>
implements AnnotatedConstantBindingBuilder, ConstantBindingBuilder {
@SuppressWarnings("unchecked") // constant bindings start out with T unknown
@@ -41,56 +39,69 @@ public final class ConstantBindingBuilderImpl<T>
super(binder, elements, source, (Key<T>) NULL_KEY);
}
+ @Override
public ConstantBindingBuilder annotatedWith(Class<? extends Annotation> annotationType) {
annotatedWithInternal(annotationType);
return this;
}
+ @Override
public ConstantBindingBuilder annotatedWith(Annotation annotation) {
annotatedWithInternal(annotation);
return this;
}
+ @Override
public void to(final String value) {
toConstant(String.class, value);
}
+ @Override
public void to(final int value) {
toConstant(Integer.class, value);
}
+ @Override
public void to(final long value) {
toConstant(Long.class, value);
}
+ @Override
public void to(final boolean value) {
toConstant(Boolean.class, value);
}
+ @Override
public void to(final double value) {
toConstant(Double.class, value);
}
+ @Override
public void to(final float value) {
toConstant(Float.class, value);
}
+ @Override
public void to(final short value) {
toConstant(Short.class, value);
}
+ @Override
public void to(final char value) {
toConstant(Character.class, value);
}
+ @Override
public void to(final byte value) {
toConstant(Byte.class, value);
- }
+ }
+ @Override
public void to(final Class<?> value) {
toConstant(Class.class, value);
}
+ @Override
public <E extends Enum<E>> void to(final E value) {
toConstant(value.getDeclaringClass(), value);
}
@@ -121,11 +132,17 @@ public final class ConstantBindingBuilderImpl<T>
binder.addError(BINDING_TO_NULL);
}
- setBinding(new InstanceBindingImpl<T>(
- base.getSource(), key, base.getScoping(), ImmutableSet.<InjectionPoint>of(), instanceAsT));
+ setBinding(
+ new InstanceBindingImpl<T>(
+ base.getSource(),
+ key,
+ base.getScoping(),
+ ImmutableSet.<InjectionPoint>of(),
+ instanceAsT));
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "ConstantBindingBuilder";
}
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/internal/ConstantFactory.java b/core/src/com/google/inject/internal/ConstantFactory.java
index 633d5de0..d9320036 100644
--- a/core/src/com/google/inject/internal/ConstantFactory.java
+++ b/core/src/com/google/inject/internal/ConstantFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,12 +16,10 @@
package com.google.inject.internal;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
import com.google.inject.spi.Dependency;
-/**
- * @author crazybob@google.com (Bob Lee)
- */
+/** @author crazybob@google.com (Bob Lee) */
final class ConstantFactory<T> implements InternalFactory<T> {
private final Initializable<T> initializable;
@@ -30,14 +28,14 @@ final class ConstantFactory<T> implements InternalFactory<T> {
this.initializable = initializable;
}
- public T get(Errors errors, InternalContext context, Dependency dependency, boolean linked)
- throws ErrorsException {
- return initializable.get(errors);
+ @Override
+ public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+ throws InternalProvisionException {
+ return initializable.get();
}
+ @Override
public String toString() {
- return Objects.toStringHelper(ConstantFactory.class)
- .add("value", initializable)
- .toString();
+ return MoreObjects.toStringHelper(ConstantFactory.class).add("value", initializable).toString();
}
}
diff --git a/core/src/com/google/inject/internal/ConstructionContext.java b/core/src/com/google/inject/internal/ConstructionContext.java
index ced388f6..25786f59 100644
--- a/core/src/com/google/inject/internal/ConstructionContext.java
+++ b/core/src/com/google/inject/internal/ConstructionContext.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,6 @@
package com.google.inject.internal;
import com.google.inject.internal.InjectorImpl.InjectorOptions;
-
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
@@ -59,28 +58,31 @@ final class ConstructionContext<T> {
invocationHandlers = null;
}
- public Object createProxy(Errors errors, InjectorOptions injectorOptions,
- Class<?> expectedType) throws ErrorsException {
+ public Object createProxy(InjectorOptions injectorOptions, Class<?> expectedType)
+ throws InternalProvisionException {
if (injectorOptions.disableCircularProxies) {
- throw errors.circularProxiesDisabled(expectedType).toException();
+ throw InternalProvisionException.circularDependenciesDisabled(expectedType);
}
if (!expectedType.isInterface()) {
- throw errors.cannotSatisfyCircularDependency(expectedType).toException();
+ throw InternalProvisionException.cannotProxyClass(expectedType);
}
if (invocationHandlers == null) {
- invocationHandlers = new ArrayList<DelegatingInvocationHandler<T>>();
+ invocationHandlers = new ArrayList<>();
}
- DelegatingInvocationHandler<T> invocationHandler = new DelegatingInvocationHandler<T>();
+ DelegatingInvocationHandler<T> invocationHandler = new DelegatingInvocationHandler<>();
invocationHandlers.add(invocationHandler);
// TODO: if I create a proxy which implements all the interfaces of
// the implementation type, I'll be able to get away with one proxy
// instance (as opposed to one per caller).
ClassLoader classLoader = BytecodeGen.getClassLoader(expectedType);
- return expectedType.cast(Proxy.newProxyInstance(classLoader,
- new Class[] { expectedType, CircularDependencyProxy.class }, invocationHandler));
+ return expectedType.cast(
+ Proxy.newProxyInstance(
+ classLoader,
+ new Class[] {expectedType, CircularDependencyProxy.class},
+ invocationHandler));
}
public void setProxyDelegates(T delegate) {
diff --git a/core/src/com/google/inject/internal/ConstructionProxy.java b/core/src/com/google/inject/internal/ConstructionProxy.java
index 6c6f3fcc..2f56cf0b 100644
--- a/core/src/com/google/inject/internal/ConstructionProxy.java
+++ b/core/src/com/google/inject/internal/ConstructionProxy.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,28 +18,22 @@ package com.google.inject.internal;
import com.google.common.collect.ImmutableMap;
import com.google.inject.spi.InjectionPoint;
-
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
/**
- * Proxies calls to a {@link java.lang.reflect.Constructor} for a class
- * {@code T}.
+ * Proxies calls to a {@link java.lang.reflect.Constructor} for a class {@code T}.
*
* @author crazybob@google.com (Bob Lee)
*/
interface ConstructionProxy<T> {
- /**
- * Constructs an instance of {@code T} for the given arguments.
- */
+ /** Constructs an instance of {@code T} for the given arguments. */
T newInstance(Object... arguments) throws InvocationTargetException;
- /**
- * Returns the injection point for this constructor.
- */
+ /** Returns the injection point for this constructor. */
InjectionPoint getInjectionPoint();
/**
@@ -49,9 +43,7 @@ interface ConstructionProxy<T> {
Constructor<T> getConstructor();
/*if[AOP]*/
- /**
- * Returns the interceptors applied to each method, in order of invocation.
- */
+ /** Returns the interceptors applied to each method, in order of invocation. */
ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>> getMethodInterceptors();
/*end[AOP]*/
}
diff --git a/core/src/com/google/inject/internal/ConstructionProxyFactory.java b/core/src/com/google/inject/internal/ConstructionProxyFactory.java
index 0eca0fe7..51225242 100644
--- a/core/src/com/google/inject/internal/ConstructionProxyFactory.java
+++ b/core/src/com/google/inject/internal/ConstructionProxyFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,8 +23,6 @@ package com.google.inject.internal;
*/
interface ConstructionProxyFactory<T> {
- /**
- * Gets a construction proxy for the given constructor.
- */
+ /** Gets a construction proxy for the given constructor. */
ConstructionProxy<T> create() throws ErrorsException;
}
diff --git a/core/src/com/google/inject/internal/ConstructorBindingImpl.java b/core/src/com/google/inject/internal/ConstructorBindingImpl.java
index 8fb21035..d141d65f 100644
--- a/core/src/com/google/inject/internal/ConstructorBindingImpl.java
+++ b/core/src/com/google/inject/internal/ConstructorBindingImpl.java
@@ -19,6 +19,7 @@ package com.google.inject.internal;
import static com.google.common.base.Preconditions.checkState;
import static com.google.inject.internal.Annotations.findScopeAnnotation;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
@@ -31,7 +32,6 @@ import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.ConstructorBinding;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.InjectionPoint;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
@@ -46,44 +46,60 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T>
private final Factory<T> factory;
private final InjectionPoint constructorInjectionPoint;
- private ConstructorBindingImpl(InjectorImpl injector, Key<T> key, Object source,
- InternalFactory<? extends T> scopedFactory, Scoping scoping, Factory<T> factory,
+ private ConstructorBindingImpl(
+ InjectorImpl injector,
+ Key<T> key,
+ Object source,
+ InternalFactory<? extends T> scopedFactory,
+ Scoping scoping,
+ Factory<T> factory,
InjectionPoint constructorInjectionPoint) {
super(injector, key, source, scopedFactory, scoping);
this.factory = factory;
this.constructorInjectionPoint = constructorInjectionPoint;
}
- public ConstructorBindingImpl(Key<T> key, Object source, Scoping scoping,
- InjectionPoint constructorInjectionPoint, Set<InjectionPoint> injectionPoints) {
+ public ConstructorBindingImpl(
+ Key<T> key,
+ Object source,
+ Scoping scoping,
+ InjectionPoint constructorInjectionPoint,
+ Set<InjectionPoint> injectionPoints) {
super(source, key, scoping);
- this.factory = new Factory<T>(false, key);
- ConstructionProxy<T> constructionProxy
- = new DefaultConstructionProxyFactory<T>(constructorInjectionPoint).create();
+ this.factory = new Factory<>(false, key);
+ ConstructionProxy<T> constructionProxy =
+ new DefaultConstructionProxyFactory<T>(constructorInjectionPoint).create();
this.constructorInjectionPoint = constructorInjectionPoint;
- factory.constructorInjector = new ConstructorInjector<T>(
- injectionPoints, constructionProxy, null, null);
+ factory.constructorInjector =
+ new ConstructorInjector<T>(injectionPoints, constructionProxy, null, null);
}
/**
* @param constructorInjector the constructor to use, or {@code null} to use the default.
- * @param failIfNotLinked true if this ConstructorBindingImpl's InternalFactory should
- * only succeed if retrieved from a linked binding
+ * @param failIfNotLinked true if this ConstructorBindingImpl's InternalFactory should only
+ * succeed if retrieved from a linked binding
*/
- static <T> ConstructorBindingImpl<T> create(InjectorImpl injector, Key<T> key,
- InjectionPoint constructorInjector, Object source, Scoping scoping, Errors errors,
- boolean failIfNotLinked, boolean failIfNotExplicit)
+ static <T> ConstructorBindingImpl<T> create(
+ InjectorImpl injector,
+ Key<T> key,
+ InjectionPoint constructorInjector,
+ Object source,
+ Scoping scoping,
+ Errors errors,
+ boolean failIfNotLinked,
+ boolean failIfNotExplicit)
throws ErrorsException {
int numErrors = errors.size();
@SuppressWarnings("unchecked") // constructorBinding guarantees type is consistent
- Class<? super T> rawType = constructorInjector == null
- ? key.getTypeLiteral().getRawType()
- : (Class) constructorInjector.getDeclaringType().getRawType();
+ Class<? super T> rawType =
+ constructorInjector == null
+ ? key.getTypeLiteral().getRawType()
+ : (Class) constructorInjector.getDeclaringType().getRawType();
// We can't inject abstract classes.
if (Modifier.isAbstract(rawType.getModifiers())) {
- errors.missingImplementation(key);
+ errors.missingImplementationWithHint(key, injector);
}
// Error: Inner class.
@@ -110,16 +126,17 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T>
Class<?> annotatedType = constructorInjector.getMember().getDeclaringClass();
Class<? extends Annotation> scopeAnnotation = findScopeAnnotation(errors, annotatedType);
if (scopeAnnotation != null) {
- scoping = Scoping.makeInjectable(Scoping.forAnnotation(scopeAnnotation),
- injector, errors.withSource(rawType));
+ scoping =
+ Scoping.makeInjectable(
+ Scoping.forAnnotation(scopeAnnotation), injector, errors.withSource(rawType));
}
}
errors.throwIfNewErrors(numErrors);
- Factory<T> factoryFactory = new Factory<T>(failIfNotLinked, key);
- InternalFactory<? extends T> scopedFactory
- = Scoping.scope(key, injector, factoryFactory, source, scoping);
+ Factory<T> factoryFactory = new Factory<>(failIfNotLinked, key);
+ InternalFactory<? extends T> scopedFactory =
+ Scoping.scope(key, injector, factoryFactory, source, scoping);
return new ConstructorBindingImpl<T>(
injector, key, source, scopedFactory, scoping, factoryFactory, constructorInjector);
@@ -131,12 +148,12 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T>
|| cxtor.isAnnotationPresent(javax.inject.Inject.class);
}
+ @Override
@SuppressWarnings("unchecked") // the result type always agrees with the ConstructorInjector type
public void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
factory.constructorInjector =
(ConstructorInjector<T>) injector.constructors.get(constructorInjectionPoint, errors);
- factory.provisionCallback =
- injector.provisionListenerStore.get(this);
+ factory.provisionCallback = injector.provisionListenerStore.get(this);
}
/** True if this binding has been initialized and is ready for use. */
@@ -146,7 +163,7 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T>
/** Returns an injection point that can be used to clean up the constructor store. */
InjectionPoint getInternalConstructor() {
- if(factory.constructorInjector != null) {
+ if (factory.constructorInjector != null) {
return factory.constructorInjector.getConstructionProxy().getInjectionPoint();
} else {
return constructorInjectionPoint;
@@ -156,69 +173,87 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T>
/** Returns a set of dependencies that can be iterated over to clean up stray JIT bindings. */
Set<Dependency<?>> getInternalDependencies() {
ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder();
- if(factory.constructorInjector == null) {
+ if (factory.constructorInjector == null) {
builder.add(constructorInjectionPoint);
// If the below throws, it's OK -- we just ignore those dependencies, because no one
// could have used them anyway.
try {
- builder.addAll(InjectionPoint.forInstanceMethodsAndFields(constructorInjectionPoint.getDeclaringType()));
- } catch(ConfigurationException ignored) {}
+ builder.addAll(
+ InjectionPoint.forInstanceMethodsAndFields(
+ constructorInjectionPoint.getDeclaringType()));
+ } catch (ConfigurationException ignored) {
+ }
} else {
- builder.add(getConstructor())
- .addAll(getInjectableMembers());
+ builder.add(getConstructor()).addAll(getInjectableMembers());
}
return Dependency.forInjectionPoints(builder.build());
}
+ @Override
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
checkState(factory.constructorInjector != null, "not initialized");
return visitor.visit(this);
}
+ @Override
public InjectionPoint getConstructor() {
checkState(factory.constructorInjector != null, "Binding is not ready");
return factory.constructorInjector.getConstructionProxy().getInjectionPoint();
}
+ @Override
public Set<InjectionPoint> getInjectableMembers() {
checkState(factory.constructorInjector != null, "Binding is not ready");
return factory.constructorInjector.getInjectableMembers();
}
/*if[AOP]*/
+ @Override
public Map<Method, List<org.aopalliance.intercept.MethodInterceptor>> getMethodInterceptors() {
checkState(factory.constructorInjector != null, "Binding is not ready");
return factory.constructorInjector.getConstructionProxy().getMethodInterceptors();
}
/*end[AOP]*/
+ @Override
public Set<Dependency<?>> getDependencies() {
- return Dependency.forInjectionPoints(new ImmutableSet.Builder<InjectionPoint>()
- .add(getConstructor())
- .addAll(getInjectableMembers())
- .build());
+ return Dependency.forInjectionPoints(
+ new ImmutableSet.Builder<InjectionPoint>()
+ .add(getConstructor())
+ .addAll(getInjectableMembers())
+ .build());
}
- @Override protected BindingImpl<T> withScoping(Scoping scoping) {
+ @Override
+ protected BindingImpl<T> withScoping(Scoping scoping) {
return new ConstructorBindingImpl<T>(
null, getKey(), getSource(), factory, scoping, factory, constructorInjectionPoint);
}
- @Override protected BindingImpl<T> withKey(Key<T> key) {
+ @Override
+ protected BindingImpl<T> withKey(Key<T> key) {
return new ConstructorBindingImpl<T>(
null, key, getSource(), factory, getScoping(), factory, constructorInjectionPoint);
}
+ @Override
@SuppressWarnings("unchecked") // the raw constructor member and declaring type always agree
public void applyTo(Binder binder) {
InjectionPoint constructor = getConstructor();
- getScoping().applyTo(binder.withSource(getSource()).bind(getKey()).toConstructor(
- (Constructor) getConstructor().getMember(), (TypeLiteral) constructor.getDeclaringType()));
+ getScoping()
+ .applyTo(
+ binder
+ .withSource(getSource())
+ .bind(getKey())
+ .toConstructor(
+ (Constructor) getConstructor().getMember(),
+ (TypeLiteral) constructor.getDeclaringType()));
}
- @Override public String toString() {
- return Objects.toStringHelper(ConstructorBinding.class)
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(ConstructorBinding.class)
.add("key", getKey())
.add("source", getSource())
.add("scope", getScoping())
@@ -227,11 +262,11 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T>
@Override
public boolean equals(Object obj) {
- if(obj instanceof ConstructorBindingImpl) {
- ConstructorBindingImpl<?> o = (ConstructorBindingImpl<?>)obj;
+ if (obj instanceof ConstructorBindingImpl) {
+ ConstructorBindingImpl<?> o = (ConstructorBindingImpl<?>) obj;
return getKey().equals(o.getKey())
- && getScoping().equals(o.getScoping())
- && Objects.equal(constructorInjectionPoint, o.constructorInjectionPoint);
+ && getScoping().equals(o.getScoping())
+ && Objects.equal(constructorInjectionPoint, o.constructorInjectionPoint);
} else {
return false;
}
@@ -253,19 +288,22 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T>
this.key = key;
}
+ @Override
@SuppressWarnings("unchecked")
- public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
- throws ErrorsException {
- checkState(constructorInjector != null, "Constructor not ready");
+ public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+ throws InternalProvisionException {
+ ConstructorInjector<T> localInjector = constructorInjector;
+ if (localInjector == null) {
+ throw new IllegalStateException("Constructor not ready");
+ }
- if(failIfNotLinked && !linked) {
- throw errors.jitDisabled(key).toException();
+ if (!linked && failIfNotLinked) {
+ throw InternalProvisionException.jitDisabled(key);
}
// This may not actually be safe because it could return a super type of T (if that's all the
// client needs), but it should be OK in practice thanks to the wonders of erasure.
- return (T) constructorInjector.construct(errors, context,
- dependency.getKey().getTypeLiteral().getRawType(), provisionCallback);
+ return (T) localInjector.construct(context, dependency, provisionCallback);
}
}
}
diff --git a/core/src/com/google/inject/internal/ConstructorInjector.java b/core/src/com/google/inject/internal/ConstructorInjector.java
index 1ff4be1f..13e11478 100644
--- a/core/src/com/google/inject/internal/ConstructorInjector.java
+++ b/core/src/com/google/inject/internal/ConstructorInjector.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,8 +18,8 @@ package com.google.inject.internal;
import com.google.common.collect.ImmutableSet;
import com.google.inject.internal.ProvisionListenerStackCallback.ProvisionCallback;
+import com.google.inject.spi.Dependency;
import com.google.inject.spi.InjectionPoint;
-
import java.lang.reflect.InvocationTargetException;
import java.util.Set;
@@ -36,7 +36,8 @@ final class ConstructorInjector<T> {
private final ConstructionProxy<T> constructionProxy;
private final MembersInjectorImpl<T> membersInjector;
- ConstructorInjector(Set<InjectionPoint> injectableMembers,
+ ConstructorInjector(
+ Set<InjectionPoint> injectableMembers,
ConstructionProxy<T> constructionProxy,
SingleParameterInjector<?>[] parameterInjectors,
MembersInjectorImpl<T> membersInjector) {
@@ -55,40 +56,48 @@ final class ConstructorInjector<T> {
}
/**
- * Construct an instance. Returns {@code Object} instead of {@code T} because
- * it may return a proxy.
+ * Construct an instance. Returns {@code Object} instead of {@code T} because it may return a
+ * proxy.
*/
- Object construct(final Errors errors, final InternalContext context,
- Class<?> expectedType,
- ProvisionListenerStackCallback<T> provisionCallback)
- throws ErrorsException {
+ Object construct(
+ final InternalContext context,
+ Dependency<?> dependency,
+ /* @Nullable */ ProvisionListenerStackCallback<T> provisionCallback)
+ throws InternalProvisionException {
final ConstructionContext<T> constructionContext = context.getConstructionContext(this);
-
// We have a circular reference between constructors. Return a proxy.
if (constructionContext.isConstructing()) {
// TODO (crazybob): if we can't proxy this object, can we proxy the other object?
return constructionContext.createProxy(
- errors, context.getInjectorOptions(), expectedType);
+ context.getInjectorOptions(), dependency.getKey().getTypeLiteral().getRawType());
}
// If we're re-entering this factory while injecting fields or methods,
// return the same instance. This prevents infinite loops.
T t = constructionContext.getCurrentReference();
if (t != null) {
- return t;
+ if (context.getInjectorOptions().disableCircularProxies) {
+ throw InternalProvisionException.circularDependenciesDisabled(
+ dependency.getKey().getTypeLiteral().getRawType());
+ } else {
+ return t;
+ }
}
constructionContext.startConstruction();
try {
// Optimization: Don't go through the callback stack if we have no listeners.
- if (!provisionCallback.hasListeners()) {
- return provision(errors, context, constructionContext);
+ if (provisionCallback == null) {
+ return provision(context, constructionContext);
} else {
- return provisionCallback.provision(errors, context, new ProvisionCallback<T>() {
- public T call() throws ErrorsException {
- return provision(errors, context, constructionContext);
- }
- });
+ return provisionCallback.provision(
+ context,
+ new ProvisionCallback<T>() {
+ @Override
+ public T call() throws InternalProvisionException {
+ return provision(context, constructionContext);
+ }
+ });
}
} finally {
constructionContext.finishConstruction();
@@ -96,12 +105,12 @@ final class ConstructorInjector<T> {
}
/** Provisions a new T. */
- private T provision(Errors errors, InternalContext context,
- ConstructionContext<T> constructionContext) throws ErrorsException {
+ private T provision(InternalContext context, ConstructionContext<T> constructionContext)
+ throws InternalProvisionException {
try {
T t;
try {
- Object[] parameters = SingleParameterInjector.getAll(errors, context, parameterInjectors);
+ Object[] parameters = SingleParameterInjector.getAll(context, parameterInjectors);
t = constructionProxy.newInstance(parameters);
constructionContext.setProxyDelegates(t);
} finally {
@@ -111,16 +120,15 @@ final class ConstructorInjector<T> {
// Store reference. If an injector re-enters this factory, they'll get the same reference.
constructionContext.setCurrentReference(t);
- membersInjector.injectMembers(t, errors, context, false);
- membersInjector.notifyListeners(t, errors);
+ MembersInjectorImpl<T> localMembersInjector = membersInjector;
+ localMembersInjector.injectMembers(t, context, false);
+ localMembersInjector.notifyListeners(t);
return t;
} catch (InvocationTargetException userException) {
- Throwable cause = userException.getCause() != null
- ? userException.getCause()
- : userException;
- throw errors.withSource(constructionProxy.getInjectionPoint())
- .errorInjectingConstructor(cause).toException();
+ Throwable cause = userException.getCause() != null ? userException.getCause() : userException;
+ throw InternalProvisionException.errorInjectingConstructor(cause)
+ .addSource(constructionProxy.getInjectionPoint());
} finally {
constructionContext.removeCurrentReference();
}
diff --git a/core/src/com/google/inject/internal/ConstructorInjectorStore.java b/core/src/com/google/inject/internal/ConstructorInjectorStore.java
index b8e48670..eb17a540 100644
--- a/core/src/com/google/inject/internal/ConstructorInjectorStore.java
+++ b/core/src/com/google/inject/internal/ConstructorInjectorStore.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,35 +29,33 @@ import com.google.inject.spi.InjectionPoint;
final class ConstructorInjectorStore {
private final InjectorImpl injector;
- private final FailableCache<InjectionPoint, ConstructorInjector<?>> cache
- = new FailableCache<InjectionPoint, ConstructorInjector<?>> () {
- @Override
- protected ConstructorInjector<?> create(InjectionPoint constructorInjector, Errors errors)
- throws ErrorsException {
- return createConstructor(constructorInjector, errors);
- }
- };
+ private final FailableCache<InjectionPoint, ConstructorInjector<?>> cache =
+ new FailableCache<InjectionPoint, ConstructorInjector<?>>() {
+ @Override
+ protected ConstructorInjector<?> create(InjectionPoint constructorInjector, Errors errors)
+ throws ErrorsException {
+ return createConstructor(constructorInjector, errors);
+ }
+ };
ConstructorInjectorStore(InjectorImpl injector) {
this.injector = injector;
}
- /**
- * Returns a new complete constructor injector with injection listeners registered.
- */
+ /** Returns a new complete constructor injector with injection listeners registered. */
public ConstructorInjector<?> get(InjectionPoint constructorInjector, Errors errors)
throws ErrorsException {
return cache.get(constructorInjector, errors);
}
-
+
/**
* Purges an injection point from the cache. Use this only if the cache is not actually valid and
* needs to be purged. (See issue 319 and
* ImplicitBindingTest#testCircularJitBindingsLeaveNoResidue and
* #testInstancesRequestingProvidersForThemselvesWithChildInjectors for examples of when this is
* necessary.)
- *
- * Returns true if the injector for that point was stored in the cache, false otherwise.
+ *
+ * <p>Returns true if the injector for that point was stored in the cache, false otherwise.
*/
boolean remove(InjectionPoint ip) {
return cache.remove(ip);
@@ -67,27 +65,32 @@ final class ConstructorInjectorStore {
throws ErrorsException {
int numErrorsBefore = errors.size();
- SingleParameterInjector<?>[] constructorParameterInjectors
- = injector.getParametersInjectors(injectionPoint.getDependencies(), errors);
+ SingleParameterInjector<?>[] constructorParameterInjectors =
+ injector.getParametersInjectors(injectionPoint.getDependencies(), errors);
@SuppressWarnings("unchecked") // the injector type agrees with the injection point type
- MembersInjectorImpl<T> membersInjector = (MembersInjectorImpl<T>) injector.membersInjectorStore
- .get(injectionPoint.getDeclaringType(), errors);
+ MembersInjectorImpl<T> membersInjector =
+ (MembersInjectorImpl<T>)
+ injector.membersInjectorStore.get(injectionPoint.getDeclaringType(), errors);
/*if[AOP]*/
ImmutableList<MethodAspect> injectorAspects = injector.state.getMethodAspects();
- ImmutableList<MethodAspect> methodAspects = membersInjector.getAddedAspects().isEmpty()
- ? injectorAspects
- : ImmutableList.copyOf(concat(injectorAspects, membersInjector.getAddedAspects()));
- ConstructionProxyFactory<T> factory = new ProxyFactory<T>(injectionPoint, methodAspects);
+ ImmutableList<MethodAspect> methodAspects =
+ membersInjector.getAddedAspects().isEmpty()
+ ? injectorAspects
+ : ImmutableList.copyOf(concat(injectorAspects, membersInjector.getAddedAspects()));
+ ConstructionProxyFactory<T> factory = new ProxyFactory<>(injectionPoint, methodAspects);
/*end[AOP]*/
/*if[NO_AOP]
- ConstructionProxyFactory<T> factory = new DefaultConstructionProxyFactory<T>(injectionPoint);
+ ConstructionProxyFactory<T> factory = new DefaultConstructionProxyFactory<>(injectionPoint);
end[NO_AOP]*/
errors.throwIfNewErrors(numErrorsBefore);
- return new ConstructorInjector<T>(membersInjector.getInjectionPoints(), factory.create(),
- constructorParameterInjectors, membersInjector);
+ return new ConstructorInjector<T>(
+ membersInjector.getInjectionPoints(),
+ factory.create(),
+ constructorParameterInjectors,
+ membersInjector);
}
}
diff --git a/core/src/com/google/inject/internal/CreationListener.java b/core/src/com/google/inject/internal/CreationListener.java
index 1779204c..53a61ee5 100644
--- a/core/src/com/google/inject/internal/CreationListener.java
+++ b/core/src/com/google/inject/internal/CreationListener.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,4 +21,4 @@ interface CreationListener {
/** Notifies that creation should happen. */
void notify(Errors errors);
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/internal/CycleDetectingLock.java b/core/src/com/google/inject/internal/CycleDetectingLock.java
index 690b1510..7b387b01 100644
--- a/core/src/com/google/inject/internal/CycleDetectingLock.java
+++ b/core/src/com/google/inject/internal/CycleDetectingLock.java
@@ -2,7 +2,6 @@ package com.google.inject.internal;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
-import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.ListMultimap;
@@ -10,7 +9,6 @@ import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
-
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
@@ -21,166 +19,174 @@ import java.util.concurrent.locks.ReentrantLock;
/**
* Simplified version of {@link Lock} that is special due to how it handles deadlocks detection.
*
- * <p>Is an inherent part of {@link SingletonScope}, moved into a upper level class due
- * to its size and complexity.
- *
- * @param <ID> Lock identification provided by the client, is returned unmodified to the client
- * when lock cycle is detected to identify it. Only toString() needs to be implemented.
- * Lock references this object internally,
- * for the purposes of Garbage Collection you should not use heavy IDs.
- * Lock is referenced by a lock factory as long as it's owned by a thread.
+ * <p>Is an inherent part of {@link SingletonScope}, moved into a upper level class due to its size
+ * and complexity.
*
+ * @param <ID> Lock identification provided by the client, is returned unmodified to the client when
+ * lock cycle is detected to identify it. Only toString() needs to be implemented. Lock
+ * references this object internally, for the purposes of Garbage Collection you should not use
+ * heavy IDs. Lock is referenced by a lock factory as long as it's owned by a thread.
* @see SingletonScope
* @see com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory
- *
* @author timofeyb (Timothy Basanov)
*/
interface CycleDetectingLock<ID> {
/**
- * Takes a lock in a blocking fashion in case no potential deadlocks are detected.
- * If the lock was successfully owned, returns an empty map indicating no detected potential
- * deadlocks.
+ * Takes a lock in a blocking fashion in case no potential deadlocks are detected. If the lock was
+ * successfully owned, returns an empty map indicating no detected potential deadlocks.
*
- * Otherwise, a map indicating threads involved in a potential deadlock are returned.
- * Map is ordered by dependency cycle and lists locks for each thread that are part of
- * the loop in order. Returned map is created atomically.
+ * <p>Otherwise, a map indicating threads involved in a potential deadlock are returned. Map is
+ * ordered by dependency cycle and lists locks for each thread that are part of the loop in order,
+ * the last lock in the list is the one that the thread is currently waiting for. Returned map is
+ * created atomically.
*
- * In case no cycle is detected performance is O(threads creating singletons),
- * in case cycle is detected performance is O(singleton locks).
+ * <p>In case no cycle is detected performance is O(threads creating singletons), in case cycle is
+ * detected performance is O(singleton locks).
*/
- ListMultimap<Long, ID> lockOrDetectPotentialLocksCycle();
+ ListMultimap<Thread, ID> lockOrDetectPotentialLocksCycle();
- /**
- * Unlocks previously locked lock.
- */
+ /** Unlocks previously locked lock. */
void unlock();
/**
- * Wraps locks so they would never cause a deadlock. On each
- * {@link CycleDetectingLock#lockOrDetectPotentialLocksCycle} we check for dependency cycles
- * within locks created by the same factory. Either we detect a cycle and return it
- * or take it atomically.
+ * Wraps locks so they would never cause a deadlock. On each {@link
+ * CycleDetectingLock#lockOrDetectPotentialLocksCycle} we check for dependency cycles within locks
+ * created by the same factory. Either we detect a cycle and return it or take it atomically.
*
- * <p>Important to note that we do not prevent deadlocks in the client code. As an example:
- * Thread A takes lock L and creates singleton class CA depending on the singleton class CB.
- * Meanwhile thread B is creating class CB and is waiting on the lock L. Issue happens
- * due to client code creating interdependent classes and using locks, where
- * no guarantees on the creation order from Guice are provided.
+ * <p>Important to note that we do not prevent deadlocks in the client code. As an example: Thread
+ * A takes lock L and creates singleton class CA depending on the singleton class CB. Meanwhile
+ * thread B is creating class CB and is waiting on the lock L. Issue happens due to client code
+ * creating interdependent classes and using locks, where no guarantees on the creation order from
+ * Guice are provided.
*
* <p>Instances of these locks are not intended to be exposed outside of {@link SingletonScope}.
*/
class CycleDetectingLockFactory<ID> {
/**
- * Specifies lock that thread is currently waiting on to own it.
- * Used only for purposes of locks cycle detection.
+ * Specifies lock that thread is currently waiting on to own it. Used only for purposes of locks
+ * cycle detection.
*
- * Key: thread id
- * Value: lock that is being waited on
+ * <ul>
+ * <li>Key: thread
+ * <li> Value: lock that is being waited on
+ * </ul>
*
- * Element is added inside {@link #lockOrDetectPotentialLocksCycle()} before {@link Lock#lock}
- * is called. Element is removed inside {@link #lockOrDetectPotentialLocksCycle()} after
- * {@link Lock#lock} and synchronously with adding it to {@link #locksOwnedByThread}.
+ * <p>Element is added inside {@link #lockOrDetectPotentialLocksCycle()} before {@link
+ * Lock#lock} is called. Element is removed inside {@link #lockOrDetectPotentialLocksCycle()}
+ * after {@link Lock#lock} and synchronously with adding it to {@link #locksOwnedByThread}.
*
- * Same lock can be added for several threads in case all of them are trying to
- * take it.
+ * <p>Same lock can be added for several threads in case all of them are trying to take it.
*
- * Guarded by {@code this}.
+ * <p>Guarded by {@code CycleDetectingLockFactory.class}.
*/
- private Map<Long, ReentrantCycleDetectingLock> lockThreadIsWaitingOn = Maps.newHashMap();
+ private static Map<Thread, ReentrantCycleDetectingLock<?>> lockThreadIsWaitingOn =
+ Maps.newHashMap();
/**
- * Lists locks that thread owns.
- * Used only to populate locks in a potential cycle when it is detected.
+ * Lists locks that thread owns. Used only to populate locks in a potential cycle when it is
+ * detected.
*
- * Key: thread id
- * Value: stack of locks that were owned.
+ * <ul>
+ * <li>Key: thread
+ * <li>Value: stack of locks that were owned.
+ * </ul>
*
- * Element is added inside {@link #lockOrDetectPotentialLocksCycle()} after {@link Lock#lock}
- * is called. Element is removed inside {@link #unlock()} synchronously with
- * {@link Lock#unlock()} call.
+ * <p>Element is added inside {@link #lockOrDetectPotentialLocksCycle()} after {@link Lock#lock}
+ * is called. Element is removed inside {@link #unlock()} synchronously with {@link
+ * Lock#unlock()} call.
*
- * Same lock can only be present several times for the same thread as locks are
- * reentrant. Lock can not be owned by several different threads as the same time.
+ * <p>Same lock can only be present several times for the same thread as locks are reentrant.
+ * Lock can not be owned by several different threads as the same time.
*
- * Guarded by {@code this}.
+ * <p>Guarded by {@code CycleDetectingLockFactory.class}.
*/
- private final Multimap<Long, ReentrantCycleDetectingLock> locksOwnedByThread =
+ private static final Multimap<Thread, ReentrantCycleDetectingLock<?>> locksOwnedByThread =
LinkedHashMultimap.create();
/**
- * Creates new lock within this factory context. We can guarantee that locks created by
- * the same factory would not deadlock.
+ * Creates new lock within this factory context. We can guarantee that locks created by the same
+ * factory would not deadlock.
*
- * @param newLockId lock id that would be used to report lock cycles if detected
+ * @param userLockId lock id that would be used to report lock cycles if detected
*/
- CycleDetectingLock<ID> create(ID newLockId) {
- return new ReentrantCycleDetectingLock(newLockId, new ReentrantLock());
+ CycleDetectingLock<ID> create(ID userLockId) {
+ return new ReentrantCycleDetectingLock<ID>(this, userLockId, new ReentrantLock());
}
/** The implementation for {@link CycleDetectingLock}. */
- class ReentrantCycleDetectingLock implements CycleDetectingLock<ID> {
+ static class ReentrantCycleDetectingLock<ID> implements CycleDetectingLock<ID> {
/** Underlying lock used for actual waiting when no potential deadlocks are detected. */
private final Lock lockImplementation;
/** User id for this lock. */
private final ID userLockId;
+ /** Factory that was used to create this lock. */
+ private final CycleDetectingLockFactory<ID> lockFactory;
/**
- * Thread id for the thread that owned this lock. Nullable.
- * Guarded by {@code CycleDetectingLockFactory.this}.
+ * Thread that owns this lock. Nullable. Guarded by {@code CycleDetectingLockFactory.this}.
*/
- private Long lockOwnerThreadId = null;
+ private Thread lockOwnerThread = null;
+
/**
- * Number of times that thread owned this lock.
- * Guarded by {@code CycleDetectingLockFactory.this}.
+ * Number of times that thread owned this lock. Guarded by {@code
+ * CycleDetectingLockFactory.this}.
*/
private int lockReentranceCount = 0;
- ReentrantCycleDetectingLock(ID userLockId, Lock lockImplementation) {
+ ReentrantCycleDetectingLock(
+ CycleDetectingLockFactory<ID> lockFactory, ID userLockId, Lock lockImplementation) {
+ this.lockFactory = lockFactory;
this.userLockId = Preconditions.checkNotNull(userLockId, "userLockId");
- this.lockImplementation = Preconditions.checkNotNull(
- lockImplementation, "lockImplementation");
+ this.lockImplementation =
+ Preconditions.checkNotNull(lockImplementation, "lockImplementation");
}
- @Override public ListMultimap<Long, ID> lockOrDetectPotentialLocksCycle() {
- final long currentThreadId = Thread.currentThread().getId();
- synchronized (CycleDetectingLockFactory.this) {
+ @Override
+ public ListMultimap<Thread, ID> lockOrDetectPotentialLocksCycle() {
+ final Thread currentThread = Thread.currentThread();
+ synchronized (CycleDetectingLockFactory.class) {
checkState();
- ListMultimap<Long, ID> locksInCycle = detectPotentialLocksCycle();
+ // Add this lock to the waiting map to ensure it is included in any reported lock cycle.
+ lockThreadIsWaitingOn.put(currentThread, this);
+ ListMultimap<Thread, ID> locksInCycle = detectPotentialLocksCycle();
if (!locksInCycle.isEmpty()) {
+ // We aren't actually going to wait for this lock, so remove it from the map.
+ lockThreadIsWaitingOn.remove(currentThread);
// potential deadlock is found, we don't try to take this lock
return locksInCycle;
}
- lockThreadIsWaitingOn.put(currentThreadId, this);
}
// this may be blocking, but we don't expect it to cause a deadlock
lockImplementation.lock();
- synchronized (CycleDetectingLockFactory.this) {
+ synchronized (CycleDetectingLockFactory.class) {
// current thread is no longer waiting on this lock
- lockThreadIsWaitingOn.remove(currentThreadId);
+ lockThreadIsWaitingOn.remove(currentThread);
checkState();
// mark it as owned by us
- lockOwnerThreadId = currentThreadId;
+ lockOwnerThread = currentThread;
lockReentranceCount++;
// add this lock to the list of locks owned by a current thread
- locksOwnedByThread.put(currentThreadId, this);
+ locksOwnedByThread.put(currentThread, this);
}
// no deadlock is found, locking successful
return ImmutableListMultimap.of();
}
- @Override public void unlock() {
- final long currentThreadId = Thread.currentThread().getId();
- synchronized (CycleDetectingLockFactory.this) {
+ @Override
+ public void unlock() {
+ final Thread currentThread = Thread.currentThread();
+ synchronized (CycleDetectingLockFactory.class) {
checkState();
- Preconditions.checkState(lockOwnerThreadId != null,
- "Thread is trying to unlock a lock that is not locked");
- Preconditions.checkState(lockOwnerThreadId == currentThreadId,
+ Preconditions.checkState(
+ lockOwnerThread != null, "Thread is trying to unlock a lock that is not locked");
+ Preconditions.checkState(
+ lockOwnerThread == currentThread,
"Thread is trying to unlock a lock owned by another thread");
// releasing underlying lock
@@ -190,12 +196,13 @@ interface CycleDetectingLock<ID> {
lockReentranceCount--;
if (lockReentranceCount == 0) {
// we no longer own this lock
- lockOwnerThreadId = null;
- Preconditions.checkState(locksOwnedByThread.remove(currentThreadId, this),
+ lockOwnerThread = null;
+ Preconditions.checkState(
+ locksOwnedByThread.remove(currentThread, this),
"Internal error: Can not find this lock in locks owned by a current thread");
- if (locksOwnedByThread.get(currentThreadId).isEmpty()) {
+ if (locksOwnedByThread.get(currentThread).isEmpty()) {
// clearing memory
- locksOwnedByThread.removeAll(currentThreadId);
+ locksOwnedByThread.removeAll(currentThread);
}
}
}
@@ -203,21 +210,26 @@ interface CycleDetectingLock<ID> {
/** Check consistency of an internal state. */
void checkState() throws IllegalStateException {
- final long currentThreadId = Thread.currentThread().getId();
- Preconditions.checkState(!lockThreadIsWaitingOn.containsKey(currentThreadId),
+ final Thread currentThread = Thread.currentThread();
+ Preconditions.checkState(
+ !lockThreadIsWaitingOn.containsKey(currentThread),
"Internal error: Thread should not be in a waiting thread on a lock now");
- if (lockOwnerThreadId != null) {
+ if (lockOwnerThread != null) {
// check state of a locked lock
- Preconditions.checkState(lockReentranceCount >= 0,
+ Preconditions.checkState(
+ lockReentranceCount >= 0,
"Internal error: Lock ownership and reentrance count internal states do not match");
- Preconditions.checkState(locksOwnedByThread.get(lockOwnerThreadId).contains(this),
+ Preconditions.checkState(
+ locksOwnedByThread.get(lockOwnerThread).contains(this),
"Internal error: Set of locks owned by a current thread and lock "
+ "ownership status do not match");
} else {
// check state of a non locked lock
- Preconditions.checkState(lockReentranceCount == 0,
+ Preconditions.checkState(
+ lockReentranceCount == 0,
"Internal error: Reentrance count of a non locked lock is expect to be zero");
- Preconditions.checkState(!locksOwnedByThread.values().contains(this),
+ Preconditions.checkState(
+ !locksOwnedByThread.values().contains(this),
"Internal error: Non locked lock should not be owned by any thread");
}
}
@@ -225,76 +237,93 @@ interface CycleDetectingLock<ID> {
/**
* Algorithm to detect a potential lock cycle.
*
- * For lock's thread owner check which lock is it trying to take.
- * Repeat recursively. When current thread is found a potential cycle is detected.
+ * <p>For lock's thread owner check which lock is it trying to take. Repeat recursively. When
+ * current thread is found a potential cycle is detected.
*
* @see CycleDetectingLock#lockOrDetectPotentialLocksCycle()
*/
- private ListMultimap<Long, ID> detectPotentialLocksCycle() {
- final long currentThreadId = Thread.currentThread().getId();
- if (lockOwnerThreadId == null || lockOwnerThreadId == currentThreadId) {
+ private ListMultimap<Thread, ID> detectPotentialLocksCycle() {
+ final Thread currentThread = Thread.currentThread();
+ if (lockOwnerThread == null || lockOwnerThread == currentThread) {
// if nobody owns this lock, lock cycle is impossible
// if a current thread owns this lock, we let Guice to handle it
return ImmutableListMultimap.of();
}
- ListMultimap<Long, ID> potentialLocksCycle = Multimaps.newListMultimap(
- new LinkedHashMap<Long, Collection<ID>>(),
- new Supplier<List<ID>>() {
- @Override
- public List<ID> get() {
- return Lists.newArrayList();
- }
- });
+ ListMultimap<Thread, ID> potentialLocksCycle =
+ Multimaps.newListMultimap(
+ new LinkedHashMap<Thread, Collection<ID>>(),
+ new Supplier<List<ID>>() {
+ @Override
+ public List<ID> get() {
+ return Lists.newArrayList();
+ }
+ });
// lock that is a part of a potential locks cycle, starts with current lock
- ReentrantCycleDetectingLock lockOwnerWaitingOn = this;
+ ReentrantCycleDetectingLock<?> lockOwnerWaitingOn = this;
// try to find a dependency path between lock's owner thread and a current thread
- while (lockOwnerWaitingOn != null && lockOwnerWaitingOn.lockOwnerThreadId != null) {
- Long threadOwnerThreadWaits = lockOwnerWaitingOn.lockOwnerThreadId;
+ while (lockOwnerWaitingOn != null && lockOwnerWaitingOn.lockOwnerThread != null) {
+ Thread threadOwnerThreadWaits = lockOwnerWaitingOn.lockOwnerThread;
// in case locks cycle exists lock we're waiting for is part of it
- potentialLocksCycle.putAll(threadOwnerThreadWaits,
- getAllLockIdsAfter(threadOwnerThreadWaits, lockOwnerWaitingOn));
-
- if (threadOwnerThreadWaits == currentThreadId) {
+ lockOwnerWaitingOn =
+ addAllLockIdsAfter(threadOwnerThreadWaits, lockOwnerWaitingOn, potentialLocksCycle);
+ if (threadOwnerThreadWaits == currentThread) {
// owner thread depends on current thread, cycle detected
return potentialLocksCycle;
}
- // going for the next thread we wait on indirectly
- lockOwnerWaitingOn = lockThreadIsWaitingOn.get(threadOwnerThreadWaits);
}
// no dependency path from an owner thread to a current thread
return ImmutableListMultimap.of();
}
- /** Return locks owned by a thread after a lock specified, inclusive. */
- private List<ID> getAllLockIdsAfter(long threadId, ReentrantCycleDetectingLock lock) {
- List<ID> ids = Lists.newArrayList();
+ /**
+ * Adds all locks held by the given thread that are after the given lock and then returns the
+ * lock the thread is currently waiting on, if any
+ */
+ private ReentrantCycleDetectingLock<?> addAllLockIdsAfter(
+ Thread thread,
+ ReentrantCycleDetectingLock<?> lock,
+ ListMultimap<Thread, ID> potentialLocksCycle) {
boolean found = false;
- Collection<ReentrantCycleDetectingLock> ownedLocks = locksOwnedByThread.get(threadId);
- Preconditions.checkNotNull(ownedLocks,
- "Internal error: No locks were found taken by a thread");
- for (ReentrantCycleDetectingLock ownedLock : ownedLocks) {
+ Collection<ReentrantCycleDetectingLock<?>> ownedLocks = locksOwnedByThread.get(thread);
+ Preconditions.checkNotNull(
+ ownedLocks, "Internal error: No locks were found taken by a thread");
+ for (ReentrantCycleDetectingLock<?> ownedLock : ownedLocks) {
if (ownedLock == lock) {
found = true;
}
- if (found) {
- ids.add(ownedLock.userLockId);
+ if (found && ownedLock.lockFactory == this.lockFactory) {
+ // All locks are stored in a shared map therefore there is no way to
+ // enforce type safety. We know that our cast is valid as we check for a lock's
+ // factory. If the lock was generated by the
+ // same factory it has to have same type as the current lock.
+ @SuppressWarnings("unchecked")
+ ID userLockId = (ID) ownedLock.userLockId;
+ potentialLocksCycle.put(thread, userLockId);
}
}
- Preconditions.checkState(found, "Internal error: We can not find locks that "
- + "created a cycle that we detected");
- return ids;
+ Preconditions.checkState(
+ found,
+ "Internal error: We can not find locks that created a cycle that we detected");
+ ReentrantCycleDetectingLock<?> unownedLock = lockThreadIsWaitingOn.get(thread);
+ // If this thread is waiting for a lock add it to the cycle and return it
+ if (unownedLock != null && unownedLock.lockFactory == this.lockFactory) {
+ @SuppressWarnings("unchecked")
+ ID typed = (ID) unownedLock.userLockId;
+ potentialLocksCycle.put(thread, typed);
+ }
+ return unownedLock;
}
- @Override public String toString() {
+ @Override
+ public String toString() {
// copy is made to prevent a data race
// no synchronization is used, potentially stale data, should be good enough
- Long localLockOwnerThreadId = this.lockOwnerThreadId;
- if (localLockOwnerThreadId != null) {
- return String.format("CycleDetectingLock[%s][locked by %s]",
- userLockId, localLockOwnerThreadId);
+ Thread thread = this.lockOwnerThread;
+ if (thread != null) {
+ return String.format("%s[%s][locked by %s]", super.toString(), userLockId, thread);
} else {
- return String.format("CycleDetectingLock[%s][unlocked]", userLockId);
+ return String.format("%s[%s][unlocked]", super.toString(), userLockId);
}
}
}
diff --git a/core/src/com/google/inject/internal/DefaultConstructionProxyFactory.java b/core/src/com/google/inject/internal/DefaultConstructionProxyFactory.java
index 947b49a2..d8cfc182 100644
--- a/core/src/com/google/inject/internal/DefaultConstructionProxyFactory.java
+++ b/core/src/com/google/inject/internal/DefaultConstructionProxyFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,10 +16,9 @@
package com.google.inject.internal;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
-import com.google.inject.internal.BytecodeGen.Visibility;
import com.google.inject.spi.InjectionPoint;
-
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -35,73 +34,119 @@ final class DefaultConstructionProxyFactory<T> implements ConstructionProxyFacto
private final InjectionPoint injectionPoint;
- /**
- * @param injectionPoint an injection point whose member is a constructor of {@code T}.
- */
+ /** @param injectionPoint an injection point whose member is a constructor of {@code T}. */
DefaultConstructionProxyFactory(InjectionPoint injectionPoint) {
this.injectionPoint = injectionPoint;
}
+ @Override
public ConstructionProxy<T> create() {
@SuppressWarnings("unchecked") // the injection point is for a constructor of T
final Constructor<T> constructor = (Constructor<T>) injectionPoint.getMember();
- // Use FastConstructor if the constructor is public.
- if (Modifier.isPublic(constructor.getModifiers())) {
- Class<T> classToConstruct = constructor.getDeclaringClass();
- /*if[AOP]*/
- try {
- final net.sf.cglib.reflect.FastConstructor fastConstructor
- = BytecodeGen.newFastClass(classToConstruct, Visibility.forMember(constructor))
- .getConstructor(constructor);
-
- return new ConstructionProxy<T>() {
- @SuppressWarnings("unchecked")
- public T newInstance(Object... arguments) throws InvocationTargetException {
- return (T) fastConstructor.newInstance(arguments);
- }
- public InjectionPoint getInjectionPoint() {
- return injectionPoint;
- }
- public Constructor<T> getConstructor() {
- return constructor;
- }
- public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>>
- getMethodInterceptors() {
- return ImmutableMap.of();
- }
- };
- } catch (net.sf.cglib.core.CodeGenerationException e) {/* fall-through */}
- /*end[AOP]*/
- if (!Modifier.isPublic(classToConstruct.getModifiers())) {
- constructor.setAccessible(true);
+ /*if[AOP]*/
+ try {
+ net.sf.cglib.reflect.FastClass fc = BytecodeGen.newFastClassForMember(constructor);
+ if (fc != null) {
+ int index = fc.getIndex(constructor.getParameterTypes());
+ // We could just fall back to reflection in this case but I believe this should actually
+ // be impossible.
+ Preconditions.checkArgument(
+ index >= 0, "Could not find constructor %s in fast class", constructor);
+ return new FastClassProxy<T>(injectionPoint, constructor, fc, index);
}
- } else {
- constructor.setAccessible(true);
+ } catch (net.sf.cglib.core.CodeGenerationException e) {
+ /* fall-through */
}
+ /*end[AOP]*/
- return new ConstructionProxy<T>() {
- public T newInstance(Object... arguments) throws InvocationTargetException {
- try {
- return constructor.newInstance(arguments);
- } catch (InstantiationException e) {
- throw new AssertionError(e); // shouldn't happen, we know this is a concrete type
- } catch (IllegalAccessException e) {
- throw new AssertionError(e); // a security manager is blocking us, we're hosed
- }
- }
- public InjectionPoint getInjectionPoint() {
- return injectionPoint;
- }
- public Constructor<T> getConstructor() {
- return constructor;
+ return new ReflectiveProxy<T>(injectionPoint, constructor);
+ }
+
+ /*if[AOP]*/
+ /** A {@link ConstructionProxy} that uses FastClass to invoke the constructor. */
+ private static final class FastClassProxy<T> implements ConstructionProxy<T> {
+ final InjectionPoint injectionPoint;
+ final Constructor<T> constructor;
+ final net.sf.cglib.reflect.FastClass fc;
+ final int index;
+
+ private FastClassProxy(
+ InjectionPoint injectionPoint,
+ Constructor<T> constructor,
+ net.sf.cglib.reflect.FastClass fc,
+ int index) {
+ this.injectionPoint = injectionPoint;
+ this.constructor = constructor;
+ this.fc = fc;
+ this.index = index;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public T newInstance(Object... arguments) throws InvocationTargetException {
+ // Use this method instead of FastConstructor to save a stack frame
+ return (T) fc.newInstance(index, arguments);
+ }
+
+ @Override
+ public InjectionPoint getInjectionPoint() {
+ return injectionPoint;
+ }
+
+ @Override
+ public Constructor<T> getConstructor() {
+ return constructor;
+ }
+
+ @Override
+ public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>>
+ getMethodInterceptors() {
+ return ImmutableMap.of();
+ }
+ }
+ /*end[AOP]*/
+
+ private static final class ReflectiveProxy<T> implements ConstructionProxy<T> {
+ final Constructor<T> constructor;
+ final InjectionPoint injectionPoint;
+
+ ReflectiveProxy(InjectionPoint injectionPoint, Constructor<T> constructor) {
+ if (!Modifier.isPublic(constructor.getDeclaringClass().getModifiers())
+ || !Modifier.isPublic(constructor.getModifiers())) {
+ constructor.setAccessible(true);
}
- /*if[AOP]*/
- public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>>
- getMethodInterceptors() {
- return ImmutableMap.of();
+ this.injectionPoint = injectionPoint;
+ this.constructor = constructor;
+ }
+
+ @Override
+ public T newInstance(Object... arguments) throws InvocationTargetException {
+ try {
+ return constructor.newInstance(arguments);
+ } catch (InstantiationException e) {
+ throw new AssertionError(e); // shouldn't happen, we know this is a concrete type
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e); // a security manager is blocking us, we're hosed
}
- /*end[AOP]*/
- };
+ }
+
+ @Override
+ public InjectionPoint getInjectionPoint() {
+ return injectionPoint;
+ }
+
+ @Override
+ public Constructor<T> getConstructor() {
+ return constructor;
+ }
+
+ /*if[AOP]*/
+ @Override
+ public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>>
+ getMethodInterceptors() {
+ return ImmutableMap.of();
+ }
+ /*end[AOP]*/
}
}
diff --git a/core/src/com/google/inject/internal/DeferredLookups.java b/core/src/com/google/inject/internal/DeferredLookups.java
index 049c9a8d..2c374060 100644
--- a/core/src/com/google/inject/internal/DeferredLookups.java
+++ b/core/src/com/google/inject/internal/DeferredLookups.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,7 +24,6 @@ import com.google.inject.TypeLiteral;
import com.google.inject.spi.Element;
import com.google.inject.spi.MembersInjectorLookup;
import com.google.inject.spi.ProviderLookup;
-
import java.util.List;
/**
@@ -41,22 +40,22 @@ final class DeferredLookups implements Lookups {
this.injector = injector;
}
- /**
- * Initialize the specified lookups, either immediately or when the injector is created.
- */
+ /** Initialize the specified lookups, either immediately or when the injector is created. */
void initialize(Errors errors) {
injector.lookups = injector;
new LookupProcessor(errors).process(injector, lookups);
}
+ @Override
public <T> Provider<T> getProvider(Key<T> key) {
- ProviderLookup<T> lookup = new ProviderLookup<T>(key, key);
+ ProviderLookup<T> lookup = new ProviderLookup<>(key, key);
lookups.add(lookup);
return lookup.getProvider();
}
+ @Override
public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) {
- MembersInjectorLookup<T> lookup = new MembersInjectorLookup<T>(type, type);
+ MembersInjectorLookup<T> lookup = new MembersInjectorLookup<>(type, type);
lookups.add(lookup);
return lookup.getMembersInjector();
}
diff --git a/core/src/com/google/inject/internal/DelayedInitialize.java b/core/src/com/google/inject/internal/DelayedInitialize.java
index 82a84634..5534f508 100644
--- a/core/src/com/google/inject/internal/DelayedInitialize.java
+++ b/core/src/com/google/inject/internal/DelayedInitialize.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,13 @@
package com.google.inject.internal;
/**
- * Something that needs some delayed initialization, typically
- * a binding or internal factory that needs to be created & put
- * into the bindings map & then initialized later.
- *
+ * Something that needs some delayed initialization, typically a binding or internal factory that
+ * needs to be created & put into the bindings map & then initialized later.
+ *
* @author sameb@google.com (Sam Berlin)
*/
interface DelayedInitialize {
-
+
/** Initializes this binding, throwing any errors if necessary. */
void initialize(InjectorImpl injector, Errors errors) throws ErrorsException;
-
}
diff --git a/core/src/com/google/inject/internal/DelegatingInvocationHandler.java b/core/src/com/google/inject/internal/DelegatingInvocationHandler.java
index 32441ff6..f78262f6 100644
--- a/core/src/com/google/inject/internal/DelegatingInvocationHandler.java
+++ b/core/src/com/google/inject/internal/DelegatingInvocationHandler.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,9 +16,7 @@
package com.google.inject.internal;
-
import com.google.common.base.Preconditions;
-
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -29,16 +27,18 @@ class DelegatingInvocationHandler<T> implements InvocationHandler {
private T delegate;
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
// checking volatile field for synchronization
- Preconditions.checkState(initialized,
+ Preconditions.checkState(
+ initialized,
"This is a proxy used to support"
+ " circular references. The object we're"
+ " proxying is not constructed yet. Please wait until after"
+ " injection has completed to use this object.");
- Preconditions.checkNotNull(delegate,
+ Preconditions.checkNotNull(
+ delegate,
"This is a proxy used to support"
+ " circular references. The object we're "
+ " proxying is initialized to null."
diff --git a/core/src/com/google/inject/internal/Element.java b/core/src/com/google/inject/internal/Element.java
new file mode 100644
index 00000000..5b738ef1
--- /dev/null
+++ b/core/src/com/google/inject/internal/Element.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 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.internal;
+
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.inject.BindingAnnotation;
+import java.lang.annotation.Retention;
+
+/**
+ * An internal binding annotation applied to each element in a multibinding. All elements are
+ * assigned a globally-unique id to allow different modules to contribute multibindings
+ * independently.
+ *
+ * @author jessewilson@google.com (Jesse Wilson)
+ */
+@Retention(RUNTIME)
+@BindingAnnotation
+@interface Element {
+
+ enum Type {
+ MAPBINDER,
+ MULTIBINDER;
+ }
+
+ String setName();
+
+ int uniqueId();
+
+ Type type();
+
+ String keyType();
+}
diff --git a/core/src/com/google/inject/internal/EncounterImpl.java b/core/src/com/google/inject/internal/EncounterImpl.java
index 8aa3e948..4fb8575e 100644
--- a/core/src/com/google/inject/internal/EncounterImpl.java
+++ b/core/src/com/google/inject/internal/EncounterImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,13 +30,10 @@ import com.google.inject.matcher.Matchers;
import com.google.inject.spi.InjectionListener;
import com.google.inject.spi.Message;
import com.google.inject.spi.TypeEncounter;
-
import java.lang.reflect.Method;
import java.util.List;
-/**
- * @author jessewilson@google.com (Jesse Wilson)
- */
+/** @author jessewilson@google.com (Jesse Wilson) */
final class EncounterImpl<T> implements TypeEncounter<T> {
private final Errors errors;
@@ -59,12 +56,12 @@ final class EncounterImpl<T> implements TypeEncounter<T> {
/*if[AOP]*/
ImmutableList<MethodAspect> getAspects() {
- return aspects == null
- ? ImmutableList.<MethodAspect>of()
- : ImmutableList.copyOf(aspects);
+ return aspects == null ? ImmutableList.<MethodAspect>of() : ImmutableList.copyOf(aspects);
}
- public void bindInterceptor(Matcher<? super Method> methodMatcher,
+ @Override
+ public void bindInterceptor(
+ Matcher<? super Method> methodMatcher,
org.aopalliance.intercept.MethodInterceptor... interceptors) {
checkState(valid, "Encounters may not be used after hear() returns.");
@@ -89,6 +86,7 @@ final class EncounterImpl<T> implements TypeEncounter<T> {
: ImmutableSet.copyOf(injectionListeners);
}
+ @Override
public void register(MembersInjector<? super T> membersInjector) {
checkState(valid, "Encounters may not be used after hear() returns.");
@@ -99,6 +97,7 @@ final class EncounterImpl<T> implements TypeEncounter<T> {
membersInjectors.add(membersInjector);
}
+ @Override
public void register(InjectionListener<? super T> injectionListener) {
checkState(valid, "Encounters may not be used after hear() returns.");
@@ -109,36 +108,43 @@ final class EncounterImpl<T> implements TypeEncounter<T> {
injectionListeners.add(injectionListener);
}
+ @Override
public void addError(String message, Object... arguments) {
checkState(valid, "Encounters may not be used after hear() returns.");
errors.addMessage(message, arguments);
}
+ @Override
public void addError(Throwable t) {
checkState(valid, "Encounters may not be used after hear() returns.");
errors.errorInUserCode(t, "An exception was caught and reported. Message: %s", t.getMessage());
}
+ @Override
public void addError(Message message) {
checkState(valid, "Encounters may not be used after hear() returns.");
errors.addMessage(message);
}
+ @Override
public <T> Provider<T> getProvider(Key<T> key) {
checkState(valid, "Encounters may not be used after hear() returns.");
return lookups.getProvider(key);
}
+ @Override
public <T> Provider<T> getProvider(Class<T> type) {
return getProvider(Key.get(type));
}
+ @Override
public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
checkState(valid, "Encounters may not be used after hear() returns.");
return lookups.getMembersInjector(typeLiteral);
}
+ @Override
public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
return getMembersInjector(TypeLiteral.get(type));
}
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/internal/ErrorHandler.java b/core/src/com/google/inject/internal/ErrorHandler.java
index b448eb7c..c0ffd014 100644
--- a/core/src/com/google/inject/internal/ErrorHandler.java
+++ b/core/src/com/google/inject/internal/ErrorHandler.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,13 +25,9 @@ import com.google.inject.spi.Message;
*/
interface ErrorHandler {
- /**
- * Handles an error.
- */
+ /** Handles an error. */
void handle(Object source, Errors errors);
- /**
- * Handles a user-reported error.
- */
+ /** Handles a user-reported error. */
void handle(Message message);
}
diff --git a/core/src/com/google/inject/internal/Errors.java b/core/src/com/google/inject/internal/Errors.java
index 7527e2a1..7269f120 100644
--- a/core/src/com/google/inject/internal/Errors.java
+++ b/core/src/com/google/inject/internal/Errors.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,45 +20,34 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
-import com.google.common.collect.Sets;
+import com.google.common.primitives.Primitives;
+import com.google.inject.Binding;
import com.google.inject.ConfigurationException;
import com.google.inject.CreationException;
-import com.google.inject.Guice;
+import com.google.inject.Injector;
import com.google.inject.Key;
-import com.google.inject.MembersInjector;
-import com.google.inject.Provider;
-import com.google.inject.Provides;
import com.google.inject.ProvisionException;
import com.google.inject.Scope;
import com.google.inject.TypeLiteral;
-import com.google.inject.internal.util.Classes;
import com.google.inject.internal.util.SourceProvider;
-import com.google.inject.internal.util.StackTraceElements;
-import com.google.inject.spi.Dependency;
import com.google.inject.spi.ElementSource;
-import com.google.inject.spi.InjectionListener;
-import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.Message;
import com.google.inject.spi.ScopeBinding;
import com.google.inject.spi.TypeConverterBinding;
import com.google.inject.spi.TypeListenerBinding;
-
-import java.io.PrintWriter;
import java.io.Serializable;
-import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Formatter;
import java.util.List;
+import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.logging.Level;
-import java.util.logging.Logger;
/**
* A collection of error messages. If this type is passed as a method parameter, the method is
@@ -77,30 +66,58 @@ import java.util.logging.Logger;
*/
public final class Errors implements Serializable {
- private static final Logger logger = Logger.getLogger(Guice.class.getName());
-
- private static final Set<Dependency<?>> warnedDependencies =
- Sets.newSetFromMap(new ConcurrentHashMap<Dependency<?>, Boolean>());
+ /** When a binding is not found, show at most this many bindings with the same type */
+ private static final int MAX_MATCHING_TYPES_REPORTED = 3;
+ /** When a binding is not found, show at most this many bindings that have some similarities */
+ private static final int MAX_RELATED_TYPES_REPORTED = 3;
/**
- * The root errors object. Used to access the list of error messages.
+ * Throws a ConfigurationException with an NullPointerExceptions as the cause if the given
+ * reference is {@code null}.
*/
- private final Errors root;
+ static <T> T checkNotNull(T reference, String name) {
+ if (reference != null) {
+ return reference;
+ }
+
+ NullPointerException npe = new NullPointerException(name);
+ throw new ConfigurationException(ImmutableSet.of(new Message(npe.toString(), npe)));
+ }
/**
- * The parent errors object. Used to obtain the chain of source objects.
+ * Throws a ConfigurationException with a formatted {@link Message} if this condition is {@code
+ * false}.
*/
- private final Errors parent;
+ static void checkConfiguration(boolean condition, String format, Object... args) {
+ if (condition) {
+ return;
+ }
+
+ throw new ConfigurationException(ImmutableSet.of(new Message(Errors.format(format, args))));
+ }
/**
- * The leaf source for errors added here.
+ * If the key is unknown and it is one of these types, it generally means there is a missing
+ * annotation.
*/
+ private static final ImmutableSet<Class<?>> COMMON_AMBIGUOUS_TYPES =
+ ImmutableSet.<Class<?>>builder()
+ .add(Object.class)
+ .add(String.class)
+ .addAll(Primitives.allWrapperTypes())
+ .build();
+
+ /** The root errors object. Used to access the list of error messages. */
+ private final Errors root;
+
+ /** The parent errors object. Used to obtain the chain of source objects. */
+ private final Errors parent;
+
+ /** The leaf source for errors added here. */
private final Object source;
- /**
- * null unless (root == this) and error messages exist. Never an empty list.
- */
+ /** null unless (root == this) and error messages exist. Never an empty list. */
private List<Message> errors; // lazy, use getErrorsForAdd()
public Errors() {
@@ -121,9 +138,7 @@ public final class Errors implements Serializable {
this.source = source;
}
- /**
- * Returns an instance that uses {@code source} as a reference point for newly added errors.
- */
+ /** Returns an instance that uses {@code source} as a reference point for newly added errors. */
public Errors withSource(Object source) {
return source == this.source || source == SourceProvider.UNKNOWN_SOURCE
? this
@@ -131,69 +146,166 @@ public final class Errors implements Serializable {
}
/**
- * We use a fairly generic error message here. The motivation is to share the
- * same message for both bind time errors:
+ * We use a fairly generic error message here. The motivation is to share the same message for
+ * both bind time errors:
+ *
* <pre><code>Guice.createInjector(new AbstractModule() {
* public void configure() {
* bind(Runnable.class);
* }
* }</code></pre>
+ *
* ...and at provide-time errors:
+ *
* <pre><code>Guice.createInjector().getInstance(Runnable.class);</code></pre>
- * Otherwise we need to know who's calling when resolving a just-in-time
- * binding, which makes things unnecessarily complex.
+ *
+ * Otherwise we need to know who's calling when resolving a just-in-time binding, which makes
+ * things unnecessarily complex.
*/
public Errors missingImplementation(Key key) {
return addMessage("No implementation for %s was bound.", key);
}
- public Errors jitDisabled(Key key) {
+ /** Within guice's core, allow for better missing binding messages */
+ <T> Errors missingImplementationWithHint(Key<T> key, Injector injector) {
+ StringBuilder sb = new StringBuilder();
+
+ sb.append(format("No implementation for %s was bound.", key));
+
+ // Keys which have similar strings as the desired key
+ List<String> possibleMatches = new ArrayList<>();
+
+ // Check for other keys that may have the same type,
+ // but not the same annotation
+ TypeLiteral<T> type = key.getTypeLiteral();
+ List<Binding<T>> sameTypes = injector.findBindingsByType(type);
+ if (!sameTypes.isEmpty()) {
+ sb.append(format("%n Did you mean?"));
+ int howMany = Math.min(sameTypes.size(), MAX_MATCHING_TYPES_REPORTED);
+ for (int i = 0; i < howMany; ++i) {
+ // TODO: Look into a better way to prioritize suggestions. For example, possbily
+ // use levenshtein distance of the given annotation vs actual annotation.
+ sb.append(format("%n * %s", sameTypes.get(i).getKey()));
+ }
+ int remaining = sameTypes.size() - MAX_MATCHING_TYPES_REPORTED;
+ if (remaining > 0) {
+ String plural = (remaining == 1) ? "" : "s";
+ sb.append(format("%n %d more binding%s with other annotations.", remaining, plural));
+ }
+ } else {
+ // For now, do a simple substring search for possibilities. This can help spot
+ // issues when there are generics being used (such as a wrapper class) and the
+ // user has forgotten they need to bind based on the wrapper, not the underlying
+ // class. In the future, consider doing a strict in-depth type search.
+ // TODO: Look into a better way to prioritize suggestions. For example, possbily
+ // use levenshtein distance of the type literal strings.
+ String want = type.toString();
+ Map<Key<?>, Binding<?>> bindingMap = injector.getAllBindings();
+ for (Key<?> bindingKey : bindingMap.keySet()) {
+ String have = bindingKey.getTypeLiteral().toString();
+ if (have.contains(want) || want.contains(have)) {
+ Formatter fmt = new Formatter();
+ Messages.formatSource(fmt, bindingMap.get(bindingKey).getSource());
+ String match = String.format("%s bound%s", convert(bindingKey), fmt.toString());
+ possibleMatches.add(match);
+ // TODO: Consider a check that if there are more than some number of results,
+ // don't suggest any.
+ if (possibleMatches.size() > MAX_RELATED_TYPES_REPORTED) {
+ // Early exit if we have found more than we need.
+ break;
+ }
+ }
+ }
+
+ if ((possibleMatches.size() > 0) && (possibleMatches.size() <= MAX_RELATED_TYPES_REPORTED)) {
+ sb.append(format("%n Did you mean?"));
+ for (String possibleMatch : possibleMatches) {
+ sb.append(format("%n %s", possibleMatch));
+ }
+ }
+ }
+
+ // If where are no possibilities to suggest, then handle the case of missing
+ // annotations on simple types. This is usually a bad idea.
+ if (sameTypes.isEmpty()
+ && possibleMatches.isEmpty()
+ && key.getAnnotation() == null
+ && COMMON_AMBIGUOUS_TYPES.contains(key.getTypeLiteral().getRawType())) {
+ // We don't recommend using such simple types without annotations.
+ sb.append(format("%nThe key seems very generic, did you forget an annotation?"));
+ }
+
+ return addMessage(sb.toString());
+ }
+
+ public Errors jitDisabled(Key<?> key) {
return addMessage("Explicit bindings are required and %s is not explicitly bound.", key);
}
public Errors jitDisabledInParent(Key<?> key) {
return addMessage(
"Explicit bindings are required and %s would be bound in a parent injector.%n"
- + "Please add an explicit binding for it, either in the child or the parent.",
+ + "Please add an explicit binding for it, either in the child or the parent.",
key);
}
public Errors atInjectRequired(Class clazz) {
return addMessage(
"Explicit @Inject annotations are required on constructors,"
- + " but %s has no constructors annotated with @Inject.",
+ + " but %s has no constructors annotated with @Inject.",
clazz);
}
- public Errors converterReturnedNull(String stringValue, Object source,
- TypeLiteral<?> type, TypeConverterBinding typeConverterBinding) {
- return addMessage("Received null converting '%s' (bound at %s) to %s%n"
- + " using %s.",
+ public Errors converterReturnedNull(
+ String stringValue,
+ Object source,
+ TypeLiteral<?> type,
+ TypeConverterBinding typeConverterBinding) {
+ return addMessage(
+ "Received null converting '%s' (bound at %s) to %s%n using %s.",
stringValue, convert(source), type, typeConverterBinding);
}
- public Errors conversionTypeError(String stringValue, Object source, TypeLiteral<?> type,
- TypeConverterBinding typeConverterBinding, Object converted) {
- return addMessage("Type mismatch converting '%s' (bound at %s) to %s%n"
- + " using %s.%n"
- + " Converter returned %s.",
+ public Errors conversionTypeError(
+ String stringValue,
+ Object source,
+ TypeLiteral<?> type,
+ TypeConverterBinding typeConverterBinding,
+ Object converted) {
+ return addMessage(
+ "Type mismatch converting '%s' (bound at %s) to %s%n"
+ + " using %s.%n"
+ + " Converter returned %s.",
stringValue, convert(source), type, typeConverterBinding, converted);
}
- public Errors conversionError(String stringValue, Object source,
- TypeLiteral<?> type, TypeConverterBinding typeConverterBinding, RuntimeException cause) {
- return errorInUserCode(cause, "Error converting '%s' (bound at %s) to %s%n"
- + " using %s.%n"
- + " Reason: %s",
- stringValue, convert(source), type, typeConverterBinding, cause);
- }
-
- public Errors ambiguousTypeConversion(String stringValue, Object source, TypeLiteral<?> type,
- TypeConverterBinding a, TypeConverterBinding b) {
- return addMessage("Multiple converters can convert '%s' (bound at %s) to %s:%n"
- + " %s and%n"
- + " %s.%n"
- + " Please adjust your type converter configuration to avoid overlapping matches.",
+ public Errors conversionError(
+ String stringValue,
+ Object source,
+ TypeLiteral<?> type,
+ TypeConverterBinding typeConverterBinding,
+ RuntimeException cause) {
+ return errorInUserCode(
+ cause,
+ "Error converting '%s' (bound at %s) to %s%n using %s.%n Reason: %s",
+ stringValue,
+ convert(source),
+ type,
+ typeConverterBinding,
+ cause);
+ }
+
+ public Errors ambiguousTypeConversion(
+ String stringValue,
+ Object source,
+ TypeLiteral<?> type,
+ TypeConverterBinding a,
+ TypeConverterBinding b) {
+ return addMessage(
+ "Multiple converters can convert '%s' (bound at %s) to %s:%n"
+ + " %s and%n"
+ + " %s.%n"
+ + " Please adjust your type converter configuration to avoid overlapping matches.",
stringValue, convert(source), type, a, b);
}
@@ -201,11 +313,6 @@ public final class Errors implements Serializable {
return addMessage("Binding to Provider is not allowed.");
}
- public Errors subtypeNotProvided(Class<? extends Provider<?>> providerType,
- Class<?> type) {
- return addMessage("%s doesn't provide instances of %s.", providerType, type);
- }
-
public Errors notASubtype(Class<?> implementationType, Class<?> type) {
return addMessage("%s doesn't extend %s.", implementationType, type);
}
@@ -227,8 +334,9 @@ public final class Errors implements Serializable {
}
public Errors optionalConstructor(Constructor constructor) {
- return addMessage("%s is annotated @Inject(optional=true), "
- + "but constructors cannot be optional.", constructor);
+ return addMessage(
+ "%s is annotated @Inject(optional=true), but constructors cannot be optional.",
+ constructor);
}
public Errors cannotBindToGuiceType(String simpleName) {
@@ -241,13 +349,17 @@ public final class Errors implements Serializable {
public Errors scopeAnnotationOnAbstractType(
Class<? extends Annotation> scopeAnnotation, Class<?> type, Object source) {
- return addMessage("%s is annotated with %s, but scope annotations are not supported "
- + "for abstract types.%n Bound at %s.", type, scopeAnnotation, convert(source));
+ return addMessage(
+ "%s is annotated with %s, but scope annotations are not supported "
+ + "for abstract types.%n Bound at %s.",
+ type, scopeAnnotation, convert(source));
}
public Errors misplacedBindingAnnotation(Member member, Annotation bindingAnnotation) {
- return addMessage("%s is annotated with %s, but binding annotations should be applied "
- + "to its parameters instead.", member, bindingAnnotation);
+ return addMessage(
+ "%s is annotated with %s, but binding annotations should be applied "
+ + "to its parameters instead.",
+ member, bindingAnnotation);
}
private static final String CONSTRUCTOR_RULES =
@@ -255,22 +367,24 @@ public final class Errors implements Serializable {
+ "annotated with @Inject or a zero-argument constructor that is not private.";
public Errors missingConstructor(Class<?> implementation) {
- return addMessage("Could not find a suitable constructor in %s. " + CONSTRUCTOR_RULES,
- implementation);
+ return addMessage(
+ "Could not find a suitable constructor in %s. " + CONSTRUCTOR_RULES, implementation);
}
public Errors tooManyConstructors(Class<?> implementation) {
- return addMessage("%s has more than one constructor annotated with @Inject. "
- + CONSTRUCTOR_RULES, implementation);
+ return addMessage(
+ "%s has more than one constructor annotated with @Inject. " + CONSTRUCTOR_RULES,
+ implementation);
}
public Errors constructorNotDefinedByType(Constructor<?> constructor, TypeLiteral<?> type) {
return addMessage("%s does not define %s", type, constructor);
}
- public Errors duplicateScopes(ScopeBinding existing,
- Class<? extends Annotation> annotationType, Scope scope) {
- return addMessage("Scope %s is already bound to %s at %s.%n Cannot bind %s.",
+ public Errors duplicateScopes(
+ ScopeBinding existing, Class<? extends Annotation> annotationType, Scope scope) {
+ return addMessage(
+ "Scope %s is already bound to %s at %s.%n Cannot bind %s.",
existing.getScope(), annotationType, existing.getSource(), scope);
}
@@ -283,14 +397,17 @@ public final class Errors implements Serializable {
}
public Errors cannotInjectInnerClass(Class<?> type) {
- return addMessage("Injecting into inner classes is not supported. "
- + "Please use a 'static' class (top-level or nested) instead of %s.", type);
+ return addMessage(
+ "Injecting into inner classes is not supported. "
+ + "Please use a 'static' class (top-level or nested) instead of %s.",
+ type);
}
- public Errors duplicateBindingAnnotations(Member member,
- Class<? extends Annotation> a, Class<? extends Annotation> b) {
- return addMessage("%s has more than one annotation annotated with @BindingAnnotation: "
- + "%s and %s", member, a, b);
+ public Errors duplicateBindingAnnotations(
+ Member member, Class<? extends Annotation> a, Class<? extends Annotation> b) {
+ return addMessage(
+ "%s has more than one annotation annotated with @BindingAnnotation: %s and %s",
+ member, a, b);
}
public Errors staticInjectionOnInterface(Class<?> clazz) {
@@ -327,7 +444,8 @@ public final class Errors implements Serializable {
}
public Errors jitBindingAlreadySet(Key<?> key) {
- return addMessage("A just-in-time binding to %s was already configured on a parent injector.", key);
+ return addMessage(
+ "A just-in-time binding to %s was already configured on a parent injector.", key);
}
public Errors childBindingAlreadySet(Key<?> key, Set<Object> sources) {
@@ -339,53 +457,32 @@ public final class Errors implements Serializable {
allSources.format("%n bound at %s", source);
}
}
- Errors errors = addMessage(
- "Unable to create binding for %s."
- + " It was already configured on one or more child injectors or private modules"
- + "%s%n"
- + " If it was in a PrivateModule, did you forget to expose the binding?",
- key, allSources.out());
+ Errors errors =
+ addMessage(
+ "Unable to create binding for %s."
+ + " It was already configured on one or more child injectors or private modules"
+ + "%s%n"
+ + " If it was in a PrivateModule, did you forget to expose the binding?",
+ key, allSources.out());
return errors;
}
public Errors errorCheckingDuplicateBinding(Key<?> key, Object source, Throwable t) {
return addMessage(
"A binding to %s was already configured at %s and an error was thrown "
- + "while checking duplicate bindings. Error: %s",
+ + "while checking duplicate bindings. Error: %s",
key, convert(source), t);
}
- public Errors errorInjectingMethod(Throwable cause) {
- return errorInUserCode(cause, "Error injecting method, %s", cause);
- }
-
- public Errors errorNotifyingTypeListener(TypeListenerBinding listener,
- TypeLiteral<?> type, Throwable cause) {
- return errorInUserCode(cause,
- "Error notifying TypeListener %s (bound at %s) of %s.%n"
- + " Reason: %s",
- listener.getListener(), convert(listener.getSource()), type, cause);
- }
-
- public Errors errorInjectingConstructor(Throwable cause) {
- return errorInUserCode(cause, "Error injecting constructor, %s", cause);
- }
-
- public Errors errorInProvider(RuntimeException runtimeException) {
- Throwable unwrapped = unwrap(runtimeException);
- return errorInUserCode(unwrapped, "Error in custom provider, %s", unwrapped);
- }
-
- public Errors errorInUserInjector(
- MembersInjector<?> listener, TypeLiteral<?> type, RuntimeException cause) {
- return errorInUserCode(cause, "Error injecting %s using %s.%n"
- + " Reason: %s", type, listener, cause);
- }
-
- public Errors errorNotifyingInjectionListener(
- InjectionListener<?> listener, TypeLiteral<?> type, RuntimeException cause) {
- return errorInUserCode(cause, "Error notifying InjectionListener %s of %s.%n"
- + " Reason: %s", listener, type, cause);
+ public Errors errorNotifyingTypeListener(
+ TypeListenerBinding listener, TypeLiteral<?> type, Throwable cause) {
+ return errorInUserCode(
+ cause,
+ "Error notifying TypeListener %s (bound at %s) of %s.%n Reason: %s",
+ listener.getListener(),
+ convert(listener.getSource()),
+ type,
+ cause);
}
public Errors exposedButNotBound(Key<?> key) {
@@ -422,14 +519,6 @@ public final class Errors implements Serializable {
}
}
- private Throwable unwrap(RuntimeException runtimeException) {
- if(runtimeException instanceof Exceptions.UnhandledCheckedUserException) {
- return runtimeException.getCause();
- } else {
- return runtimeException;
- }
- }
-
public Errors cannotInjectRawProvider() {
return addMessage("Cannot inject a Provider that has no type parameter");
}
@@ -446,18 +535,6 @@ public final class Errors implements Serializable {
return addMessage("Cannot inject a TypeLiteral that has no type parameter");
}
- public Errors cannotSatisfyCircularDependency(Class<?> expectedType) {
- return addMessage(
- "Tried proxying %s to support a circular dependency, but it is not an interface.",
- expectedType);
- }
-
- public Errors circularProxiesDisabled(Class<?> expectedType) {
- return addMessage(
- "Tried proxying %s to support a circular dependency, but circular proxies are disabled.",
- expectedType);
- }
-
public void throwCreationExceptionIfErrorsExist() {
if (!hasErrors()) {
return;
@@ -474,6 +551,7 @@ public final class Errors implements Serializable {
throw new ConfigurationException(getMessages());
}
+ // Guice no longer calls this, but external callers do
public void throwProvisionExceptionIfErrorsExist() {
if (!hasErrors()) {
return;
@@ -482,16 +560,10 @@ public final class Errors implements Serializable {
throw new ProvisionException(getMessages());
}
- private Message merge(Message message) {
- List<Object> sources = Lists.newArrayList();
- sources.addAll(getSources());
- sources.addAll(message.getSources());
- return new Message(sources, message.getMessage(), message.getCause());
- }
-
public Errors merge(Collection<Message> messages) {
+ List<Object> sources = getSources();
for (Message message : messages) {
- addMessage(merge(message));
+ addMessage(Messages.mergeSources(sources, message));
}
return this;
}
@@ -505,7 +577,12 @@ public final class Errors implements Serializable {
return this;
}
- public List<Object> getSources() {
+ public Errors merge(InternalProvisionException ipe) {
+ merge(ipe.getErrors());
+ return this;
+ }
+
+ private List<Object> getSources() {
List<Object> sources = Lists.newArrayList();
for (Errors e = this; e != null; e = e.parent) {
if (e.source != SourceProvider.UNKNOWN_SOURCE) {
@@ -536,8 +613,7 @@ public final class Errors implements Serializable {
}
private Errors addMessage(Throwable cause, String messageFormat, Object... arguments) {
- String message = format(messageFormat, arguments);
- addMessage(new Message(getSources(), message, cause));
+ addMessage(Messages.create(cause, getSources(), messageFormat, arguments));
return this;
}
@@ -549,11 +625,9 @@ public final class Errors implements Serializable {
return this;
}
+ // TODO(lukes): inline into callers
public static String format(String messageFormat, Object... arguments) {
- for (int i = 0; i < arguments.length; i++) {
- arguments[i] = Errors.convert(arguments[i]);
- }
- return String.format(messageFormat, arguments);
+ return Messages.format(messageFormat, arguments);
}
public List<Message> getMessages() {
@@ -569,274 +643,23 @@ public final class Errors implements Serializable {
}.sortedCopy(root.errors);
}
- /** Returns the formatted message for an exception with the specified messages. */
- public static String format(String heading, Collection<Message> errorMessages) {
- Formatter fmt = new Formatter().format(heading).format(":%n%n");
- int index = 1;
- boolean displayCauses = getOnlyCause(errorMessages) == null;
-
- for (Message errorMessage : errorMessages) {
- fmt.format("%s) %s%n", index++, errorMessage.getMessage());
-
- List<Object> dependencies = errorMessage.getSources();
- for (int i = dependencies.size() - 1; i >= 0; i--) {
- Object source = dependencies.get(i);
- formatSource(fmt, source);
- }
-
- Throwable cause = errorMessage.getCause();
- if (displayCauses && cause != null) {
- StringWriter writer = new StringWriter();
- cause.printStackTrace(new PrintWriter(writer));
- fmt.format("Caused by: %s", writer.getBuffer());
- }
-
- fmt.format("%n");
- }
-
- if (errorMessages.size() == 1) {
- fmt.format("1 error");
- } else {
- fmt.format("%s errors", errorMessages.size());
- }
-
- return fmt.toString();
- }
-
- /**
- * Returns {@code value} if it is non-null allowed to be null. Otherwise a message is added and
- * an {@code ErrorsException} is thrown.
- */
- public <T> T checkForNull(T value, Object source, Dependency<?> dependency)
- throws ErrorsException {
- if (value != null || dependency.isNullable() ) {
- return value;
- }
-
- // Hack to allow null parameters to @Provides methods, for backwards compatibility.
- if (dependency.getInjectionPoint().getMember() instanceof Method) {
- Method annotated = (Method) dependency.getInjectionPoint().getMember();
- if (annotated.isAnnotationPresent(Provides.class)) {
- switch (InternalFlags.getNullableProvidesOption()) {
- case ERROR:
- break; // break out & let the below exception happen
- case IGNORE:
- return value; // user doesn't care about injecting nulls to non-@Nullables.
- case WARN:
- // Warn only once, otherwise we spam logs too much.
- if (!warnedDependencies.add(dependency)) {
- return value;
- }
- logger.log(Level.WARNING,
- "Guice injected null into parameter {0} of {1} (a {2}), please mark it @Nullable."
- + " Use -Dguice_check_nullable_provides_params=ERROR to turn this into an"
- + " error.",
- new Object[] {
- dependency.getParameterIndex(),
- convert(dependency.getInjectionPoint().getMember()),
- convert(dependency.getKey())});
- return null; // log & exit.
- }
- }
- }
-
- int parameterIndex = dependency.getParameterIndex();
- String parameterName = (parameterIndex != -1)
- ? "parameter " + parameterIndex + " of "
- : "";
- addMessage("null returned by binding at %s%n but %s%s is not @Nullable",
- source, parameterName, dependency.getInjectionPoint().getMember());
-
- throw toException();
- }
-
- /**
- * Returns the cause throwable if there is exactly one cause in {@code messages}. If there are
- * zero or multiple messages with causes, null is returned.
- */
- public static Throwable getOnlyCause(Collection<Message> messages) {
- Throwable onlyCause = null;
- for (Message message : messages) {
- Throwable messageCause = message.getCause();
- if (messageCause == null) {
- continue;
- }
-
- if (onlyCause != null) {
- return null;
- }
-
- onlyCause = messageCause;
- }
-
- return onlyCause;
- }
-
public int size() {
return root.errors == null ? 0 : root.errors.size();
}
- private static abstract class Converter<T> {
-
- final Class<T> type;
-
- Converter(Class<T> type) {
- this.type = type;
- }
-
- boolean appliesTo(Object o) {
- return o != null && type.isAssignableFrom(o.getClass());
- }
-
- String convert(Object o) {
- return toString(type.cast(o));
- }
-
- abstract String toString(T t);
- }
-
- private static final Collection<Converter<?>> converters = ImmutableList.of(
- new Converter<Class>(Class.class) {
- @Override public String toString(Class c) {
- return c.getName();
- }
- },
- new Converter<Member>(Member.class) {
- @Override public String toString(Member member) {
- return Classes.toString(member);
- }
- },
- new Converter<Key>(Key.class) {
- @Override public String toString(Key key) {
- if (key.getAnnotationType() != null) {
- return key.getTypeLiteral() + " annotated with "
- + (key.getAnnotation() != null ? key.getAnnotation() : key.getAnnotationType());
- } else {
- return key.getTypeLiteral().toString();
- }
- }
- });
-
+ // TODO(lukes): inline in callers. There are some callers outside of guice, so this is difficult
public static Object convert(Object o) {
- ElementSource source = null;
- if (o instanceof ElementSource) {
- source = (ElementSource)o;
- o = source.getDeclaringSource();
- }
- return convert(o, source);
+ return Messages.convert(o);
}
+ // TODO(lukes): inline in callers. There are some callers outside of guice, so this is difficult
public static Object convert(Object o, ElementSource source) {
- for (Converter<?> converter : converters) {
- if (converter.appliesTo(o)) {
- return appendModules(converter.convert(o), source);
- }
- }
- return appendModules(o, source);
- }
-
- private static Object appendModules(Object source, ElementSource elementSource) {
- String modules = moduleSourceString(elementSource);
- if (modules.length() == 0) {
- return source;
- } else {
- return source + modules;
- }
- }
-
- private static String moduleSourceString(ElementSource elementSource) {
- // if we only have one module (or don't know what they are), then don't bother
- // reporting it, because the source already is going to report exactly that module.
- if (elementSource == null) {
- return "";
- }
- List<String> modules = Lists.newArrayList(elementSource.getModuleClassNames());
- // Insert any original element sources w/ module info into the path.
- while(elementSource.getOriginalElementSource() != null) {
- elementSource = elementSource.getOriginalElementSource();
- modules.addAll(0, elementSource.getModuleClassNames());
- }
- if (modules.size() <= 1) {
- return "";
- }
-
- // Ideally we'd do:
- // return Joiner.on(" -> ")
- // .appendTo(new StringBuilder(" (via modules: "), Lists.reverse(modules))
- // .append(")").toString();
- // ... but for some reason we can't find Lists.reverse, so do it the boring way.
- StringBuilder builder = new StringBuilder(" (via modules: ");
- for (int i = modules.size() - 1; i >= 0; i--) {
- builder.append(modules.get(i));
- if (i != 0) {
- builder.append(" -> ");
- }
- }
- builder.append(")");
- return builder.toString();
+ return Messages.convert(o, source);
}
+ // TODO(lukes): inline in callers. There are some callers outside of guice, so this is difficult
public static void formatSource(Formatter formatter, Object source) {
- ElementSource elementSource = null;
- if (source instanceof ElementSource) {
- elementSource = (ElementSource)source;
- source = elementSource.getDeclaringSource();
- }
- formatSource(formatter, source, elementSource);
+ Messages.formatSource(formatter, source);
}
- public static void formatSource(Formatter formatter, Object source, ElementSource elementSource) {
- String modules = moduleSourceString(elementSource);
- if (source instanceof Dependency) {
- Dependency<?> dependency = (Dependency<?>) source;
- InjectionPoint injectionPoint = dependency.getInjectionPoint();
- if (injectionPoint != null) {
- formatInjectionPoint(formatter, dependency, injectionPoint, elementSource);
- } else {
- formatSource(formatter, dependency.getKey(), elementSource);
- }
-
- } else if (source instanceof InjectionPoint) {
- formatInjectionPoint(formatter, null, (InjectionPoint) source, elementSource);
-
- } else if (source instanceof Class) {
- formatter.format(" at %s%s%n", StackTraceElements.forType((Class<?>) source), modules);
-
- } else if (source instanceof Member) {
- formatter.format(" at %s%s%n", StackTraceElements.forMember((Member) source), modules);
-
- } else if (source instanceof TypeLiteral) {
- formatter.format(" while locating %s%s%n", source, modules);
-
- } else if (source instanceof Key) {
- Key<?> key = (Key<?>) source;
- formatter.format(" while locating %s%n", convert(key, elementSource));
-
- } else if (source instanceof Thread) {
- formatter.format(" in thread %s%n", source);
-
- } else {
- formatter.format(" at %s%s%n", source, modules);
- }
- }
-
- public static void formatInjectionPoint(Formatter formatter, Dependency<?> dependency,
- InjectionPoint injectionPoint, ElementSource elementSource) {
- Member member = injectionPoint.getMember();
- Class<? extends Member> memberType = Classes.memberType(member);
-
- if (memberType == Field.class) {
- dependency = injectionPoint.getDependencies().get(0);
- formatter.format(" while locating %s%n", convert(dependency.getKey(), elementSource));
- formatter.format(" for field at %s%n", StackTraceElements.forMember(member));
-
- } else if (dependency != null) {
- formatter.format(" while locating %s%n", convert(dependency.getKey(), elementSource));
- formatter.format(" for parameter %s at %s%n",
- dependency.getParameterIndex(), StackTraceElements.forMember(member));
-
- } else {
- formatSource(formatter, injectionPoint.getMember());
- }
- }
}
diff --git a/core/src/com/google/inject/internal/ErrorsException.java b/core/src/com/google/inject/internal/ErrorsException.java
index 57f55c49..6e95dbc7 100644
--- a/core/src/com/google/inject/internal/ErrorsException.java
+++ b/core/src/com/google/inject/internal/ErrorsException.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package com.google.inject.internal;
/**
@@ -25,6 +24,8 @@ package com.google.inject.internal;
* @author jessewilson@google.com (Jesse Wilson)
*/
public class ErrorsException extends Exception {
+ // NOTE: this is used by Gin which is abandoned. So changing this API will prevent Gin users from
+ // upgrading Guice version.
private final Errors errors;
diff --git a/core/src/com/google/inject/internal/Exceptions.java b/core/src/com/google/inject/internal/Exceptions.java
deleted file mode 100644
index f9d1e21f..00000000
--- a/core/src/com/google/inject/internal/Exceptions.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * Copyright (C) 2010 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.internal;
-
-
-/**
- * Rethrows user-code exceptions in wrapped exceptions so that Errors can target the correct
- * exception.
- *
- * @author sameb@google.com (Sam Berlin)
- */
-class Exceptions {
-
- /**
- * Rethrows the exception (or it's cause, if it has one) directly if possible.
- * If it was a checked exception, this wraps the exception in a stack trace
- * with no frames, so that the exception is shown immediately with no frames
- * above it.
- */
- public static RuntimeException rethrowCause(Throwable throwable) {
- Throwable cause = throwable;
- if(cause.getCause() != null) {
- cause = cause.getCause();
- }
- return rethrow(cause);
- }
-
- /** Rethrows the exception. */
- public static RuntimeException rethrow(Throwable throwable) {
- if(throwable instanceof RuntimeException) {
- throw (RuntimeException)throwable;
- } else if(throwable instanceof Error) {
- throw (Error)throwable;
- } else {
- throw new UnhandledCheckedUserException(throwable);
- }
- }
-
- /**
- * A marker exception class that we look for in order to unwrap the exception
- * into the user exception, to provide a cleaner stack trace.
- */
- static class UnhandledCheckedUserException extends RuntimeException {
- public UnhandledCheckedUserException(Throwable cause) {
- super(cause);
- }
- }
-}
diff --git a/core/src/com/google/inject/internal/ExposedBindingImpl.java b/core/src/com/google/inject/internal/ExposedBindingImpl.java
index f17d5a6a..1dfe4088 100644
--- a/core/src/com/google/inject/internal/ExposedBindingImpl.java
+++ b/core/src/com/google/inject/internal/ExposedBindingImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
package com.google.inject.internal;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
import com.google.inject.Injector;
@@ -25,43 +25,51 @@ import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.ExposedBinding;
import com.google.inject.spi.PrivateElements;
-
import java.util.Set;
public final class ExposedBindingImpl<T> extends BindingImpl<T> implements ExposedBinding<T> {
private final PrivateElements privateElements;
- public ExposedBindingImpl(InjectorImpl injector, Object source, Key<T> key,
- InternalFactory<T> factory, PrivateElements privateElements) {
+ public ExposedBindingImpl(
+ InjectorImpl injector,
+ Object source,
+ Key<T> key,
+ InternalFactory<T> factory,
+ PrivateElements privateElements) {
super(injector, key, source, factory, Scoping.UNSCOPED);
this.privateElements = privateElements;
}
+ @Override
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
return visitor.visit(this);
}
+ @Override
public Set<Dependency<?>> getDependencies() {
return ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class)));
}
+ @Override
public PrivateElements getPrivateElements() {
return privateElements;
}
- @Override public String toString() {
- return Objects.toStringHelper(ExposedBinding.class)
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(ExposedBinding.class)
.add("key", getKey())
.add("source", getSource())
.add("privateElements", privateElements)
.toString();
}
+ @Override
public void applyTo(Binder binder) {
throw new UnsupportedOperationException("This element represents a synthetic binding.");
}
-
+
// Purposely does not override equals/hashcode, because exposed bindings are only equal to
// themselves right now -- that is, there cannot be "duplicate" exposed bindings.
}
diff --git a/core/src/com/google/inject/internal/ExposedKeyFactory.java b/core/src/com/google/inject/internal/ExposedKeyFactory.java
index 52bf7cb6..5de73aae 100644
--- a/core/src/com/google/inject/internal/ExposedKeyFactory.java
+++ b/core/src/com/google/inject/internal/ExposedKeyFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,6 +34,7 @@ final class ExposedKeyFactory<T> implements InternalFactory<T>, CreationListener
this.privateElements = privateElements;
}
+ @Override
public void notify(Errors errors) {
InjectorImpl privateInjector = (InjectorImpl) privateElements.getInjector();
BindingImpl<T> explicitBinding = privateInjector.state.getExplicitBinding(key);
@@ -49,8 +50,10 @@ final class ExposedKeyFactory<T> implements InternalFactory<T>, CreationListener
this.delegate = explicitBinding;
}
- public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
- throws ErrorsException {
- return delegate.getInternalFactory().get(errors, context, dependency, linked);
+ @Override
+ public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+ throws InternalProvisionException {
+ // TODO(lukes): add a source to the thrown exception?
+ return delegate.getInternalFactory().get(context, dependency, linked);
}
}
diff --git a/core/src/com/google/inject/internal/ExposureBuilder.java b/core/src/com/google/inject/internal/ExposureBuilder.java
index 3b1c2279..35dca169 100644
--- a/core/src/com/google/inject/internal/ExposureBuilder.java
+++ b/core/src/com/google/inject/internal/ExposureBuilder.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,12 +20,9 @@ import com.google.common.base.Preconditions;
import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.binder.AnnotatedElementBuilder;
-
import java.lang.annotation.Annotation;
-/**
- * For private binder's expose() method.
- */
+/** For private binder's expose() method. */
public class ExposureBuilder<T> implements AnnotatedElementBuilder {
private final Binder binder;
private final Object source;
@@ -43,12 +40,14 @@ public class ExposureBuilder<T> implements AnnotatedElementBuilder {
}
}
+ @Override
public void annotatedWith(Class<? extends Annotation> annotationType) {
Preconditions.checkNotNull(annotationType, "annotationType");
checkNotAnnotated();
key = Key.get(key.getTypeLiteral(), annotationType);
}
+ @Override
public void annotatedWith(Annotation annotation) {
Preconditions.checkNotNull(annotation, "annotation");
checkNotAnnotated();
@@ -63,7 +62,8 @@ public class ExposureBuilder<T> implements AnnotatedElementBuilder {
return source;
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "AnnotatedElementBuilder";
}
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/internal/FactoryProxy.java b/core/src/com/google/inject/internal/FactoryProxy.java
index 6416d26e..a3a2227f 100644
--- a/core/src/com/google/inject/internal/FactoryProxy.java
+++ b/core/src/com/google/inject/internal/FactoryProxy.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,14 +16,14 @@
package com.google.inject.internal;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
import com.google.inject.Key;
import com.google.inject.internal.InjectorImpl.JitLimitation;
import com.google.inject.spi.Dependency;
/**
- * A placeholder which enables us to swap in the real factory once the injector is created.
- * Used for a linked binding, so that getting the linked binding returns the link's factory.
+ * A placeholder which enables us to swap in the real factory once the injector is created. Used for
+ * a linked binding, so that getting the linked binding returns the link's factory.
*/
final class FactoryProxy<T> implements InternalFactory<T>, CreationListener {
@@ -41,26 +41,36 @@ final class FactoryProxy<T> implements InternalFactory<T>, CreationListener {
this.source = source;
}
+ @Override
public void notify(final Errors errors) {
try {
- targetFactory = injector.getInternalFactory(targetKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT);
+ targetFactory =
+ injector.getInternalFactory(
+ targetKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
}
}
- public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
- throws ErrorsException {
- context.pushState(targetKey, source);
+ @Override
+ public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+ throws InternalProvisionException {
+ Key<? extends T> localTargetKey = targetKey;
+ context.pushState(localTargetKey, source);
+
try {
- return targetFactory.get(errors.withSource(targetKey), context, dependency, true);
- } finally {
- context.popState();
+ return targetFactory.get(context, dependency, true);
+ } catch (InternalProvisionException ipe) {
+ throw ipe.addSource(localTargetKey);
+ } finally {
+ context.popState();
+
}
}
- @Override public String toString() {
- return Objects.toStringHelper(FactoryProxy.class)
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(FactoryProxy.class)
.add("key", key)
.add("provider", targetFactory)
.toString();
diff --git a/core/src/com/google/inject/internal/FailableCache.java b/core/src/com/google/inject/internal/FailableCache.java
index acd8be5b..e1a461d8 100644
--- a/core/src/com/google/inject/internal/FailableCache.java
+++ b/core/src/com/google/inject/internal/FailableCache.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,23 +27,26 @@ import com.google.common.cache.LoadingCache;
* @author jessewilson@google.com (Jesse Wilson)
*/
public abstract class FailableCache<K, V> {
-
- private final LoadingCache<K, Object> delegate = CacheBuilder.newBuilder().build(
- new CacheLoader<K, Object>() {
- public Object load(K key) {
- Errors errors = new Errors();
- V result = null;
- try {
- result = FailableCache.this.create(key, errors);
- } catch (ErrorsException e) {
- errors.merge(e.getErrors());
- }
- return errors.hasErrors() ? errors : result;
- }
- });
+
+ private final LoadingCache<K, Object> delegate =
+ CacheBuilder.newBuilder()
+ .build(
+ new CacheLoader<K, Object>() {
+ @Override
+ public Object load(K key) {
+ Errors errors = new Errors();
+ V result = null;
+ try {
+ result = FailableCache.this.create(key, errors);
+ } catch (ErrorsException e) {
+ errors.merge(e.getErrors());
+ }
+ return errors.hasErrors() ? errors : result;
+ }
+ });
protected abstract V create(K key, Errors errors) throws ErrorsException;
-
+
public V get(K key, Errors errors) throws ErrorsException {
Object resultOrError = delegate.getUnchecked(key);
if (resultOrError instanceof Errors) {
@@ -55,7 +58,7 @@ public abstract class FailableCache<K, V> {
return result;
}
}
-
+
boolean remove(K key) {
return delegate.asMap().remove(key) != null;
}
diff --git a/core/src/com/google/inject/internal/Indexer.java b/core/src/com/google/inject/internal/Indexer.java
new file mode 100644
index 00000000..acbc1638
--- /dev/null
+++ b/core/src/com/google/inject/internal/Indexer.java
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2014 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.internal;
+
+import com.google.common.base.Objects;
+import com.google.inject.Binding;
+import com.google.inject.Injector;
+import com.google.inject.Scope;
+import com.google.inject.Scopes;
+import com.google.inject.TypeLiteral;
+import com.google.inject.spi.BindingScopingVisitor;
+import com.google.inject.spi.ConstructorBinding;
+import com.google.inject.spi.ConvertedConstantBinding;
+import com.google.inject.spi.DefaultBindingTargetVisitor;
+import com.google.inject.spi.ExposedBinding;
+import com.google.inject.spi.InstanceBinding;
+import com.google.inject.spi.LinkedKeyBinding;
+import com.google.inject.spi.ProviderBinding;
+import com.google.inject.spi.ProviderInstanceBinding;
+import com.google.inject.spi.ProviderKeyBinding;
+import com.google.inject.spi.UntargettedBinding;
+import java.lang.annotation.Annotation;
+
+/**
+ * Visits bindings to return a {@code IndexedBinding} that can be used to emulate the binding
+ * deduplication that Guice internally performs.
+ *
+ * <p>Note: simply using equals/hashCode on the BindingImpls doesn't work because they all have
+ * unique annotations. This works around that by reimplementing equality semantics that ignores
+ * {@link Element#uniqueId()}. A better solution might be to introduce the idea of an 'anonymous'
+ * binding to guice, that might support this usecase directly.
+ */
+class Indexer extends DefaultBindingTargetVisitor<Object, Indexer.IndexedBinding>
+ implements BindingScopingVisitor<Object> {
+ enum BindingType {
+ INSTANCE,
+ PROVIDER_INSTANCE,
+ PROVIDER_KEY,
+ LINKED_KEY,
+ UNTARGETTED,
+ CONSTRUCTOR,
+ CONSTANT,
+ EXPOSED,
+ PROVIDED_BY,
+ }
+
+ static class IndexedBinding {
+ final String annotationName;
+ final Element.Type annotationType;
+ final TypeLiteral<?> typeLiteral;
+ final Object scope;
+ final BindingType type;
+ final Object extraEquality;
+
+ IndexedBinding(Binding<?> binding, BindingType type, Object scope, Object extraEquality) {
+ this.scope = scope;
+ this.type = type;
+ this.extraEquality = extraEquality;
+ this.typeLiteral = binding.getKey().getTypeLiteral();
+ Element annotation = (Element) binding.getKey().getAnnotation();
+ this.annotationName = annotation.setName();
+ this.annotationType = annotation.type();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (!(obj instanceof IndexedBinding)) {
+ return false;
+ }
+ IndexedBinding o = (IndexedBinding) obj;
+ return type == o.type
+ && Objects.equal(scope, o.scope)
+ && typeLiteral.equals(o.typeLiteral)
+ && annotationType == o.annotationType
+ && annotationName.equals(o.annotationName)
+ && Objects.equal(extraEquality, o.extraEquality);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(
+ type, scope, typeLiteral, annotationType, annotationName, extraEquality);
+ }
+ }
+
+ final Injector injector;
+
+ Indexer(Injector injector) {
+ this.injector = injector;
+ }
+
+ boolean isIndexable(Binding<?> binding) {
+ return binding.getKey().getAnnotation() instanceof Element;
+ }
+
+ private Object scope(Binding<?> binding) {
+ return binding.acceptScopingVisitor(this);
+ }
+
+ @Override
+ public Indexer.IndexedBinding visit(ConstructorBinding<? extends Object> binding) {
+ return new Indexer.IndexedBinding(
+ binding, BindingType.CONSTRUCTOR, scope(binding), binding.getConstructor());
+ }
+
+ @Override
+ public Indexer.IndexedBinding visit(ConvertedConstantBinding<? extends Object> binding) {
+ return new Indexer.IndexedBinding(
+ binding, BindingType.CONSTANT, scope(binding), binding.getValue());
+ }
+
+ @Override
+ public Indexer.IndexedBinding visit(ExposedBinding<? extends Object> binding) {
+ return new Indexer.IndexedBinding(binding, BindingType.EXPOSED, scope(binding), binding);
+ }
+
+ @Override
+ public Indexer.IndexedBinding visit(InstanceBinding<? extends Object> binding) {
+ return new Indexer.IndexedBinding(
+ binding, BindingType.INSTANCE, scope(binding), binding.getInstance());
+ }
+
+ @Override
+ public Indexer.IndexedBinding visit(LinkedKeyBinding<? extends Object> binding) {
+ return new Indexer.IndexedBinding(
+ binding, BindingType.LINKED_KEY, scope(binding), binding.getLinkedKey());
+ }
+
+ @Override
+ public Indexer.IndexedBinding visit(ProviderBinding<? extends Object> binding) {
+ return new Indexer.IndexedBinding(
+ binding,
+ BindingType.PROVIDED_BY,
+ scope(binding),
+ injector.getBinding(binding.getProvidedKey()));
+ }
+
+ @Override
+ public Indexer.IndexedBinding visit(ProviderInstanceBinding<? extends Object> binding) {
+ return new Indexer.IndexedBinding(
+ binding, BindingType.PROVIDER_INSTANCE, scope(binding), binding.getUserSuppliedProvider());
+ }
+
+ @Override
+ public Indexer.IndexedBinding visit(ProviderKeyBinding<? extends Object> binding) {
+ return new Indexer.IndexedBinding(
+ binding, BindingType.PROVIDER_KEY, scope(binding), binding.getProviderKey());
+ }
+
+ @Override
+ public Indexer.IndexedBinding visit(UntargettedBinding<? extends Object> binding) {
+ return new Indexer.IndexedBinding(binding, BindingType.UNTARGETTED, scope(binding), null);
+ }
+
+ private static final Object EAGER_SINGLETON = new Object();
+
+ @Override
+ public Object visitEagerSingleton() {
+ return EAGER_SINGLETON;
+ }
+
+ @Override
+ public Object visitNoScoping() {
+ return Scopes.NO_SCOPE;
+ }
+
+ @Override
+ public Object visitScope(Scope scope) {
+ return scope;
+ }
+
+ @Override
+ public Object visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
+ return scopeAnnotation;
+ }
+}
diff --git a/core/src/com/google/inject/internal/InheritingState.java b/core/src/com/google/inject/internal/InheritingState.java
index 18363f48..7b739fca 100644
--- a/core/src/com/google/inject/internal/InheritingState.java
+++ b/core/src/com/google/inject/internal/InheritingState.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,25 +31,21 @@ import com.google.inject.spi.ProvisionListenerBinding;
import com.google.inject.spi.ScopeBinding;
import com.google.inject.spi.TypeConverterBinding;
import com.google.inject.spi.TypeListenerBinding;
-
import java.lang.annotation.Annotation;
-import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
-/**
- * @author jessewilson@google.com (Jesse Wilson)
- */
+/** @author jessewilson@google.com (Jesse Wilson) */
final class InheritingState implements State {
private final State parent;
// Must be a linked hashmap in order to preserve order of bindings in Modules.
private final Map<Key<?>, Binding<?>> explicitBindingsMutable = Maps.newLinkedHashMap();
- private final Map<Key<?>, Binding<?>> explicitBindings
- = Collections.unmodifiableMap(explicitBindingsMutable);
+ private final Map<Key<?>, Binding<?>> explicitBindings =
+ Collections.unmodifiableMap(explicitBindingsMutable);
private final Map<Class<? extends Annotation>, ScopeBinding> scopes = Maps.newHashMap();
private final List<TypeConverterBinding> converters = Lists.newArrayList();
/*if[AOP]*/
@@ -67,41 +63,50 @@ final class InheritingState implements State {
this.blacklistedKeys = new WeakKeySet(lock);
}
+ @Override
public State parent() {
return parent;
}
+ @Override
@SuppressWarnings("unchecked") // we only put in BindingImpls that match their key types
public <T> BindingImpl<T> getExplicitBinding(Key<T> key) {
Binding<?> binding = explicitBindings.get(key);
return binding != null ? (BindingImpl<T>) binding : parent.getExplicitBinding(key);
}
+ @Override
public Map<Key<?>, Binding<?>> getExplicitBindingsThisLevel() {
return explicitBindings;
}
+ @Override
public void putBinding(Key<?> key, BindingImpl<?> binding) {
explicitBindingsMutable.put(key, binding);
}
+ @Override
public ScopeBinding getScopeBinding(Class<? extends Annotation> annotationType) {
ScopeBinding scopeBinding = scopes.get(annotationType);
return scopeBinding != null ? scopeBinding : parent.getScopeBinding(annotationType);
}
+ @Override
public void putScopeBinding(Class<? extends Annotation> annotationType, ScopeBinding scope) {
scopes.put(annotationType, scope);
}
+ @Override
public Iterable<TypeConverterBinding> getConvertersThisLevel() {
return converters;
}
+ @Override
public void addConverter(TypeConverterBinding typeConverterBinding) {
converters.add(typeConverterBinding);
}
+ @Override
public TypeConverterBinding getConverter(
String stringValue, TypeLiteral<?> type, Errors errors, Object source) {
TypeConverterBinding matchingConverter = null;
@@ -119,10 +124,12 @@ final class InheritingState implements State {
}
/*if[AOP]*/
+ @Override
public void addMethodAspect(MethodAspect methodAspect) {
methodAspects.add(methodAspect);
}
+ @Override
public ImmutableList<MethodAspect> getMethodAspects() {
return new ImmutableList.Builder<MethodAspect>()
.addAll(parent.getMethodAspects())
@@ -131,10 +138,12 @@ final class InheritingState implements State {
}
/*end[AOP]*/
+ @Override
public void addTypeListener(TypeListenerBinding listenerBinding) {
typeListenerBindings.add(listenerBinding);
}
+ @Override
public List<TypeListenerBinding> getTypeListenerBindings() {
List<TypeListenerBinding> parentBindings = parent.getTypeListenerBindings();
List<TypeListenerBinding> result =
@@ -143,11 +152,13 @@ final class InheritingState implements State {
result.addAll(typeListenerBindings);
return result;
}
-
+
+ @Override
public void addProvisionListener(ProvisionListenerBinding listenerBinding) {
provisionListenerBindings.add(listenerBinding);
}
+ @Override
public List<ProvisionListenerBinding> getProvisionListenerBindings() {
List<ProvisionListenerBinding> parentBindings = parent.getProvisionListenerBindings();
List<ProvisionListenerBinding> result =
@@ -157,10 +168,12 @@ final class InheritingState implements State {
return result;
}
+ @Override
public void addScanner(ModuleAnnotatedMethodScannerBinding scanner) {
scannerBindings.add(scanner);
}
+ @Override
public List<ModuleAnnotatedMethodScannerBinding> getScannerBindings() {
List<ModuleAnnotatedMethodScannerBinding> parentBindings = parent.getScannerBindings();
List<ModuleAnnotatedMethodScannerBinding> result =
@@ -170,23 +183,28 @@ final class InheritingState implements State {
return result;
}
+ @Override
public void blacklist(Key<?> key, State state, Object source) {
parent.blacklist(key, state, source);
blacklistedKeys.add(key, state, source);
}
+ @Override
public boolean isBlacklisted(Key<?> key) {
return blacklistedKeys.contains(key);
}
-
+
+ @Override
public Set<Object> getSourcesForBlacklistedKey(Key<?> key) {
return blacklistedKeys.getSources(key);
}
+ @Override
public Object lock() {
return lock;
}
+ @Override
public Map<Class<? extends Annotation>, Scope> getScopes() {
ImmutableMap.Builder<Class<? extends Annotation>, Scope> builder = ImmutableMap.builder();
for (Map.Entry<Class<? extends Annotation>, ScopeBinding> entry : scopes.entrySet()) {
diff --git a/core/src/com/google/inject/internal/Initializable.java b/core/src/com/google/inject/internal/Initializable.java
index 855dd8cb..e3c9ed93 100644
--- a/core/src/com/google/inject/internal/Initializable.java
+++ b/core/src/com/google/inject/internal/Initializable.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,8 +23,6 @@ package com.google.inject.internal;
*/
interface Initializable<T> {
- /**
- * Ensures the reference is initialized, then returns it.
- */
- T get(Errors errors) throws ErrorsException;
+ /** Ensures the reference is initialized, then returns it. */
+ T get() throws InternalProvisionException;
}
diff --git a/core/src/com/google/inject/internal/Initializables.java b/core/src/com/google/inject/internal/Initializables.java
index 82e28687..36655f7d 100644
--- a/core/src/com/google/inject/internal/Initializables.java
+++ b/core/src/com/google/inject/internal/Initializables.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,21 +16,19 @@
package com.google.inject.internal;
-/**
- * @author jessewilson@google.com (Jesse Wilson)
- */
+/** @author jessewilson@google.com (Jesse Wilson) */
final class Initializables {
- /**
- * Returns an initializable for an instance that requires no initialization.
- */
+ /** Returns an initializable for an instance that requires no initialization. */
static <T> Initializable<T> of(final T instance) {
return new Initializable<T>() {
- public T get(Errors errors) throws ErrorsException {
+ @Override
+ public T get() {
return instance;
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return String.valueOf(instance);
}
};
diff --git a/core/src/com/google/inject/internal/Initializer.java b/core/src/com/google/inject/internal/Initializer.java
index ff83ea9b..2ab4b0fe 100644
--- a/core/src/com/google/inject/internal/Initializer.java
+++ b/core/src/com/google/inject/internal/Initializer.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,15 +21,16 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
import com.google.inject.Binding;
import com.google.inject.Key;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
+import com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory;
import com.google.inject.spi.InjectionPoint;
-
-import java.util.Map;
+import java.util.IdentityHashMap;
+import java.util.List;
import java.util.Set;
-import java.util.concurrent.CountDownLatch;
/**
* Manages and injects instances at injector-creation time. This is made more complicated by
@@ -39,46 +40,76 @@ import java.util.concurrent.CountDownLatch;
* @author jessewilson@google.com (Jesse Wilson)
*/
final class Initializer {
-
- /** the only thread that we'll use to inject members. */
- private final Thread creatingThread = Thread.currentThread();
-
- /** zero means everything is injected. */
- private final CountDownLatch ready = new CountDownLatch(1);
-
- /** Maps from instances that need injection to the MembersInjector that will inject them. */
- private final Map<Object, MembersInjectorImpl<?>> pendingMembersInjectors =
- Maps.newIdentityHashMap();
- /** Maps instances that need injection to a source that registered them */
- private final Map<Object, InjectableReference<?>> pendingInjection = Maps.newIdentityHashMap();
+ /** Is set to true once {@link #validateOustandingInjections} is called. */
+ private volatile boolean validationStarted = false;
+
+ /**
+ * Allows us to detect circular dependencies. It's only used during injectable reference
+ * initialization. After initialization direct access through volatile field is used.
+ */
+ private final CycleDetectingLockFactory<Class<?>> cycleDetectingLockFactory =
+ new CycleDetectingLockFactory<Class<?>>();
+
+ /**
+ * Instances that need injection during injector creation to a source that registered them. New
+ * references added before {@link #validateOustandingInjections}. Cleared up in {@link
+ * #injectAll}.
+ */
+ private final List<InjectableReference<?>> pendingInjections = Lists.newArrayList();
+
+ /**
+ * Map that guarantees that no instance would get two references. New references added before
+ * {@link #validateOustandingInjections}. Cleared up in {@link #validateOustandingInjections}.
+ */
+ private final IdentityHashMap<Object, InjectableReference<?>> initializablesCache =
+ Maps.newIdentityHashMap();
/**
* Registers an instance for member injection when that step is performed.
*
- * @param instance an instance that optionally has members to be injected (each annotated with
- * @Inject).
+ * @param instance an instance that optionally has members to be injected (each annotated
+ * with @Inject).
* @param binding the binding that caused this initializable to be created, if it exists.
* @param source the source location that this injection was requested
*/
- <T> Initializable<T> requestInjection(InjectorImpl injector, T instance, Binding<T> binding,
- Object source, Set<InjectionPoint> injectionPoints) {
+ <T> Initializable<T> requestInjection(
+ InjectorImpl injector,
+ T instance,
+ Binding<T> binding,
+ Object source,
+ Set<InjectionPoint> injectionPoints) {
checkNotNull(source);
-
+ Preconditions.checkState(
+ !validationStarted, "Member injection could not be requested after validation is started");
ProvisionListenerStackCallback<T> provisionCallback =
binding == null ? null : injector.provisionListenerStore.get(binding);
// short circuit if the object has no injections or listeners.
- if (instance == null || (injectionPoints.isEmpty()
- && !injector.membersInjectorStore.hasTypeListeners()
- && (provisionCallback == null || !provisionCallback.hasListeners()))) {
+ if (instance == null
+ || (injectionPoints.isEmpty()
+ && !injector.membersInjectorStore.hasTypeListeners()
+ && provisionCallback == null)) {
return Initializables.of(instance);
}
- InjectableReference<T> initializable = new InjectableReference<T>(
- injector, instance, binding == null ? null : binding.getKey(), provisionCallback, source);
- pendingInjection.put(instance, initializable);
- return initializable;
+ if (initializablesCache.containsKey(instance)) {
+ @SuppressWarnings("unchecked") // Map from T to InjectableReference<T>
+ Initializable<T> cached = (Initializable<T>) initializablesCache.get(instance);
+ return cached;
+ }
+
+ InjectableReference<T> injectableReference =
+ new InjectableReference<T>(
+ injector,
+ instance,
+ binding == null ? null : binding.getKey(),
+ provisionCallback,
+ source,
+ cycleDetectingLockFactory.create(instance.getClass()));
+ initializablesCache.put(instance, injectableReference);
+ pendingInjections.add(injectableReference);
+ return injectableReference;
}
/**
@@ -86,9 +117,11 @@ final class Initializer {
* on the injected instances.
*/
void validateOustandingInjections(Errors errors) {
- for (InjectableReference<?> reference : pendingInjection.values()) {
+ validationStarted = true;
+ initializablesCache.clear();
+ for (InjectableReference<?> reference : pendingInjections) {
try {
- pendingMembersInjectors.put(reference.instance, reference.validate(errors));
+ reference.validate(errors);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
}
@@ -101,88 +134,130 @@ final class Initializer {
* instances are codependent (directly or transitively), ordering of injection is arbitrary.
*/
void injectAll(final Errors errors) {
- // loop over a defensive copy since ensureInjected() mutates the set. Unfortunately, that copy
- // is made complicated by a bug in IBM's JDK, wherein entrySet().toArray(Object[]) doesn't work
- for (InjectableReference<?> reference : Lists.newArrayList(pendingInjection.values())) {
+ Preconditions.checkState(validationStarted, "Validation should be done before injection");
+ for (InjectableReference<?> reference : pendingInjections) {
try {
- reference.get(errors);
- } catch (ErrorsException e) {
- errors.merge(e.getErrors());
+ reference.get();
+ } catch (InternalProvisionException ipe) {
+ errors.merge(ipe);
}
}
+ pendingInjections.clear();
+ }
- if (!pendingInjection.isEmpty()) {
- throw new AssertionError("Failed to satisfy " + pendingInjection);
- }
-
- ready.countDown();
+ private enum InjectableReferenceState {
+ NEW,
+ VALIDATED,
+ INJECTING,
+ READY
}
- private class InjectableReference<T> implements Initializable<T> {
+ private static class InjectableReference<T> implements Initializable<T> {
+ private volatile InjectableReferenceState state = InjectableReferenceState.NEW;
+ private volatile MembersInjectorImpl<T> membersInjector = null;
+
private final InjectorImpl injector;
private final T instance;
private final Object source;
private final Key<T> key;
private final ProvisionListenerStackCallback<T> provisionCallback;
+ private final CycleDetectingLock<?> lock;
- public InjectableReference(InjectorImpl injector, T instance, Key<T> key,
- ProvisionListenerStackCallback<T> provisionCallback, Object source) {
+ public InjectableReference(
+ InjectorImpl injector,
+ T instance,
+ Key<T> key,
+ ProvisionListenerStackCallback<T> provisionCallback,
+ Object source,
+ CycleDetectingLock<?> lock) {
this.injector = injector;
this.key = key; // possibly null!
this.provisionCallback = provisionCallback; // possibly null!
this.instance = checkNotNull(instance, "instance");
this.source = checkNotNull(source, "source");
+ this.lock = checkNotNull(lock, "lock");
}
- public MembersInjectorImpl<T> validate(Errors errors) throws ErrorsException {
+ public void validate(Errors errors) throws ErrorsException {
@SuppressWarnings("unchecked") // the type of 'T' is a TypeLiteral<T>
- TypeLiteral<T> type = TypeLiteral.get((Class<T>) instance.getClass());
- return injector.membersInjectorStore.get(type, errors.withSource(source));
+ TypeLiteral<T> type = TypeLiteral.get((Class<T>) instance.getClass());
+ membersInjector = injector.membersInjectorStore.get(type, errors.withSource(source));
+ Preconditions.checkNotNull(
+ membersInjector,
+ "No membersInjector available for instance: %s, from key: %s",
+ instance,
+ key);
+ state = InjectableReferenceState.VALIDATED;
}
/**
* Reentrant. If {@code instance} was registered for injection at injector-creation time, this
* method will ensure that all its members have been injected before returning.
*/
- public T get(Errors errors) throws ErrorsException {
- if (ready.getCount() == 0) {
+ @Override
+ public T get() throws InternalProvisionException {
+ // skipping acquiring lock if initialization is already finished
+ if (state == InjectableReferenceState.READY) {
return instance;
}
- // just wait for everything to be injected by another thread
- if (Thread.currentThread() != creatingThread) {
- try {
- ready.await();
- return instance;
- } catch (InterruptedException e) {
- // Give up, since we don't know if our injection is ready
- throw new RuntimeException(e);
- }
+ // acquire lock for current binding to initialize an instance
+ Multimap<?, ?> lockCycle = lock.lockOrDetectPotentialLocksCycle();
+ if (!lockCycle.isEmpty()) {
+ // Potential deadlock detected and creation lock is not taken.
+ // According to injectAll()'s contract return non-initialized instance.
+
+ // This condition should not be possible under the current Guice implementation.
+ // This clause exists for defensive programming purposes.
+
+ // Reasoning:
+ // get() is called either directly from injectAll(), holds no locks and can not create
+ // a cycle, or it is called through a singleton scope, which resolves deadlocks by itself.
+ // Before calling get() object has to be requested for injection.
+ // Initializer.requestInjection() is called either for constant object bindings, which wrap
+ // creation into a Singleton scope, or from Binder.requestInjection(), which
+ // has to use Singleton scope to reuse the same InjectableReference to potentially
+ // create a lock cycle.
+ return instance;
}
+ try {
+ // lock acquired, current thread owns this instance initialization
+ switch (state) {
+ case READY:
+ return instance;
+ // When instance depends on itself in the same thread potential dead lock
+ // is not detected. We have to prevent a stack overflow and we use
+ // an "injecting" stage to short-circuit a call.
+ case INJECTING:
+ return instance;
+ case VALIDATED:
+ state = InjectableReferenceState.INJECTING;
+ break;
+ case NEW:
+ throw new IllegalStateException("InjectableReference is not validated yet");
+ default:
+ throw new IllegalStateException("Unknown state: " + state);
+ }
- // toInject needs injection, do it right away. we only do this once, even if it fails
- if (pendingInjection.remove(instance) != null) {
- // safe because we only insert a members injector for the appropriate instance
- @SuppressWarnings("unchecked")
- MembersInjectorImpl<T> membersInjector =
- (MembersInjectorImpl<T>)pendingMembersInjectors.remove(instance);
- Preconditions.checkState(membersInjector != null,
- "No membersInjector available for instance: %s, from key: %s", instance, key);
-
// if in Stage.TOOL, we only want to inject & notify toolable injection points.
// (otherwise we'll inject all of them)
- membersInjector.injectAndNotify(instance,
- errors.withSource(source),
- key,
- provisionCallback,
- source,
- injector.options.stage == Stage.TOOL);
+ try {
+ membersInjector.injectAndNotify(
+ instance, key, provisionCallback, source, injector.options.stage == Stage.TOOL);
+ } catch (InternalProvisionException ipe) {
+ throw ipe.addSource(source);
+ }
+ // mark instance as ready to skip a lock on subsequent calls
+ state = InjectableReferenceState.READY;
+ return instance;
+ } finally {
+ // always release our creation lock, even on failures
+ lock.unlock();
}
-
- return instance;
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return instance.toString();
}
}
diff --git a/core/src/com/google/inject/internal/InjectionRequestProcessor.java b/core/src/com/google/inject/internal/InjectionRequestProcessor.java
index 36ad261a..dce78e85 100644
--- a/core/src/com/google/inject/internal/InjectionRequestProcessor.java
+++ b/core/src/com/google/inject/internal/InjectionRequestProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@ import com.google.inject.Stage;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.InjectionRequest;
import com.google.inject.spi.StaticInjectionRequest;
-
import java.util.List;
import java.util.Set;
@@ -44,12 +43,14 @@ final class InjectionRequestProcessor extends AbstractProcessor {
this.initializer = initializer;
}
- @Override public Boolean visit(StaticInjectionRequest request) {
+ @Override
+ public Boolean visit(StaticInjectionRequest request) {
staticInjections.add(new StaticInjection(injector, request));
return true;
}
- @Override public Boolean visit(InjectionRequest<?> request) {
+ @Override
+ public Boolean visit(InjectionRequest<?> request) {
Set<InjectionPoint> injectionPoints;
try {
injectionPoints = request.getInjectionPoints();
@@ -103,31 +104,32 @@ final class InjectionRequestProcessor extends AbstractProcessor {
injectionPoints = e.getPartialValue();
}
if (injectionPoints != null) {
- memberInjectors = injector.membersInjectorStore.getInjectors(
- injectionPoints, errorsForMember);
+ memberInjectors =
+ injector.membersInjectorStore.getInjectors(injectionPoints, errorsForMember);
} else {
memberInjectors = ImmutableList.of();
}
-
+
errors.merge(errorsForMember);
}
void injectMembers() {
+ InternalContext context = injector.enterContext();
try {
- injector.callInContext(new ContextualCallable<Void>() {
- public Void call(InternalContext context) {
- for (SingleMemberInjector memberInjector : memberInjectors) {
- // Run injections if we're not in tool stage (ie, PRODUCTION or DEV),
- // or if we are in tool stage and the injection point is toolable.
- if(injector.options.stage != Stage.TOOL || memberInjector.getInjectionPoint().isToolable()) {
- memberInjector.inject(errors, context, null);
- }
+ boolean isStageTool = injector.options.stage == Stage.TOOL;
+ for (SingleMemberInjector memberInjector : memberInjectors) {
+ // Run injections if we're not in tool stage (ie, PRODUCTION or DEV),
+ // or if we are in tool stage and the injection point is toolable.
+ if (!isStageTool || memberInjector.getInjectionPoint().isToolable()) {
+ try {
+ memberInjector.inject(context, null);
+ } catch (InternalProvisionException e) {
+ errors.merge(e);
}
- return null;
}
- });
- } catch (ErrorsException e) {
- throw new AssertionError();
+ }
+ } finally {
+ context.close();
}
}
}
diff --git a/core/src/com/google/inject/internal/InjectorImpl.java b/core/src/com/google/inject/internal/InjectorImpl.java
index 54ce8a3c..321dbea2 100644
--- a/core/src/com/google/inject/internal/InjectorImpl.java
+++ b/core/src/com/google/inject/internal/InjectorImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,11 +16,13 @@
package com.google.inject.internal;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
+import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
+import com.google.common.collect.ListMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.inject.Binder;
@@ -33,7 +35,6 @@ import com.google.inject.MembersInjector;
import com.google.inject.Module;
import com.google.inject.ProvidedBy;
import com.google.inject.Provider;
-import com.google.inject.ProvisionException;
import com.google.inject.Scope;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
@@ -43,10 +44,10 @@ import com.google.inject.spi.ConvertedConstantBinding;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.InstanceBinding;
import com.google.inject.spi.ProviderBinding;
import com.google.inject.spi.TypeConverterBinding;
import com.google.inject.util.Providers;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
@@ -57,7 +58,6 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ConcurrentMap;
/**
* Default {@link Injector} implementation.
@@ -75,8 +75,12 @@ final class InjectorImpl implements Injector, Lookups {
final boolean atInjectRequired;
final boolean exactBindingAnnotationsRequired;
- InjectorOptions(Stage stage, boolean jitDisabled, boolean disableCircularProxies,
- boolean atInjectRequired, boolean exactBindingAnnotationsRequired) {
+ InjectorOptions(
+ Stage stage,
+ boolean jitDisabled,
+ boolean disableCircularProxies,
+ boolean atInjectRequired,
+ boolean exactBindingAnnotationsRequired) {
this.stage = stage;
this.jitDisabled = jitDisabled;
this.disableCircularProxies = disableCircularProxies;
@@ -86,7 +90,7 @@ final class InjectorImpl implements Injector, Lookups {
@Override
public String toString() {
- return Objects.toStringHelper(getClass())
+ return MoreObjects.toStringHelper(getClass())
.add("stage", stage)
.add("jitDisabled", jitDisabled)
.add("disableCircularProxies", disableCircularProxies)
@@ -108,14 +112,14 @@ final class InjectorImpl implements Injector, Lookups {
final State state;
final InjectorImpl parent;
- final BindingsMultimap bindingsMultimap = new BindingsMultimap();
+ final ListMultimap<TypeLiteral<?>, Binding<?>> bindingsMultimap = ArrayListMultimap.create();
final InjectorOptions options;
/** Just-in-time binding cache. Guarded by state.lock() */
final Map<Key<?>, BindingImpl<?>> jitBindings = Maps.newHashMap();
/**
- * Cache of Keys that we were unable to create JIT bindings for, so we don't
- * keep trying. Also guarded by state.lock().
+ * Cache of Keys that we were unable to create JIT bindings for, so we don't keep trying. Also
+ * guarded by state.lock().
*/
final Set<Key<?>> failedJitBindings = Sets.newHashSet();
@@ -129,26 +133,29 @@ final class InjectorImpl implements Injector, Lookups {
if (parent != null) {
localContext = parent.localContext;
} else {
- localContext = new ThreadLocal<Object[]>();
+ // No ThreadLocal.initialValue(), as that would cause classloader leaks. See
+ // https://github.com/google/guice/issues/288#issuecomment-48216933,
+ // https://github.com/google/guice/issues/288#issuecomment-48216944
+ localContext = new ThreadLocal<>();
}
}
/** Indexes bindings by type. */
void index() {
for (Binding<?> binding : state.getExplicitBindingsThisLevel().values()) {
- index(binding);
+ bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding);
}
}
- <T> void index(Binding<T> binding) {
- bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding);
- }
-
+ @Override
public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) {
- return bindingsMultimap.getAll(type);
+ @SuppressWarnings("unchecked") // safe because we only put matching entries into the map
+ List<Binding<T>> list = (List<Binding<T>>) (List) bindingsMultimap.get(type);
+ return Collections.unmodifiableList(list);
}
/** Returns the binding for {@code key} */
+ @Override
public <T> BindingImpl<T> getBinding(Key<T> key) {
Errors errors = new Errors(key);
try {
@@ -160,6 +167,7 @@ final class InjectorImpl implements Injector, Lookups {
}
}
+ @Override
public <T> BindingImpl<T> getExistingBinding(Key<T> key) {
// Check explicit bindings, i.e. bindings created by modules.
BindingImpl<T> explicitBinding = state.getExplicitBinding(key);
@@ -171,7 +179,7 @@ final class InjectorImpl implements Injector, Lookups {
for (InjectorImpl injector = this; injector != null; injector = injector.parent) {
@SuppressWarnings("unchecked")
BindingImpl<T> jitBinding = (BindingImpl<T>) injector.jitBindings.get(key);
- if(jitBinding != null) {
+ if (jitBinding != null) {
return jitBinding;
}
}
@@ -179,15 +187,15 @@ final class InjectorImpl implements Injector, Lookups {
// If Key is a Provider, we have to see if the type it is providing exists,
// and, if so, we have to create the binding for the provider.
- if(isProvider(key)) {
+ if (isProvider(key)) {
try {
// This is safe because isProvider above ensures that T is a Provider<?>
@SuppressWarnings({"unchecked", "cast"})
- Key<?> providedKey = (Key<?>)getProvidedKey((Key)key, new Errors());
- if(getExistingBinding(providedKey) != null) {
+ Key<?> providedKey = (Key<?>) getProvidedKey((Key) key, new Errors());
+ if (getExistingBinding(providedKey) != null) {
return getBinding(key);
}
- } catch(ErrorsException e) {
+ } catch (ErrorsException e) {
throw new ConfigurationException(e.getErrors().getMessages());
}
}
@@ -197,8 +205,8 @@ final class InjectorImpl implements Injector, Lookups {
}
/**
- * Gets a binding implementation. First, it check to see if the parent has a binding. If the
- * parent has a binding and the binding is scoped, it will use that binding. Otherwise, this
+ * Gets a binding implementation. First, it check to see if the parent has a binding. If the
+ * parent has a binding and the binding is scoped, it will use that binding. Otherwise, this
* checks for an explicit binding. If no explicit binding is found, it looks for a just-in-time
* binding.
*/
@@ -214,21 +222,22 @@ final class InjectorImpl implements Injector, Lookups {
return getJustInTimeBinding(key, errors, jitType);
}
+ @Override
public <T> Binding<T> getBinding(Class<T> type) {
return getBinding(Key.get(type));
}
+ @Override
public Injector getParent() {
return parent;
}
+ @Override
public Injector createChildInjector(Iterable<? extends Module> modules) {
- return new InternalInjectorCreator()
- .parentInjector(this)
- .addModules(modules)
- .build();
+ return new InternalInjectorCreator().parentInjector(this).addModules(modules).build();
}
+ @Override
public Injector createChildInjector(Module... modules) {
return createChildInjector(ImmutableList.copyOf(modules));
}
@@ -292,7 +301,8 @@ final class InjectorImpl implements Injector, Lookups {
return key.getTypeLiteral().getRawType().equals(TypeLiteral.class);
}
- private static <T> Key<T> getProvidedKey(Key<Provider<T>> key, Errors errors) throws ErrorsException {
+ private static <T> Key<T> getProvidedKey(Key<Provider<T>> key, Errors errors)
+ throws ErrorsException {
Type providerType = key.getTypeLiteral().getType();
// If the Provider has no type parameter (raw Provider)...
@@ -321,21 +331,26 @@ final class InjectorImpl implements Injector, Lookups {
}
@SuppressWarnings("unchecked") // safe because T came from Key<MembersInjector<T>>
- TypeLiteral<T> instanceType = (TypeLiteral<T>) TypeLiteral.get(
- ((ParameterizedType) membersInjectorType).getActualTypeArguments()[0]);
+ TypeLiteral<T> instanceType =
+ (TypeLiteral<T>)
+ TypeLiteral.get(((ParameterizedType) membersInjectorType).getActualTypeArguments()[0]);
MembersInjector<T> membersInjector = membersInjectorStore.get(instanceType, errors);
- InternalFactory<MembersInjector<T>> factory = new ConstantFactory<MembersInjector<T>>(
- Initializables.of(membersInjector));
-
+ InternalFactory<MembersInjector<T>> factory =
+ new ConstantFactory<MembersInjector<T>>(Initializables.of(membersInjector));
- return new InstanceBindingImpl<MembersInjector<T>>(this, key, SourceProvider.UNKNOWN_SOURCE,
- factory, ImmutableSet.<InjectionPoint>of(), membersInjector);
+ return new InstanceBindingImpl<MembersInjector<T>>(
+ this,
+ key,
+ SourceProvider.UNKNOWN_SOURCE,
+ factory,
+ ImmutableSet.<InjectionPoint>of(),
+ membersInjector);
}
/**
- * Creates a synthetic binding to {@code Provider<T>}, i.e. a binding to the provider from
- * {@code Binding<T>}.
+ * Creates a synthetic binding to {@code Provider<T>}, i.e. a binding to the provider from {@code
+ * Binding<T>}.
*/
private <T> BindingImpl<Provider<T>> createProviderBinding(Key<Provider<T>> key, Errors errors)
throws ErrorsException {
@@ -349,7 +364,11 @@ final class InjectorImpl implements Injector, Lookups {
final BindingImpl<T> providedBinding;
ProviderBindingImpl(InjectorImpl injector, Key<Provider<T>> key, Binding<T> providedBinding) {
- super(injector, key, providedBinding.getSource(), createInternalFactory(providedBinding),
+ super(
+ injector,
+ key,
+ providedBinding.getSource(),
+ createInternalFactory(providedBinding),
Scoping.UNSCOPED);
this.providedBinding = (BindingImpl<T>) providedBinding;
}
@@ -357,42 +376,48 @@ final class InjectorImpl implements Injector, Lookups {
static <T> InternalFactory<Provider<T>> createInternalFactory(Binding<T> providedBinding) {
final Provider<T> provider = providedBinding.getProvider();
return new InternalFactory<Provider<T>>() {
- public Provider<T> get(Errors errors, InternalContext context, Dependency dependency, boolean linked) {
+ @Override
+ public Provider<T> get(InternalContext context, Dependency<?> dependency, boolean linked) {
return provider;
}
};
}
+ @Override
public Key<? extends T> getProvidedKey() {
return providedBinding.getKey();
}
+ @Override
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super Provider<T>, V> visitor) {
return visitor.visit(this);
}
+ @Override
public void applyTo(Binder binder) {
throw new UnsupportedOperationException("This element represents a synthetic binding.");
}
- @Override public String toString() {
- return Objects.toStringHelper(ProviderBinding.class)
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(ProviderBinding.class)
.add("key", getKey())
.add("providedKey", getProvidedKey())
.toString();
}
+ @Override
public Set<Dependency<?>> getDependencies() {
return ImmutableSet.<Dependency<?>>of(Dependency.get(getProvidedKey()));
}
@Override
public boolean equals(Object obj) {
- if(obj instanceof ProviderBindingImpl) {
- ProviderBindingImpl<?> o = (ProviderBindingImpl<?>)obj;
+ if (obj instanceof ProviderBindingImpl) {
+ ProviderBindingImpl<?> o = (ProviderBindingImpl<?>) obj;
return getKey().equals(o.getKey())
- && getScoping().equals(o.getScoping())
- && Objects.equal(providedBinding, o.providedBinding);
+ && getScoping().equals(o.getScoping())
+ && Objects.equal(providedBinding, o.providedBinding);
} else {
return false;
}
@@ -419,12 +444,17 @@ final class InjectorImpl implements Injector, Lookups {
return null;
}
- String stringValue = stringBinding.getProvider().get();
+ // We can't call getProvider().get() because this InstanceBinding may not have been inintialized
+ // yet (because we may have been called during InternalInjectorCreator.initializeStatically and
+ // instance binding validation hasn't happened yet.)
+ @SuppressWarnings("unchecked")
+ String stringValue = ((InstanceBinding<String>) stringBinding).getInstance();
Object source = stringBinding.getSource();
// Find a matching type converter.
TypeLiteral<T> type = key.getTypeLiteral();
- TypeConverterBinding typeConverterBinding = state.getConverter(stringValue, type, errors, source);
+ TypeConverterBinding typeConverterBinding =
+ state.getConverter(stringValue, type, errors, source);
if (typeConverterBinding == null) {
// No converter can handle the given type.
@@ -437,73 +467,91 @@ final class InjectorImpl implements Injector, Lookups {
T converted = (T) typeConverterBinding.getTypeConverter().convert(stringValue, type);
if (converted == null) {
- throw errors.converterReturnedNull(stringValue, source, type, typeConverterBinding)
+ throw errors
+ .converterReturnedNull(stringValue, source, type, typeConverterBinding)
.toException();
}
if (!type.getRawType().isInstance(converted)) {
- throw errors.conversionTypeError(stringValue, source, type, typeConverterBinding, converted)
+ throw errors
+ .conversionTypeError(stringValue, source, type, typeConverterBinding, converted)
.toException();
}
- return new ConvertedConstantBindingImpl<T>(this, key, converted, stringBinding,
- typeConverterBinding);
+ return new ConvertedConstantBindingImpl<T>(
+ this, key, converted, stringBinding, typeConverterBinding);
} catch (ErrorsException e) {
throw e;
} catch (RuntimeException e) {
- throw errors.conversionError(stringValue, source, type, typeConverterBinding, e)
+ throw errors
+ .conversionError(stringValue, source, type, typeConverterBinding, e)
.toException();
}
}
- private static class ConvertedConstantBindingImpl<T>
- extends BindingImpl<T> implements ConvertedConstantBinding<T> {
+ private static class ConvertedConstantBindingImpl<T> extends BindingImpl<T>
+ implements ConvertedConstantBinding<T> {
final T value;
final Provider<T> provider;
final Binding<String> originalBinding;
final TypeConverterBinding typeConverterBinding;
ConvertedConstantBindingImpl(
- InjectorImpl injector, Key<T> key, T value, Binding<String> originalBinding,
+ InjectorImpl injector,
+ Key<T> key,
+ T value,
+ Binding<String> originalBinding,
TypeConverterBinding typeConverterBinding) {
- super(injector, key, originalBinding.getSource(),
- new ConstantFactory<T>(Initializables.of(value)), Scoping.UNSCOPED);
+ super(
+ injector,
+ key,
+ originalBinding.getSource(),
+ new ConstantFactory<T>(Initializables.of(value)),
+ Scoping.UNSCOPED);
this.value = value;
provider = Providers.of(value);
this.originalBinding = originalBinding;
this.typeConverterBinding = typeConverterBinding;
}
- @Override public Provider<T> getProvider() {
+ @Override
+ public Provider<T> getProvider() {
return provider;
}
+ @Override
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
return visitor.visit(this);
}
+ @Override
public T getValue() {
return value;
}
+ @Override
public TypeConverterBinding getTypeConverterBinding() {
return typeConverterBinding;
}
+ @Override
public Key<String> getSourceKey() {
return originalBinding.getKey();
}
+ @Override
public Set<Dependency<?>> getDependencies() {
return ImmutableSet.<Dependency<?>>of(Dependency.get(getSourceKey()));
}
+ @Override
public void applyTo(Binder binder) {
throw new UnsupportedOperationException("This element represents a synthetic binding.");
}
- @Override public String toString() {
- return Objects.toStringHelper(ConvertedConstantBinding.class)
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(ConvertedConstantBinding.class)
.add("key", getKey())
.add("sourceKey", getSourceKey())
.add("value", value)
@@ -512,11 +560,11 @@ final class InjectorImpl implements Injector, Lookups {
@Override
public boolean equals(Object obj) {
- if(obj instanceof ConvertedConstantBindingImpl) {
- ConvertedConstantBindingImpl<?> o = (ConvertedConstantBindingImpl<?>)obj;
+ if (obj instanceof ConvertedConstantBindingImpl) {
+ ConvertedConstantBindingImpl<?> o = (ConvertedConstantBindingImpl<?>) obj;
return getKey().equals(o.getKey())
- && getScoping().equals(o.getScoping())
- && Objects.equal(value, o.value);
+ && getScoping().equals(o.getScoping())
+ && Objects.equal(value, o.value);
} else {
return false;
}
@@ -542,7 +590,7 @@ final class InjectorImpl implements Injector, Lookups {
Key<T> key = binding.getKey();
jitBindings.put(key, binding);
boolean successful = false;
- DelayedInitialize delayed = (DelayedInitialize)binding;
+ DelayedInitialize delayed = (DelayedInitialize) binding;
try {
delayed.initialize(this, errors);
successful = true;
@@ -560,32 +608,32 @@ final class InjectorImpl implements Injector, Lookups {
/**
* Iterates through the binding's dependencies to clean up any stray bindings that were leftover
- * from a failed JIT binding. This is required because the bindings are eagerly &
- * optimistically added to allow circular dependency support, so dependencies may pass where they
- * should have failed.
+ * from a failed JIT binding. This is required because the bindings are eagerly & optimistically
+ * added to allow circular dependency support, so dependencies may pass where they should have
+ * failed.
*/
private boolean cleanup(BindingImpl<?> binding, Set<Key> encountered) {
boolean bindingFailed = false;
Set<Dependency<?>> deps = getInternalDependencies(binding);
- for(Dependency dep : deps) {
+ for (Dependency dep : deps) {
Key<?> depKey = dep.getKey();
InjectionPoint ip = dep.getInjectionPoint();
- if(encountered.add(depKey)) { // only check if we haven't looked at this key yet
+ if (encountered.add(depKey)) { // only check if we haven't looked at this key yet
BindingImpl depBinding = jitBindings.get(depKey);
- if(depBinding != null) { // if the binding still exists, validate
+ if (depBinding != null) { // if the binding still exists, validate
boolean failed = cleanup(depBinding, encountered); // if children fail, we fail
- if(depBinding instanceof ConstructorBindingImpl) {
- ConstructorBindingImpl ctorBinding = (ConstructorBindingImpl)depBinding;
+ if (depBinding instanceof ConstructorBindingImpl) {
+ ConstructorBindingImpl ctorBinding = (ConstructorBindingImpl) depBinding;
ip = ctorBinding.getInternalConstructor();
- if(!ctorBinding.isInitialized()) {
+ if (!ctorBinding.isInitialized()) {
failed = true;
}
}
- if(failed) {
+ if (failed) {
removeFailedJitBinding(depBinding, ip);
bindingFailed = true;
}
- } else if(state.getExplicitBinding(depKey) == null) {
+ } else if (state.getExplicitBinding(depKey) == null) {
// ignore keys if they were explicitly bound, but if neither JIT
// nor explicit, it's also invalid & should let parent know.
bindingFailed = true;
@@ -601,7 +649,7 @@ final class InjectorImpl implements Injector, Lookups {
jitBindings.remove(binding.getKey());
membersInjectorStore.remove(binding.getKey().getTypeLiteral());
provisionListenerStore.remove(binding);
- if(ip != null) {
+ if (ip != null) {
constructors.remove(ip);
}
}
@@ -609,10 +657,10 @@ final class InjectorImpl implements Injector, Lookups {
/** Safely gets the dependencies of possibly not initialized bindings. */
@SuppressWarnings("unchecked")
private Set<Dependency<?>> getInternalDependencies(BindingImpl<?> binding) {
- if(binding instanceof ConstructorBindingImpl) {
- return ((ConstructorBindingImpl)binding).getInternalDependencies();
- } else if(binding instanceof HasDependencies) {
- return ((HasDependencies)binding).getDependencies();
+ if (binding instanceof ConstructorBindingImpl) {
+ return ((ConstructorBindingImpl) binding).getInternalDependencies();
+ } else if (binding instanceof HasDependencies) {
+ return ((HasDependencies) binding).getDependencies();
} else {
return ImmutableSet.of();
}
@@ -622,22 +670,23 @@ final class InjectorImpl implements Injector, Lookups {
* Creates a binding for an injectable type with the given scope. Looks for a scope on the type if
* none is specified.
*/
- <T> BindingImpl<T> createUninitializedBinding(Key<T> key, Scoping scoping, Object source,
- Errors errors, boolean jitBinding) throws ErrorsException {
+ <T> BindingImpl<T> createUninitializedBinding(
+ Key<T> key, Scoping scoping, Object source, Errors errors, boolean jitBinding)
+ throws ErrorsException {
Class<?> rawType = key.getTypeLiteral().getRawType();
ImplementedBy implementedBy = rawType.getAnnotation(ImplementedBy.class);
// Don't try to inject arrays or enums annotated with @ImplementedBy.
if (rawType.isArray() || (rawType.isEnum() && implementedBy != null)) {
- throw errors.missingImplementation(key).toException();
+ throw errors.missingImplementationWithHint(key, this).toException();
}
// Handle TypeLiteral<T> by binding the inner type
if (rawType == TypeLiteral.class) {
@SuppressWarnings("unchecked") // we have to fudge the inner type as Object
- BindingImpl<T> binding = (BindingImpl<T>) createTypeLiteralBinding(
- (Key<TypeLiteral<Object>>) key, errors);
+ BindingImpl<T> binding =
+ (BindingImpl<T>) createTypeLiteralBinding((Key<TypeLiteral<Object>>) key, errors);
return binding;
}
@@ -654,8 +703,8 @@ final class InjectorImpl implements Injector, Lookups {
return createProvidedByBinding(key, scoping, providedBy, errors);
}
-
- return ConstructorBindingImpl.create(this,
+ return ConstructorBindingImpl.create(
+ this,
key,
null, /* use default constructor */
source,
@@ -689,17 +738,22 @@ final class InjectorImpl implements Injector, Lookups {
@SuppressWarnings("unchecked") // by definition, innerType == T, so this is safe
TypeLiteral<T> value = (TypeLiteral<T>) TypeLiteral.get(innerType);
- InternalFactory<TypeLiteral<T>> factory = new ConstantFactory<TypeLiteral<T>>(
- Initializables.of(value));
- return new InstanceBindingImpl<TypeLiteral<T>>(this, key, SourceProvider.UNKNOWN_SOURCE,
- factory, ImmutableSet.<InjectionPoint>of(), value);
+ InternalFactory<TypeLiteral<T>> factory =
+ new ConstantFactory<TypeLiteral<T>>(Initializables.of(value));
+ return new InstanceBindingImpl<TypeLiteral<T>>(
+ this,
+ key,
+ SourceProvider.UNKNOWN_SOURCE,
+ factory,
+ ImmutableSet.<InjectionPoint>of(),
+ value);
}
/** Creates a binding for a type annotated with @ProvidedBy. */
- <T> BindingImpl<T> createProvidedByBinding(Key<T> key, Scoping scoping,
- ProvidedBy providedBy, Errors errors) throws ErrorsException {
+ <T> BindingImpl<T> createProvidedByBinding(
+ Key<T> key, Scoping scoping, ProvidedBy providedBy, Errors errors) throws ErrorsException {
Class<?> rawType = key.getTypeLiteral().getRawType();
- Class<? extends Provider<?>> providerType = providedBy.value();
+ Class<? extends javax.inject.Provider<?>> providerType = providedBy.value();
// Make sure it's not the same type. TODO: Can we check for deeper loops?
if (providerType == rawType) {
@@ -712,21 +766,22 @@ final class InjectorImpl implements Injector, Lookups {
ProvidedByInternalFactory<T> internalFactory =
new ProvidedByInternalFactory<T>(rawType, providerType, providerKey);
Object source = rawType;
- BindingImpl<T> binding = LinkedProviderBindingImpl.createWithInitializer(
- this,
- key,
- source,
- Scoping.<T>scope(key, this, internalFactory, source, scoping),
- scoping,
- providerKey,
- internalFactory);
+ BindingImpl<T> binding =
+ LinkedProviderBindingImpl.createWithInitializer(
+ this,
+ key,
+ source,
+ Scoping.<T>scope(key, this, internalFactory, source, scoping),
+ scoping,
+ providerKey,
+ internalFactory);
internalFactory.setProvisionListenerCallback(provisionListenerStore.get(binding));
return binding;
}
/** Creates a binding for a type annotated with @ImplementedBy. */
- private <T> BindingImpl<T> createImplementedByBinding(Key<T> key, Scoping scoping,
- ImplementedBy implementedBy, Errors errors)
+ private <T> BindingImpl<T> createImplementedByBinding(
+ Key<T> key, Scoping scoping, ImplementedBy implementedBy, Errors errors)
throws ErrorsException {
Class<?> rawType = key.getTypeLiteral().getRawType();
Class<?> implementationType = implementedBy.value();
@@ -746,27 +801,14 @@ final class InjectorImpl implements Injector, Lookups {
// Look up the target binding.
final Key<? extends T> targetKey = Key.get(subclass);
- final BindingImpl<? extends T> targetBinding = getBindingOrThrow(targetKey, errors, JitLimitation.NEW_OR_EXISTING_JIT);
-
- InternalFactory<T> internalFactory = new InternalFactory<T>() {
- public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
- throws ErrorsException {
- context.pushState(targetKey, targetBinding.getSource());
- try {
- return targetBinding.getInternalFactory().get(
- errors.withSource(targetKey), context, dependency, true);
- } finally {
- context.popState();
- }
- }
- };
-
Object source = rawType;
+ FactoryProxy<T> factory = new FactoryProxy<>(this, key, targetKey, source);
+ factory.notify(errors); // causes the factory to initialize itself internally
return new LinkedBindingImpl<T>(
this,
key,
source,
- Scoping.<T>scope(key, this, internalFactory, source, scoping),
+ Scoping.<T>scope(key, this, factory, source, scoping),
scoping,
targetKey);
}
@@ -775,18 +817,23 @@ final class InjectorImpl implements Injector, Lookups {
* Attempts to create a just-in-time binding for {@code key} in the root injector, falling back to
* other ancestor injectors until this injector is tried.
*/
- private <T> BindingImpl<T> createJustInTimeBindingRecursive(Key<T> key, Errors errors,
- boolean jitDisabled, JitLimitation jitType) throws ErrorsException {
+ private <T> BindingImpl<T> createJustInTimeBindingRecursive(
+ Key<T> key, Errors errors, boolean jitDisabled, JitLimitation jitType)
+ throws ErrorsException {
// ask the parent to create the JIT binding
if (parent != null) {
if (jitType == JitLimitation.NEW_OR_EXISTING_JIT
- && jitDisabled && !parent.options.jitDisabled) {
+ && jitDisabled
+ && !parent.options.jitDisabled) {
// If the binding would be forbidden here but allowed in a parent, report an error instead
throw errors.jitDisabledInParent(key).toException();
}
try {
- return parent.createJustInTimeBindingRecursive(key, new Errors(), jitDisabled,
+ return parent.createJustInTimeBindingRecursive(
+ key,
+ new Errors(),
+ jitDisabled,
parent.options.jitDisabled ? JitLimitation.NO_JIT : jitType);
} catch (ErrorsException ignored) {
}
@@ -811,18 +858,20 @@ final class InjectorImpl implements Injector, Lookups {
/**
* Returns a new just-in-time binding created by resolving {@code key}. The strategies used to
* create just-in-time bindings are:
+ *
* <ol>
- * <li>Internalizing Providers. If the requested binding is for {@code Provider<T>}, we delegate
+ * <li>Internalizing Providers. If the requested binding is for {@code Provider<T>}, we delegate
* to the binding for {@code T}.
- * <li>Converting constants.
- * <li>ImplementedBy and ProvidedBy annotations. Only for unannotated keys.
- * <li>The constructor of the raw type. Only for unannotated keys.
+ * <li>Converting constants.
+ * <li>ImplementedBy and ProvidedBy annotations. Only for unannotated keys.
+ * <li>The constructor of the raw type. Only for unannotated keys.
* </ol>
*
* @throws com.google.inject.internal.ErrorsException if the binding cannot be created.
*/
- private <T> BindingImpl<T> createJustInTimeBinding(Key<T> key, Errors errors,
- boolean jitDisabled, JitLimitation jitType) throws ErrorsException {
+ private <T> BindingImpl<T> createJustInTimeBinding(
+ Key<T> key, Errors errors, boolean jitDisabled, JitLimitation jitType)
+ throws ErrorsException {
int numErrorsBefore = errors.size();
// Retrieve the sources before checking for blacklisting to guard against sources becoming null
@@ -858,9 +907,7 @@ final class InjectorImpl implements Injector, Lookups {
return convertedBinding;
}
- if (!isTypeLiteral(key)
- && jitDisabled
- && jitType != JitLimitation.NEW_OR_EXISTING_JIT) {
+ if (!isTypeLiteral(key) && jitDisabled && jitType != JitLimitation.NEW_OR_EXISTING_JIT) {
throw errors.jitDisabled(key).toException();
}
@@ -875,25 +922,28 @@ final class InjectorImpl implements Injector, Lookups {
// throw with a more appropriate message below
}
}
- throw errors.missingImplementation(key).toException();
+ throw errors.missingImplementationWithHint(key, this).toException();
}
Object source = key.getTypeLiteral().getRawType();
- BindingImpl<T> binding = createUninitializedBinding(key, Scoping.UNSCOPED, source, errors, true);
+ BindingImpl<T> binding =
+ createUninitializedBinding(key, Scoping.UNSCOPED, source, errors, true);
errors.throwIfNewErrors(numErrorsBefore);
initializeJitBinding(binding, errors);
return binding;
}
- <T> InternalFactory<? extends T> getInternalFactory(Key<T> key, Errors errors, JitLimitation jitType)
- throws ErrorsException {
+ <T> InternalFactory<? extends T> getInternalFactory(
+ Key<T> key, Errors errors, JitLimitation jitType) throws ErrorsException {
return getBindingOrThrow(key, errors, jitType).getInternalFactory();
}
+ @Override
public Map<Key<?>, Binding<?>> getBindings() {
return state.getExplicitBindingsThisLevel();
}
+ @Override
public Map<Key<?>, Binding<?>> getAllBindings() {
synchronized (state.lock()) {
return new ImmutableMap.Builder<Key<?>, Binding<?>>()
@@ -903,41 +953,19 @@ final class InjectorImpl implements Injector, Lookups {
}
}
+ @Override
public Map<Class<? extends Annotation>, Scope> getScopeBindings() {
return ImmutableMap.copyOf(state.getScopes());
}
+ @Override
public Set<TypeConverterBinding> getTypeConverterBindings() {
return ImmutableSet.copyOf(state.getConvertersThisLevel());
}
- private static class BindingsMultimap {
- final Map<TypeLiteral<?>, List<Binding<?>>> multimap = Maps.newHashMap();
-
- <T> void put(TypeLiteral<T> type, Binding<T> binding) {
- List<Binding<?>> bindingsForType = multimap.get(type);
- if (bindingsForType == null) {
- bindingsForType = Lists.newArrayList();
- multimap.put(type, bindingsForType);
- }
- bindingsForType.add(binding);
- }
-
-
- @SuppressWarnings("unchecked") // safe because we only put matching entries into the map
- <T> List<Binding<T>> getAll(TypeLiteral<T> type) {
- List<Binding<?>> bindings = multimap.get(type);
- return bindings != null
- ? Collections.<Binding<T>>unmodifiableList((List) multimap.get(type))
- : ImmutableList.<Binding<T>>of();
- }
- }
-
- /**
- * Returns parameter injectors, or {@code null} if there are no parameters.
- */
- SingleParameterInjector<?>[] getParametersInjectors(
- List<Dependency<?>> parameters, Errors errors) throws ErrorsException {
+ /** Returns parameter injectors, or {@code null} if there are no parameters. */
+ SingleParameterInjector<?>[] getParametersInjectors(List<Dependency<?>> parameters, Errors errors)
+ throws ErrorsException {
if (parameters.isEmpty()) {
return null;
}
@@ -957,9 +985,10 @@ final class InjectorImpl implements Injector, Lookups {
return result;
}
- <T> SingleParameterInjector<T> createParameterInjector(final Dependency<T> dependency,
- final Errors errors) throws ErrorsException {
- BindingImpl<? extends T> binding = getBindingOrThrow(dependency.getKey(), errors, JitLimitation.NO_JIT);
+ <T> SingleParameterInjector<T> createParameterInjector(
+ final Dependency<T> dependency, final Errors errors) throws ErrorsException {
+ BindingImpl<? extends T> binding =
+ getBindingOrThrow(dependency.getKey(), errors, JitLimitation.NO_JIT);
return new SingleParameterInjector<T>(dependency, binding);
}
@@ -978,12 +1007,14 @@ final class InjectorImpl implements Injector, Lookups {
/** Cached provision listener callbacks for each key. */
ProvisionListenerCallbackStore provisionListenerStore;
+ @Override
@SuppressWarnings("unchecked") // the members injector type is consistent with instance's type
public void injectMembers(Object instance) {
MembersInjector membersInjector = getMembersInjector(instance.getClass());
membersInjector.injectMembers(instance);
}
+ @Override
public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
Errors errors = new Errors(typeLiteral);
try {
@@ -993,45 +1024,47 @@ final class InjectorImpl implements Injector, Lookups {
}
}
+ @Override
public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
return getMembersInjector(TypeLiteral.get(type));
}
+ @Override
public <T> Provider<T> getProvider(Class<T> type) {
return getProvider(Key.get(type));
}
- <T> Provider<T> getProviderOrThrow(final Dependency<T> dependency, Errors errors) throws ErrorsException {
- final Key<T> key = dependency.getKey();
- final BindingImpl<? extends T> binding = getBindingOrThrow(key, errors, JitLimitation.NO_JIT);
+ <T> Provider<T> getProviderOrThrow(final Dependency<T> dependency, Errors errors)
+ throws ErrorsException {
+ Key<T> key = dependency.getKey();
+ BindingImpl<? extends T> binding = getBindingOrThrow(key, errors, JitLimitation.NO_JIT);
+ final InternalFactory<? extends T> internalFactory = binding.getInternalFactory();
+ final Object source = binding.getSource();
return new Provider<T>() {
+ @Override
public T get() {
- final Errors errors = new Errors(dependency);
+ InternalContext currentContext = enterContext();
+ Dependency previous = currentContext.pushDependency(dependency, source);
try {
- T t = callInContext(new ContextualCallable<T>() {
- public T call(InternalContext context) throws ErrorsException {
- Dependency previous = context.pushDependency(dependency, binding.getSource());
- try {
- return binding.getInternalFactory().get(errors, context, dependency, false);
- } finally {
- context.popStateAndSetDependency(previous);
- }
- }
- });
- errors.throwIfNewErrors(0);
+ T t = internalFactory.get(currentContext, dependency, false);
return t;
- } catch (ErrorsException e) {
- throw new ProvisionException(errors.merge(e.getErrors()).getMessages());
+ } catch (InternalProvisionException e) {
+ throw e.addSource(dependency).toProvisionException();
+ } finally {
+ currentContext.popStateAndSetDependency(previous);
+ currentContext.close();
}
}
- @Override public String toString() {
- return binding.getInternalFactory().toString();
+ @Override
+ public String toString() {
+ return internalFactory.toString();
}
};
}
+ @Override
public <T> Provider<T> getProvider(final Key<T> key) {
Errors errors = new Errors(key);
try {
@@ -1043,77 +1076,68 @@ final class InjectorImpl implements Injector, Lookups {
}
}
+ @Override
public <T> T getInstance(Key<T> key) {
return getProvider(key).get();
}
+ @Override
public <T> T getInstance(Class<T> type) {
return getProvider(type).get();
}
- /** @see #getGlobalInternalContext */
- private final ThreadLocal<Object[]> localContext;
/**
- * Synchronization: map value is modified only for the current thread,
- * it's ok to read map values of other threads. It can change between your
- * calls.
+ * Holds Object[] as a mutable wrapper, rather than InternalContext, since array operations are
+ * faster than ThreadLocal.set() / .get() operations.
*
- * @see #getGlobalInternalContext
+ * <p>Holds Object[] rather than InternalContext[], since localContext never gets cleaned up at
+ * any point. This could lead to problems when, for example, an OSGI application is reloaded, the
+ * InjectorImpl is destroyed, but the thread that the injector runs on is kept alive. In such a
+ * case, ThreadLocal itself would hold on to a reference to localContext, which would hold on to
+ * the old InternalContext.class object, which would hold on to the old classloader that loaded
+ * that class, and so on.
*/
- private static final ConcurrentMap<Thread, InternalContext> globalInternalContext =
- Maps.newConcurrentMap();
+ private final ThreadLocal<Object[]> localContext;
+
+ /** Only to be called by the {@link SingletonScope} provider. */
+ InternalContext getLocalContext() {
+ return (InternalContext) localContext.get()[0];
+ }
/**
- * Provides access to the internal context for the current injector of all threads.
- * One does not need to use this from Guice source code as context could be passed on the stack.
- * It is required for custom scopes which are called from Guice and sometimes do require
- * access to current internal context, but it is not passed in. Contrary to {@link #localContext}
- * it is not used to store injector-specific state, but to provide easy access to the current
- * state.
+ * Looks up thread local context and {@link InternalContext#enter() enters} it or creates a new
+ * context if necessary.
+ *
+ * <p>All callers of this are responsible for calling {@link InternalContext#close()}. Typical
+ * usage should look like:
*
- * @return unmodifiable map
+ * <pre>{@code
+ * InternalContext ctx = injector.enterContext();
+ * try {
+ * ... use ctx ...
+ * } finally {
+ * ctx.close();
+ * }
+ * }</pre>
*/
- static Map<Thread, InternalContext> getGlobalInternalContext() {
- return Collections.unmodifiableMap(globalInternalContext);
- }
-
- /** Looks up thread local context. Creates (and removes) a new context if necessary. */
- <T> T callInContext(ContextualCallable<T> callable) throws ErrorsException {
+ InternalContext enterContext() {
Object[] reference = localContext.get();
if (reference == null) {
reference = new Object[1];
localContext.set(reference);
}
- Thread currentThread = Thread.currentThread();
- if (reference[0] == null) {
- reference[0] = new InternalContext(options);
- globalInternalContext.put(currentThread, (InternalContext) reference[0]);
- try {
- return callable.call((InternalContext) reference[0]);
- } finally {
- // Only clear contexts if this call created them.
- reference[0] = null;
- globalInternalContext.remove(currentThread);
- }
+ InternalContext ctx = (InternalContext) reference[0];
+ if (ctx == null) {
+ reference[0] = ctx = new InternalContext(options, reference);
} else {
- Object previousGlobalInternalContext = globalInternalContext.get(currentThread);
- globalInternalContext.put(currentThread, (InternalContext) reference[0]);
- try {
- // Someone else will clean up this local context.
- return callable.call((InternalContext) reference[0]);
- } finally {
- if (previousGlobalInternalContext != null) {
- globalInternalContext.put(currentThread, (InternalContext) previousGlobalInternalContext);
- } else {
- globalInternalContext.remove(currentThread);
- }
- }
+ ctx.enter();
}
+ return ctx;
}
@Override
public String toString() {
- return Objects.toStringHelper(Injector.class)
+ return MoreObjects.toStringHelper(Injector.class)
.add("bindings", state.getExplicitBindingsThisLevel().values())
.toString();
}
diff --git a/core/src/com/google/inject/internal/InjectorOptionsProcessor.java b/core/src/com/google/inject/internal/InjectorOptionsProcessor.java
index 61cc6eea..32bab003 100644
--- a/core/src/com/google/inject/internal/InjectorOptionsProcessor.java
+++ b/core/src/com/google/inject/internal/InjectorOptionsProcessor.java
@@ -53,11 +53,11 @@ class InjectorOptionsProcessor extends AbstractProcessor {
jitDisabled = true;
return true;
}
-
+
@Override
public Boolean visit(RequireAtInjectOnConstructorsOption option) {
atInjectRequired = true;
- return true;
+ return true;
}
@Override
@@ -68,7 +68,7 @@ class InjectorOptionsProcessor extends AbstractProcessor {
InjectorOptions getOptions(Stage stage, InjectorOptions parentOptions) {
checkNotNull(stage, "stage must be set");
- if(parentOptions == null) {
+ if (parentOptions == null) {
return new InjectorOptions(
stage,
jitDisabled,
@@ -85,5 +85,4 @@ class InjectorOptionsProcessor extends AbstractProcessor {
exactBindingAnnotationsRequired || parentOptions.exactBindingAnnotationsRequired);
}
}
-
}
diff --git a/core/src/com/google/inject/internal/InjectorShell.java b/core/src/com/google/inject/internal/InjectorShell.java
index 5982bb39..e2ddcd98 100644
--- a/core/src/com/google/inject/internal/InjectorShell.java
+++ b/core/src/com/google/inject/internal/InjectorShell.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -39,14 +39,13 @@ import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding;
import com.google.inject.spi.PrivateElements;
import com.google.inject.spi.ProvisionListenerBinding;
import com.google.inject.spi.TypeListenerBinding;
-
import java.util.List;
import java.util.logging.Logger;
/**
- * A partially-initialized injector. See {@link InternalInjectorCreator}, which
- * uses this to build a tree of injectors in batch.
- *
+ * A partially-initialized injector. See {@link InternalInjectorCreator}, which uses this to build a
+ * tree of injectors in batch.
+ *
* @author jessewilson@google.com (Jesse Wilson)
*/
final class InjectorShell {
@@ -54,7 +53,7 @@ final class InjectorShell {
private final List<Element> elements;
private final InjectorImpl injector;
- private InjectorShell(Builder builder, List<Element> elements, InjectorImpl injector) {
+ private InjectorShell(List<Element> elements, InjectorImpl injector) {
this.elements = elements;
this.injector = injector;
}
@@ -80,7 +79,7 @@ final class InjectorShell {
/** null unless this exists in a {@link Binder#newPrivateBinder private environment} */
private PrivateElementsImpl privateElements;
-
+
Builder stage(Stage stage) {
this.stage = stage;
return this;
@@ -105,7 +104,7 @@ final class InjectorShell {
this.modules.add(module);
}
}
-
+
Stage getStage() {
return options.stage;
}
@@ -136,12 +135,12 @@ final class InjectorShell {
modules.add(0, new InheritedScannersModule(parent.state));
}
elements.addAll(Elements.getElements(stage, modules));
-
+
// Look for injector-changing options
InjectorOptionsProcessor optionsProcessor = new InjectorOptionsProcessor(errors);
optionsProcessor.process(null, elements);
options = optionsProcessor.getOptions(stage, options);
-
+
InjectorImpl injector = new InjectorImpl(parent, state, options);
if (privateElements != null) {
privateElements.initInjector(injector);
@@ -179,7 +178,7 @@ final class InjectorShell {
bindStage(injector, stage);
bindInjector(injector);
bindLogger(injector);
-
+
// Process all normal bindings, then UntargettedBindings.
// This is necessary because UntargettedBindings can create JIT bindings
// and need all their other dependencies set up ahead of time.
@@ -191,7 +190,7 @@ final class InjectorShell {
stopwatch.resetAndLog("Module annotated method scanners creation");
List<InjectorShell> injectorShells = Lists.newArrayList();
- injectorShells.add(new InjectorShell(this, elements, injector));
+ injectorShells.add(new InjectorShell(elements, injector));
// recursively build child shells
PrivateElementProcessor processor = new PrivateElementProcessor(errors);
@@ -213,15 +212,21 @@ final class InjectorShell {
}
/**
- * The Injector is a special case because we allow both parent and child injectors to both have
- * a binding for that key.
+ * The Injector is a special case because we allow both parent and child injectors to both have a
+ * binding for that key.
*/
private static void bindInjector(InjectorImpl injector) {
Key<Injector> key = Key.get(Injector.class);
InjectorFactory injectorFactory = new InjectorFactory(injector);
- injector.state.putBinding(key,
- new ProviderInstanceBindingImpl<Injector>(injector, key, SourceProvider.UNKNOWN_SOURCE,
- injectorFactory, Scoping.UNSCOPED, injectorFactory,
+ injector.state.putBinding(
+ key,
+ new ProviderInstanceBindingImpl<Injector>(
+ injector,
+ key,
+ SourceProvider.UNKNOWN_SOURCE,
+ injectorFactory,
+ Scoping.UNSCOPED,
+ injectorFactory,
ImmutableSet.<InjectionPoint>of()));
}
@@ -232,15 +237,17 @@ final class InjectorShell {
this.injector = injector;
}
- public Injector get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
- throws ErrorsException {
+ @Override
+ public Injector get(InternalContext context, Dependency<?> dependency, boolean linked) {
return injector;
}
+ @Override
public Injector get() {
return injector;
}
+ @Override
public String toString() {
return "Provider<Injector>";
}
@@ -253,42 +260,53 @@ final class InjectorShell {
private static void bindLogger(InjectorImpl injector) {
Key<Logger> key = Key.get(Logger.class);
LoggerFactory loggerFactory = new LoggerFactory();
- injector.state.putBinding(key,
- new ProviderInstanceBindingImpl<Logger>(injector, key,
- SourceProvider.UNKNOWN_SOURCE, loggerFactory, Scoping.UNSCOPED,
- loggerFactory, ImmutableSet.<InjectionPoint>of()));
+ injector.state.putBinding(
+ key,
+ new ProviderInstanceBindingImpl<Logger>(
+ injector,
+ key,
+ SourceProvider.UNKNOWN_SOURCE,
+ loggerFactory,
+ Scoping.UNSCOPED,
+ loggerFactory,
+ ImmutableSet.<InjectionPoint>of()));
}
private static class LoggerFactory implements InternalFactory<Logger>, Provider<Logger> {
- public Logger get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) {
+ @Override
+ public Logger get(InternalContext context, Dependency<?> dependency, boolean linked) {
InjectionPoint injectionPoint = dependency.getInjectionPoint();
return injectionPoint == null
? Logger.getAnonymousLogger()
: Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
+ @Override
public Logger get() {
return Logger.getAnonymousLogger();
}
+ @Override
public String toString() {
return "Provider<Logger>";
}
}
-
+
private static void bindStage(InjectorImpl injector, Stage stage) {
Key<Stage> key = Key.get(Stage.class);
- InstanceBindingImpl<Stage> stageBinding = new InstanceBindingImpl<Stage>(
- injector,
- key,
- SourceProvider.UNKNOWN_SOURCE,
- new ConstantFactory<Stage>(Initializables.of(stage)),
- ImmutableSet.<InjectionPoint>of(),
- stage);
+ InstanceBindingImpl<Stage> stageBinding =
+ new InstanceBindingImpl<Stage>(
+ injector,
+ key,
+ SourceProvider.UNKNOWN_SOURCE,
+ new ConstantFactory<Stage>(Initializables.of(stage)),
+ ImmutableSet.<InjectionPoint>of(),
+ stage);
injector.state.putBinding(key, stageBinding);
}
private static class RootModule implements Module {
+ @Override
public void configure(Binder binder) {
binder = binder.withSource(SourceProvider.UNKNOWN_SOURCE);
binder.bindScope(Singleton.class, SINGLETON);
@@ -303,6 +321,7 @@ final class InjectorShell {
this.state = state;
}
+ @Override
public void configure(Binder binder) {
for (ModuleAnnotatedMethodScannerBinding binding : state.getScannerBindings()) {
binding.applyTo(binder);
diff --git a/core/src/com/google/inject/internal/InstanceBindingImpl.java b/core/src/com/google/inject/internal/InstanceBindingImpl.java
index 9b7a4835..44d53b4c 100644
--- a/core/src/com/google/inject/internal/InstanceBindingImpl.java
+++ b/core/src/com/google/inject/internal/InstanceBindingImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,80 +16,83 @@
package com.google.inject.internal;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
import com.google.inject.Key;
-import com.google.inject.Provider;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.InstanceBinding;
-import com.google.inject.util.Providers;
-
import java.util.Set;
final class InstanceBindingImpl<T> extends BindingImpl<T> implements InstanceBinding<T> {
final T instance;
- final Provider<T> provider;
final ImmutableSet<InjectionPoint> injectionPoints;
- public InstanceBindingImpl(InjectorImpl injector, Key<T> key, Object source,
- InternalFactory<? extends T> internalFactory, Set<InjectionPoint> injectionPoints,
+ public InstanceBindingImpl(
+ InjectorImpl injector,
+ Key<T> key,
+ Object source,
+ InternalFactory<? extends T> internalFactory,
+ Set<InjectionPoint> injectionPoints,
T instance) {
super(injector, key, source, internalFactory, Scoping.EAGER_SINGLETON);
this.injectionPoints = ImmutableSet.copyOf(injectionPoints);
this.instance = instance;
- this.provider = Providers.of(instance);
}
- public InstanceBindingImpl(Object source, Key<T> key, Scoping scoping,
- Set<InjectionPoint> injectionPoints, T instance) {
+ public InstanceBindingImpl(
+ Object source, Key<T> key, Scoping scoping, Set<InjectionPoint> injectionPoints, T instance) {
super(source, key, scoping);
this.injectionPoints = ImmutableSet.copyOf(injectionPoints);
this.instance = instance;
- this.provider = Providers.of(instance);
- }
-
- @Override public Provider<T> getProvider() {
- return this.provider;
}
+ @Override
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
return visitor.visit(this);
}
+ @Override
public T getInstance() {
return instance;
}
+ @Override
public Set<InjectionPoint> getInjectionPoints() {
return injectionPoints;
}
+ @Override
public Set<Dependency<?>> getDependencies() {
return instance instanceof HasDependencies
? ImmutableSet.copyOf(((HasDependencies) instance).getDependencies())
: Dependency.forInjectionPoints(injectionPoints);
}
+ @Override
public BindingImpl<T> withScoping(Scoping scoping) {
return new InstanceBindingImpl<T>(getSource(), getKey(), scoping, injectionPoints, instance);
}
+ @Override
public BindingImpl<T> withKey(Key<T> key) {
return new InstanceBindingImpl<T>(getSource(), key, getScoping(), injectionPoints, instance);
}
+ @Override
public void applyTo(Binder binder) {
// instance bindings aren't scoped
binder.withSource(getSource()).bind(getKey()).toInstance(instance);
}
- @Override public String toString() {
- return Objects.toStringHelper(InstanceBinding.class)
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(InstanceBinding.class)
.add("key", getKey())
.add("source", getSource())
.add("instance", instance)
@@ -98,11 +101,11 @@ final class InstanceBindingImpl<T> extends BindingImpl<T> implements InstanceBin
@Override
public boolean equals(Object obj) {
- if(obj instanceof InstanceBindingImpl) {
- InstanceBindingImpl<?> o = (InstanceBindingImpl<?>)obj;
+ if (obj instanceof InstanceBindingImpl) {
+ InstanceBindingImpl<?> o = (InstanceBindingImpl<?>) obj;
return getKey().equals(o.getKey())
- && getScoping().equals(o.getScoping())
- && Objects.equal(instance, o.instance);
+ && getScoping().equals(o.getScoping())
+ && Objects.equal(instance, o.instance);
} else {
return false;
}
diff --git a/core/src/com/google/inject/internal/InterceptorBindingProcessor.java b/core/src/com/google/inject/internal/InterceptorBindingProcessor.java
index e3526727..de2174aa 100644
--- a/core/src/com/google/inject/internal/InterceptorBindingProcessor.java
+++ b/core/src/com/google/inject/internal/InterceptorBindingProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,9 +30,11 @@ final class InterceptorBindingProcessor extends AbstractProcessor {
super(errors);
}
- @Override public Boolean visit(InterceptorBinding command) {
- injector.state.addMethodAspect(new MethodAspect(
- command.getClassMatcher(), command.getMethodMatcher(), command.getInterceptors()));
+ @Override
+ public Boolean visit(InterceptorBinding command) {
+ injector.state.addMethodAspect(
+ new MethodAspect(
+ command.getClassMatcher(), command.getMethodMatcher(), command.getInterceptors()));
return true;
}
}
diff --git a/core/src/com/google/inject/internal/InterceptorStackCallback.java b/core/src/com/google/inject/internal/InterceptorStackCallback.java
index f12ddaf5..7ae22bbb 100644
--- a/core/src/com/google/inject/internal/InterceptorStackCallback.java
+++ b/core/src/com/google/inject/internal/InterceptorStackCallback.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,18 +17,15 @@
package com.google.inject.internal;
import com.google.common.collect.Lists;
-
-import net.sf.cglib.proxy.MethodProxy;
-
-import org.aopalliance.intercept.MethodInterceptor;
-import org.aopalliance.intercept.MethodInvocation;
-
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import net.sf.cglib.proxy.MethodProxy;
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
/**
* Intercepts a method with a stack of interceptors.
@@ -36,22 +33,24 @@ import java.util.Set;
* @author crazybob@google.com (Bob Lee)
*/
final class InterceptorStackCallback implements net.sf.cglib.proxy.MethodInterceptor {
- private static final Set<String> AOP_INTERNAL_CLASSES = new HashSet<String>(Arrays.asList(
- InterceptorStackCallback.class.getName(),
- InterceptedMethodInvocation.class.getName(),
- MethodProxy.class.getName()));
+ private static final Set<String> AOP_INTERNAL_CLASSES =
+ new HashSet<String>(
+ Arrays.asList(
+ InterceptorStackCallback.class.getName(),
+ InterceptedMethodInvocation.class.getName(),
+ MethodProxy.class.getName()));
final MethodInterceptor[] interceptors;
final Method method;
- public InterceptorStackCallback(Method method,
- List<MethodInterceptor> interceptors) {
+ public InterceptorStackCallback(Method method, List<MethodInterceptor> interceptors) {
this.method = method;
this.interceptors = interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
- public Object intercept(Object proxy, Method method, Object[] arguments,
- MethodProxy methodProxy) throws Throwable {
+ @Override
+ public Object intercept(Object proxy, Method method, Object[] arguments, MethodProxy methodProxy)
+ throws Throwable {
return new InterceptedMethodInvocation(proxy, methodProxy, arguments, 0).proceed();
}
@@ -62,49 +61,54 @@ final class InterceptorStackCallback implements net.sf.cglib.proxy.MethodInterce
final MethodProxy methodProxy;
final int index;
- public InterceptedMethodInvocation(Object proxy, MethodProxy methodProxy,
- Object[] arguments, int index) {
+ public InterceptedMethodInvocation(
+ Object proxy, MethodProxy methodProxy, Object[] arguments, int index) {
this.proxy = proxy;
this.methodProxy = methodProxy;
this.arguments = arguments;
this.index = index;
}
+ @Override
public Object proceed() throws Throwable {
try {
return index == interceptors.length
? methodProxy.invokeSuper(proxy, arguments)
- : interceptors[index].invoke(
- new InterceptedMethodInvocation(proxy, methodProxy, arguments, index + 1));
+ : interceptors[index]
+ .invoke(new InterceptedMethodInvocation(proxy, methodProxy, arguments, index + 1));
} catch (Throwable t) {
pruneStacktrace(t);
throw t;
}
}
+ @Override
public Method getMethod() {
return method;
}
+ @Override
public Object[] getArguments() {
return arguments;
}
+ @Override
public Object getThis() {
return proxy;
}
+ @Override
public AccessibleObject getStaticPart() {
return getMethod();
}
}
/**
- * Removes stacktrace elements related to AOP internal mechanics from the
- * throwable's stack trace and any causes it may have.
+ * Removes stacktrace elements related to AOP internal mechanics from the throwable's stack trace
+ * and any causes it may have.
*/
private void pruneStacktrace(Throwable throwable) {
- for(Throwable t = throwable; t != null; t = t.getCause()) {
+ for (Throwable t = throwable; t != null; t = t.getCause()) {
StackTraceElement[] stackTrace = t.getStackTrace();
List<StackTraceElement> pruned = Lists.newArrayList();
for (StackTraceElement element : stackTrace) {
diff --git a/core/src/com/google/inject/internal/InternalContext.java b/core/src/com/google/inject/internal/InternalContext.java
index 0af19697..59c77c58 100644
--- a/core/src/com/google/inject/internal/InternalContext.java
+++ b/core/src/com/google/inject/internal/InternalContext.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,129 +16,153 @@
package com.google.inject.internal;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.inject.Key;
import com.google.inject.internal.InjectorImpl.InjectorOptions;
import com.google.inject.spi.Dependency;
-import com.google.inject.spi.DependencyAndSource;
-
-import java.util.Arrays;
-import java.util.List;
+import java.util.IdentityHashMap;
import java.util.Map;
/**
- * Internal context. Used to coordinate injections and support circular
- * dependencies.
+ * Internal context. Used to coordinate injections and support circular dependencies.
*
* @author crazybob@google.com (Bob Lee)
*/
-final class InternalContext {
+final class InternalContext implements AutoCloseable {
private final InjectorOptions options;
- private Map<Object, ConstructionContext<?>> constructionContexts = Maps.newHashMap();
+ private final Map<Object, ConstructionContext<?>> constructionContexts =
+ new IdentityHashMap<Object, ConstructionContext<?>>();
/** Keeps track of the type that is currently being requested for injection. */
private Dependency<?> dependency;
- /** Keeps track of the hierarchy of types needed during injection. */
- private final DependencyStack state = new DependencyStack();
+ /**
+ * Keeps track of the hierarchy of types needed during injection.
+ *
+ * <p>This is a pairwise combination of dependencies and sources, with dependencies or keys on
+ * even indices, and sources on odd indices. This structure is to avoid the memory overhead of
+ * DependencyAndSource objects, which can add to several tens of megabytes in large applications.
+ */
+ private Object[] dependencyStack = new Object[16];
+
+ private int dependencyStackSize = 0;
- InternalContext(InjectorOptions options) {
+
+ /**
+ * The number of times {@link #enter()} has been called + 1 for initial construction. This value
+ * is decremented when {@link #exit()} is called.
+ */
+ private int enterCount;
+
+ /**
+ * A single element array to clear when the {@link #enterCount} hits {@code 0}.
+ *
+ * <p>This is the value stored in the {@code InjectorImpl.localContext} thread local.
+ */
+ private final Object[] toClear;
+
+ InternalContext(InjectorOptions options, Object[] toClear) {
this.options = options;
+ this.toClear = toClear;
+ this.enterCount = 1;
+ }
+
+ /** Should only be called by InjectorImpl.enterContext(). */
+ void enter() {
+ enterCount++;
+ }
+
+ /** Should be called any any method that received an instance via InjectorImpl.enterContext(). */
+ @Override
+ public void close() {
+ int newCount = --enterCount;
+ if (newCount < 0) {
+ throw new IllegalStateException("Called close() too many times");
+ }
+ if (newCount == 0) {
+ toClear[0] = null;
+ }
}
- public InjectorOptions getInjectorOptions() {
+ InjectorOptions getInjectorOptions() {
return options;
}
@SuppressWarnings("unchecked")
- public <T> ConstructionContext<T> getConstructionContext(Object key) {
- ConstructionContext<T> constructionContext
- = (ConstructionContext<T>) constructionContexts.get(key);
+ <T> ConstructionContext<T> getConstructionContext(Object key) {
+ ConstructionContext<T> constructionContext =
+ (ConstructionContext<T>) constructionContexts.get(key);
if (constructionContext == null) {
- constructionContext = new ConstructionContext<T>();
+ constructionContext = new ConstructionContext<>();
constructionContexts.put(key, constructionContext);
}
return constructionContext;
}
- public Dependency<?> getDependency() {
+ Dependency<?> getDependency() {
return dependency;
}
/** Sets the new current dependency & adds it to the state. */
- public Dependency<?> pushDependency(Dependency<?> dependency, Object source) {
+ Dependency<?> pushDependency(Dependency<?> dependency, Object source) {
Dependency<?> previous = this.dependency;
this.dependency = dependency;
- state.add(dependency, source);
+ doPushState(dependency, source);
return previous;
}
+
/** Pops the current state & sets the new dependency. */
- public void popStateAndSetDependency(Dependency<?> newDependency) {
- state.pop();
+ void popStateAndSetDependency(Dependency<?> newDependency) {
+ popState();
this.dependency = newDependency;
}
+
/** Adds to the state without setting the dependency. */
- public void pushState(Key<?> key, Object source) {
- state.add(key, source);
+ void pushState(com.google.inject.Key<?> key, Object source) {
+ doPushState(key, source);
}
-
+
+
+ private void doPushState(Object dependencyOrKey, Object source) {
+ int localSize = dependencyStackSize;
+ Object[] localStack = dependencyStack;
+ if (localStack.length < localSize + 2) {
+ localStack = dependencyStack =
+ java.util.Arrays.copyOf(localStack, (localStack.length * 3) / 2 + 2);
+ }
+ localStack[localSize++] = dependencyOrKey;
+ localStack[localSize++] = source;
+ dependencyStackSize = localSize;
+ }
+
+
/** Pops from the state without setting a dependency. */
- public void popState() {
- state.pop();
+ void popState() {
+ // N.B. we don't null out the array entries. It isn't necessary since all the objects in the
+ // array (Key, Dependency, or Binding source objects) are all tied to the lifetime of the
+ // injector, which is greater than the lifetime of this object. So removing them from the array
+ // doesn't matter.
+ dependencyStackSize -= 2;
}
- /** Returns the current dependency chain (all the state). */
- public List<DependencyAndSource> getDependencyChain() {
- ImmutableList.Builder<DependencyAndSource> builder = ImmutableList.builder();
- for (int i = 0; i < state.size(); i += 2) {
- Object evenEntry = state.get(i);
+
+ /** Returns the current dependency chain (all the state stored in the dependencyStack). */
+ java.util.List<com.google.inject.spi.DependencyAndSource> getDependencyChain() {
+ com.google.common.collect.ImmutableList.Builder<com.google.inject.spi.DependencyAndSource>
+ builder = com.google.common.collect.ImmutableList.builder();
+ for (int i = 0; i < dependencyStackSize; i += 2) {
+ Object evenEntry = dependencyStack[i];
Dependency<?> dependency;
- if (evenEntry instanceof Key) {
- dependency = Dependency.get((Key<?>) evenEntry);
+ if (evenEntry instanceof com.google.inject.Key) {
+ dependency = Dependency.get((com.google.inject.Key<?>) evenEntry);
} else {
dependency = (Dependency<?>) evenEntry;
}
- builder.add(new DependencyAndSource(dependency, state.get(i + 1)));
+ builder.add(new com.google.inject.spi.DependencyAndSource(dependency, dependencyStack[i + 1]));
}
return builder.build();
}
- /**
- * Keeps track of the hierarchy of types needed during injection.
- *
- * <p>This is a pairwise combination of dependencies and sources, with dependencies or keys on
- * even indices, and sources on odd indices. This structure is to avoid the memory overhead of
- * DependencyAndSource objects, which can add to several tens of megabytes in large applications.
- */
- private static final class DependencyStack {
- private Object[] elements = new Object[16];
- private int size = 0;
-
- public void add(Object dependencyOrKey, Object source) {
- if (elements.length < size + 2) {
- elements = Arrays.copyOf(elements, (elements.length*3)/2 + 2);
- }
- elements[size++] = dependencyOrKey;
- elements[size++] = source;
- }
-
- public void pop() {
- elements[--size] = null;
- elements[--size] = null;
- }
-
- public Object get(int i) {
- return elements[i];
- }
-
- public int size() {
- return size;
- }
- }
}
diff --git a/core/src/com/google/inject/internal/InternalFactory.java b/core/src/com/google/inject/internal/InternalFactory.java
index 2267b128..00f0d11a 100644
--- a/core/src/com/google/inject/internal/InternalFactory.java
+++ b/core/src/com/google/inject/internal/InternalFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,12 +27,12 @@ interface InternalFactory<T> {
/**
* Creates an object to be injected.
+ *
* @param context of this injection
* @param linked true if getting as a result of a linked binding
- *
- * @throws com.google.inject.internal.ErrorsException if a value cannot be provided
- * @return instance to be injected
+ * @throws com.google.inject.internal.InternalProvisionException if a value cannot be provided
+ * @return instance that was created
*/
- T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
- throws ErrorsException;
+ T get(InternalContext context, Dependency<?> dependency, boolean linked)
+ throws InternalProvisionException;
}
diff --git a/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java b/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java
index c02c70ea..218ce7c1 100644
--- a/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java
+++ b/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,11 +22,11 @@ import com.google.inject.spi.Dependency;
import com.google.inject.spi.ProviderInstanceBinding;
/**
- * Adapts {@link ProviderInstanceBinding} providers, ensuring circular proxies
- * fail (or proxy) properly.
- *
+ * Adapts {@link ProviderInstanceBinding} providers, ensuring circular proxies fail (or proxy)
+ * properly.
+ *
* @author sameb@google.com (Sam Berlin)
-*/
+ */
final class InternalFactoryToInitializableAdapter<T> extends ProviderInternalFactory<T> {
private final ProvisionListenerStackCallback<T> provisionCallback;
@@ -34,29 +34,34 @@ final class InternalFactoryToInitializableAdapter<T> extends ProviderInternalFac
public InternalFactoryToInitializableAdapter(
Initializable<? extends javax.inject.Provider<? extends T>> initializable,
- Object source, ProvisionListenerStackCallback<T> provisionCallback) {
+ Object source,
+ ProvisionListenerStackCallback<T> provisionCallback) {
super(source);
- this.provisionCallback = checkNotNull(provisionCallback, "provisionCallback");
+ this.provisionCallback = provisionCallback;
this.initializable = checkNotNull(initializable, "provider");
}
- public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
- throws ErrorsException {
- return circularGet(initializable.get(errors), errors, context, dependency,
- provisionCallback);
+ @Override
+ public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+ throws InternalProvisionException {
+ return circularGet(initializable.get(), context, dependency, provisionCallback);
}
-
+
@Override
- protected T provision(javax.inject.Provider<? extends T> provider, Errors errors,
- Dependency<?> dependency, ConstructionContext<T> constructionContext) throws ErrorsException {
+ protected T provision(
+ javax.inject.Provider<? extends T> provider,
+ Dependency<?> dependency,
+ ConstructionContext<T> constructionContext)
+ throws InternalProvisionException {
try {
- return super.provision(provider, errors, dependency, constructionContext);
- } catch(RuntimeException userException) {
- throw errors.withSource(source).errorInProvider(userException).toException();
+ return super.provision(provider, dependency, constructionContext);
+ } catch (RuntimeException userException) {
+ throw InternalProvisionException.errorInProvider(userException).addSource(source);
}
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return initializable.toString();
}
}
diff --git a/core/src/com/google/inject/internal/InternalFactoryToProviderAdapter.java b/core/src/com/google/inject/internal/InternalFactoryToProviderAdapter.java
index 4cd1b2e1..690f6836 100644
--- a/core/src/com/google/inject/internal/InternalFactoryToProviderAdapter.java
+++ b/core/src/com/google/inject/internal/InternalFactoryToProviderAdapter.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,9 +21,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.inject.Provider;
import com.google.inject.spi.Dependency;
-/**
- * @author crazybob@google.com (Bob Lee)
-*/
+/** @author crazybob@google.com (Bob Lee) */
final class InternalFactoryToProviderAdapter<T> implements InternalFactory<T> {
private final Provider<? extends T> provider;
@@ -34,17 +32,22 @@ final class InternalFactoryToProviderAdapter<T> implements InternalFactory<T> {
this.source = checkNotNull(source, "source");
}
- public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
- throws ErrorsException {
- // TODO(sameb): Does this need to push state into the context?
+ @Override
+ public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+ throws InternalProvisionException {
try {
- return errors.checkForNull(provider.get(), source, dependency);
+ T t = provider.get();
+ if (t == null && !dependency.isNullable()) {
+ InternalProvisionException.onNullInjectedIntoNonNullableDependency(source, dependency);
+ }
+ return t;
} catch (RuntimeException userException) {
- throw errors.withSource(source).errorInProvider(userException).toException();
+ throw InternalProvisionException.errorInProvider(userException).addSource(source);
}
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return provider.toString();
}
}
diff --git a/core/src/com/google/inject/internal/InternalFlags.java b/core/src/com/google/inject/internal/InternalFlags.java
index 85c07acb..4127ea6d 100644
--- a/core/src/com/google/inject/internal/InternalFlags.java
+++ b/core/src/com/google/inject/internal/InternalFlags.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -121,11 +121,14 @@ public class InternalFlags {
Class<T> enumType = defaultValue.getDeclaringClass();
String value = null;
try {
- value = AccessController.doPrivileged(new PrivilegedAction<String>() {
- public String run() {
- return System.getProperty(name);
- }
- });
+ value =
+ AccessController.doPrivileged(
+ new PrivilegedAction<String>() {
+ @Override
+ public String run() {
+ return System.getProperty(name);
+ }
+ });
return (value != null && value.length() > 0) ? Enum.valueOf(enumType, value) : defaultValue;
} catch (SecurityException e) {
return secureValue;
diff --git a/core/src/com/google/inject/internal/InternalInjectorCreator.java b/core/src/com/google/inject/internal/InternalInjectorCreator.java
index d40bc83b..64c4cf1f 100644
--- a/core/src/com/google/inject/internal/InternalInjectorCreator.java
+++ b/core/src/com/google/inject/internal/InternalInjectorCreator.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,8 +16,6 @@
package com.google.inject.internal;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
@@ -30,8 +28,8 @@ import com.google.inject.TypeLiteral;
import com.google.inject.internal.util.Stopwatch;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.TypeConverterBinding;
-
import java.lang.annotation.Annotation;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -43,14 +41,15 @@ import java.util.Set;
* top-level injector.
*
* <p>Injector construction happens in two phases.
+ *
* <ol>
- * <li>Static building. In this phase, we interpret commands, create bindings, and inspect
+ * <li>Static building. In this phase, we interpret commands, create bindings, and inspect
* dependencies. During this phase, we hold a lock to ensure consistency with parent injectors.
- * No user code is executed in this phase.</li>
- * <li>Dynamic injection. In this phase, we call user code. We inject members that requested
+ * No user code is executed in this phase.
+ * <li>Dynamic injection. In this phase, we call user code. We inject members that requested
* injection. This may require user's objects be created and their providers be called. And we
* create eager singletons. In this phase, user code may have started other threads. This phase
- * is not executed for injectors created using {@link Stage#TOOL the tool stage}</li>
+ * is not executed for injectors created using {@link Stage#TOOL the tool stage}
* </ol>
*
* @author crazybob@google.com (Bob Lee)
@@ -67,12 +66,12 @@ public final class InternalInjectorCreator {
private final InjectorShell.Builder shellBuilder = new InjectorShell.Builder();
private List<InjectorShell> shells;
-
+
public InternalInjectorCreator() {
injectionRequestProcessor = new InjectionRequestProcessor(errors, initializer);
bindingData = new ProcessedBindingData();
}
-
+
public InternalInjectorCreator stage(Stage stage) {
shellBuilder.stage(stage);
return this;
@@ -146,6 +145,11 @@ public final class InternalInjectorCreator {
}
stopwatch.resetAndLog("Provider verification");
+ // This needs to come late since some user bindings rely on requireBinding calls to create
+ // jit bindings during the LookupProcessor.
+ bindingData.initializeDelayedBindings();
+ stopwatch.resetAndLog("Delayed Binding initialization");
+
for (InjectorShell shell : shells) {
if (!shell.getElements().isEmpty()) {
throw new AssertionError("Failed to execute " + shell.getElements());
@@ -155,9 +159,7 @@ public final class InternalInjectorCreator {
errors.throwCreationExceptionIfErrorsExist();
}
- /**
- * Returns the injector being constructed. This is not necessarily the root injector.
- */
+ /** Returns the injector being constructed. This is not necessarily the root injector. */
private Injector primaryInjector() {
return shells.get(0).getInjector();
}
@@ -175,7 +177,7 @@ public final class InternalInjectorCreator {
stopwatch.resetAndLog("Instance injection");
errors.throwCreationExceptionIfErrorsExist();
- if(shellBuilder.getStage() != Stage.TOOL) {
+ if (shellBuilder.getStage() != Stage.TOOL) {
for (InjectorShell shell : shells) {
loadEagerSingletons(shell.getInjector(), shellBuilder.getStage(), errors);
}
@@ -189,33 +191,33 @@ public final class InternalInjectorCreator {
* while we're binding these singletons are not be eager.
*/
void loadEagerSingletons(InjectorImpl injector, Stage stage, final Errors errors) {
+ List<BindingImpl<?>> candidateBindings = new ArrayList<>();
@SuppressWarnings("unchecked") // casting Collection<Binding> to Collection<BindingImpl> is safe
- Iterable<BindingImpl<?>> candidateBindings = ImmutableList.copyOf(Iterables.concat(
- (Collection) injector.state.getExplicitBindingsThisLevel().values(),
- injector.jitBindings.values()));
- for (final BindingImpl<?> binding : candidateBindings) {
- if (isEagerSingleton(injector, binding, stage)) {
- try {
- injector.callInContext(new ContextualCallable<Void>() {
- Dependency<?> dependency = Dependency.get(binding.getKey());
- public Void call(InternalContext context) {
- Dependency previous = context.pushDependency(dependency, binding.getSource());
- Errors errorsForBinding = errors.withSource(dependency);
- try {
- binding.getInternalFactory().get(errorsForBinding, context, dependency, false);
- } catch (ErrorsException e) {
- errorsForBinding.merge(e.getErrors());
- } finally {
- context.popStateAndSetDependency(previous);
- }
-
- return null;
+ Collection<BindingImpl<?>> bindingsAtThisLevel =
+ (Collection) injector.state.getExplicitBindingsThisLevel().values();
+ candidateBindings.addAll(bindingsAtThisLevel);
+ synchronized (injector.state.lock()) {
+ // jit bindings must be accessed while holding the lock.
+ candidateBindings.addAll(injector.jitBindings.values());
+ }
+ InternalContext context = injector.enterContext();
+ try {
+ for (BindingImpl<?> binding : candidateBindings) {
+ if (isEagerSingleton(injector, binding, stage)) {
+ Dependency<?> dependency = Dependency.get(binding.getKey());
+ Dependency previous = context.pushDependency(dependency, binding.getSource());
+
+ try {
+ binding.getInternalFactory().get(context, dependency, false);
+ } catch (InternalProvisionException e) {
+ errors.withSource(dependency).merge(e);
+ } finally {
+ context.popStateAndSetDependency(previous);
}
- });
- } catch (ErrorsException e) {
- throw new AssertionError();
}
}
+ } finally {
+ context.close();
}
}
@@ -238,70 +240,106 @@ public final class InternalInjectorCreator {
/** {@link Injector} exposed to users in {@link Stage#TOOL}. */
static class ToolStageInjector implements Injector {
private final Injector delegateInjector;
-
+
ToolStageInjector(Injector delegateInjector) {
this.delegateInjector = delegateInjector;
}
+
+ @Override
public void injectMembers(Object o) {
throw new UnsupportedOperationException(
- "Injector.injectMembers(Object) is not supported in Stage.TOOL");
+ "Injector.injectMembers(Object) is not supported in Stage.TOOL");
}
+
+ @Override
public Map<Key<?>, Binding<?>> getBindings() {
return this.delegateInjector.getBindings();
}
+
+ @Override
public Map<Key<?>, Binding<?>> getAllBindings() {
return this.delegateInjector.getAllBindings();
}
+
+ @Override
public <T> Binding<T> getBinding(Key<T> key) {
return this.delegateInjector.getBinding(key);
}
+
+ @Override
public <T> Binding<T> getBinding(Class<T> type) {
return this.delegateInjector.getBinding(type);
}
+
+ @Override
public <T> Binding<T> getExistingBinding(Key<T> key) {
return this.delegateInjector.getExistingBinding(key);
}
+
+ @Override
public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) {
return this.delegateInjector.findBindingsByType(type);
}
+
+ @Override
public Injector getParent() {
return delegateInjector.getParent();
}
+
+ @Override
public Injector createChildInjector(Iterable<? extends Module> modules) {
return delegateInjector.createChildInjector(modules);
}
+
+ @Override
public Injector createChildInjector(Module... modules) {
return delegateInjector.createChildInjector(modules);
}
+
+ @Override
public Map<Class<? extends Annotation>, Scope> getScopeBindings() {
return delegateInjector.getScopeBindings();
}
+
+ @Override
public Set<TypeConverterBinding> getTypeConverterBindings() {
return delegateInjector.getTypeConverterBindings();
}
+
+ @Override
public <T> Provider<T> getProvider(Key<T> key) {
throw new UnsupportedOperationException(
- "Injector.getProvider(Key<T>) is not supported in Stage.TOOL");
+ "Injector.getProvider(Key<T>) is not supported in Stage.TOOL");
}
+
+ @Override
public <T> Provider<T> getProvider(Class<T> type) {
throw new UnsupportedOperationException(
- "Injector.getProvider(Class<T>) is not supported in Stage.TOOL");
+ "Injector.getProvider(Class<T>) is not supported in Stage.TOOL");
}
+
+ @Override
public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
throw new UnsupportedOperationException(
- "Injector.getMembersInjector(TypeLiteral<T>) is not supported in Stage.TOOL");
+ "Injector.getMembersInjector(TypeLiteral<T>) is not supported in Stage.TOOL");
}
+
+ @Override
public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
throw new UnsupportedOperationException(
- "Injector.getMembersInjector(Class<T>) is not supported in Stage.TOOL");
+ "Injector.getMembersInjector(Class<T>) is not supported in Stage.TOOL");
}
+
+ @Override
public <T> T getInstance(Key<T> key) {
throw new UnsupportedOperationException(
- "Injector.getInstance(Key<T>) is not supported in Stage.TOOL");
+ "Injector.getInstance(Key<T>) is not supported in Stage.TOOL");
}
+
+ @Override
public <T> T getInstance(Class<T> type) {
throw new UnsupportedOperationException(
- "Injector.getInstance(Class<T>) is not supported in Stage.TOOL");
+ "Injector.getInstance(Class<T>) is not supported in Stage.TOOL");
}
}
}
diff --git a/core/src/com/google/inject/internal/InternalProviderInstanceBindingImpl.java b/core/src/com/google/inject/internal/InternalProviderInstanceBindingImpl.java
new file mode 100644
index 00000000..dd941aa7
--- /dev/null
+++ b/core/src/com/google/inject/internal/InternalProviderInstanceBindingImpl.java
@@ -0,0 +1,195 @@
+package com.google.inject.internal;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Key;
+import com.google.inject.Provider;
+import com.google.inject.internal.ProvisionListenerStackCallback.ProvisionCallback;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.HasDependencies;
+import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.ProviderWithExtensionVisitor;
+
+/**
+ * A {@link ProviderInstanceBindingImpl} for implementing 'native' guice extensions.
+ *
+ * <p>Beyond the normal binding contract that is mostly handled by our baseclass, this also
+ * implements {@link DelayedInitialize} in order to initialize factory state.
+ */
+final class InternalProviderInstanceBindingImpl<T> extends ProviderInstanceBindingImpl<T>
+ implements DelayedInitialize {
+ enum InitializationTiming {
+ /** This factory can be initialized eagerly. This should be the case for most things. */
+ EAGER,
+
+ /**
+ * Initialization of this factory should be delayed until after all other static initialization
+ * completes. This will be useful for factories that need to call {@link
+ * InjectorImpl#getExistingBinding(Key)} to not create jit bindings, but also want to be able to
+ * conditionally consume jit bindings created by other other bindings.
+ */
+ DELAYED;
+ }
+
+ private final Factory<T> originalFactory;
+
+ InternalProviderInstanceBindingImpl(
+ InjectorImpl injector,
+ Key<T> key,
+ Object source,
+ Factory<T> originalFactory,
+ InternalFactory<? extends T> scopedFactory,
+ Scoping scoping) {
+ super(
+ injector,
+ key,
+ source,
+ scopedFactory,
+ scoping,
+ originalFactory,
+ ImmutableSet.<InjectionPoint>of());
+ this.originalFactory = originalFactory;
+ }
+
+ InitializationTiming getInitializationTiming() {
+ return originalFactory.initializationTiming;
+ }
+
+ @Override
+ public void initialize(final InjectorImpl injector, final Errors errors) throws ErrorsException {
+ originalFactory.source = getSource();
+ originalFactory.provisionCallback = injector.provisionListenerStore.get(this);
+ // For these kinds of providers, the 'user supplied provider' is really 'guice supplied'
+ // So make our user supplied provider just delegate to the guice supplied one.
+ originalFactory.delegateProvider = getProvider();
+ originalFactory.initialize(injector, errors);
+ }
+
+ /**
+ * A base factory implementation. Any Factories that delegate to other bindings should use the
+ * {@code CyclicFactory} subclass, but trivial factories can use this one.
+ */
+ abstract static class Factory<T> implements InternalFactory<T>, Provider<T>, HasDependencies {
+ private final InitializationTiming initializationTiming;
+ private Object source;
+ private Provider<T> delegateProvider;
+ ProvisionListenerStackCallback<T> provisionCallback;
+
+ Factory(InitializationTiming initializationTiming) {
+ this.initializationTiming = initializationTiming;
+ }
+ /**
+ * The binding source.
+ *
+ * <p>May be useful for augmenting runtime error messages.
+ *
+ * <p>Note: this will return {#code null} until {@link #initialize(InjectorImpl, Errors)} has
+ * already been called.
+ */
+ final Object getSource() {
+ return source;
+ }
+
+ /**
+ * A callback that allows for implementations to fetch dependencies on other bindings.
+ *
+ * <p>Will be called exactly once, prior to any call to {@link #doProvision}.
+ */
+ abstract void initialize(InjectorImpl injector, Errors errors) throws ErrorsException;
+
+ @Override
+ public final T get() {
+ Provider<T> local = delegateProvider;
+ if (local == null) {
+ throw new IllegalStateException(
+ "This Provider cannot be used until the Injector has been created.");
+ }
+ return local.get();
+ }
+
+ @Override
+ public T get(final InternalContext context, final Dependency<?> dependency, boolean linked)
+ throws InternalProvisionException {
+ if (provisionCallback == null) {
+ return doProvision(context, dependency);
+ } else {
+ return provisionCallback.provision(
+ context,
+ new ProvisionCallback<T>() {
+ @Override
+ public T call() throws InternalProvisionException {
+ return doProvision(context, dependency);
+ }
+ });
+ }
+ }
+ /**
+ * Creates an object to be injected.
+ *
+ * @throws com.google.inject.internal.InternalProvisionException if a value cannot be provided
+ * @return instance to be injected
+ */
+ protected abstract T doProvision(InternalContext context, Dependency<?> dependency)
+ throws InternalProvisionException;
+ }
+
+ /**
+ * An base factory implementation that can be extended to provide a specialized implementation of
+ * a {@link ProviderWithExtensionVisitor} and also implements {@link InternalFactory}
+ */
+ abstract static class CyclicFactory<T> extends Factory<T> {
+
+ CyclicFactory(InitializationTiming initializationTiming) {
+ super(initializationTiming);
+ }
+
+ @Override
+ public final T get(
+ final InternalContext context, final Dependency<?> dependency, boolean linked)
+ throws InternalProvisionException {
+ final ConstructionContext<T> constructionContext = context.getConstructionContext(this);
+ // We have a circular reference between bindings. Return a proxy.
+ if (constructionContext.isConstructing()) {
+ Class<?> expectedType = dependency.getKey().getTypeLiteral().getRawType();
+ @SuppressWarnings("unchecked")
+ T proxyType =
+ (T) constructionContext.createProxy(context.getInjectorOptions(), expectedType);
+ return proxyType;
+ }
+ // Optimization: Don't go through the callback stack if no one's listening.
+ constructionContext.startConstruction();
+ try {
+ if (provisionCallback == null) {
+ return provision(dependency, context, constructionContext);
+ } else {
+ return provisionCallback.provision(
+ context,
+ new ProvisionCallback<T>() {
+ @Override
+ public T call() throws InternalProvisionException {
+ return provision(dependency, context, constructionContext);
+ }
+ });
+ }
+ } finally {
+ constructionContext.removeCurrentReference();
+ constructionContext.finishConstruction();
+ }
+ }
+
+ private T provision(
+ Dependency<?> dependency,
+ InternalContext context,
+ ConstructionContext<T> constructionContext)
+ throws InternalProvisionException {
+ try {
+ T t = doProvision(context, dependency);
+ constructionContext.setProxyDelegates(t);
+ return t;
+ } catch (InternalProvisionException ipe) {
+ throw ipe.addSource(getSource());
+ } catch (Throwable t) {
+ throw InternalProvisionException.errorInProvider(t).addSource(getSource());
+ }
+ }
+ }
+}
diff --git a/core/src/com/google/inject/internal/InternalProvisionException.java b/core/src/com/google/inject/internal/InternalProvisionException.java
new file mode 100644
index 00000000..4a49d923
--- /dev/null
+++ b/core/src/com/google/inject/internal/InternalProvisionException.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2017 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.internal;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.inject.Guice;
+import com.google.inject.Key;
+import com.google.inject.MembersInjector;
+import com.google.inject.Provides;
+import com.google.inject.ProvisionException;
+import com.google.inject.TypeLiteral;
+import com.google.inject.internal.util.SourceProvider;
+import com.google.inject.internal.util.StackTraceElements;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.InjectionListener;
+import com.google.inject.spi.Message;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+/**
+ * A checked exception for provisioning errors.
+ *
+ * <p>This is the internal dual of {@link ProvisionException}, similar to the relationship between
+ * {@link com.google.inject.ConfigurationException} and {@link ErrorsException}. This is useful for
+ * several reasons:
+ *
+ * <ul>
+ * <li>Since it is a checked exception, we get some assistance from the java compiler in ensuring
+ * that we correctly handle it everywhere. ProvisionException is unchecked.
+ * <li>Since this is an internal package, we can add useful construction and mutation APIs that
+ * would be undesirable in a public supported API.
+ * </ul>
+ *
+ * <p>This exception will be thrown when errors are encountered during provisioning, ErrorsException
+ * will continue to be used for errors that are encountered during provisioning and both make use of
+ * the {@link Message} as the core model.
+ *
+ * <p>NOTE: this object stores a list of messages but in the most common case the cardinality will
+ * be 1. The only time that multiple errors might be reported via this mechanism is when {@link
+ * #errorInUserCode} is called with an exception that holds multiple errors (like
+ * ProvisionException).
+ */
+public final class InternalProvisionException extends Exception {
+ private static final Logger logger = Logger.getLogger(Guice.class.getName());
+ private static final Set<Dependency<?>> warnedDependencies =
+ Collections.newSetFromMap(new ConcurrentHashMap<Dependency<?>, Boolean>());
+
+
+ public static InternalProvisionException circularDependenciesDisabled(Class<?> expectedType) {
+ return create(
+ "Found a circular dependency involving %s, and circular dependencies are disabled.",
+ expectedType);
+ }
+
+ public static InternalProvisionException cannotProxyClass(Class<?> expectedType) {
+ return create(
+ "Tried proxying %s to support a circular dependency, but it is not an interface.",
+ expectedType);
+ }
+
+ public static InternalProvisionException create(String format, Object... arguments) {
+ return new InternalProvisionException(Messages.create(format, arguments));
+ }
+
+ public static InternalProvisionException errorInUserCode(
+ Throwable cause, String messageFormat, Object... arguments) {
+ Collection<Message> messages = Errors.getMessagesFromThrowable(cause);
+ if (!messages.isEmpty()) {
+ // TODO(lukes): it seems like we are dropping some valuable context here..
+ // consider eliminating this special case
+ return new InternalProvisionException(messages);
+ } else {
+ return new InternalProvisionException(Messages.create(cause, messageFormat, arguments));
+ }
+ }
+
+ public static InternalProvisionException subtypeNotProvided(
+ Class<? extends javax.inject.Provider<?>> providerType, Class<?> type) {
+ return create("%s doesn't provide instances of %s.", providerType, type);
+ }
+
+ public static InternalProvisionException errorInProvider(Throwable cause) {
+ return errorInUserCode(cause, "Error in custom provider, %s", cause);
+ }
+
+ public static InternalProvisionException errorInjectingMethod(Throwable cause) {
+ return errorInUserCode(cause, "Error injecting method, %s", cause);
+ }
+
+ public static InternalProvisionException errorInjectingConstructor(Throwable cause) {
+ return errorInUserCode(cause, "Error injecting constructor, %s", cause);
+ }
+
+ public static InternalProvisionException errorInUserInjector(
+ MembersInjector<?> listener, TypeLiteral<?> type, RuntimeException cause) {
+ return errorInUserCode(
+ cause, "Error injecting %s using %s.%n Reason: %s", type, listener, cause);
+ }
+
+ public static InternalProvisionException jitDisabled(Key<?> key) {
+ return create("Explicit bindings are required and %s is not explicitly bound.", key);
+ }
+
+ public static InternalProvisionException errorNotifyingInjectionListener(
+ InjectionListener<?> listener, TypeLiteral<?> type, RuntimeException cause) {
+ return errorInUserCode(
+ cause, "Error notifying InjectionListener %s of %s.%n Reason: %s", listener, type, cause);
+ }
+
+ /**
+ * Returns {@code value} if it is non-null or allowed to be null. Otherwise a message is added and
+ * an {@code InternalProvisionException} is thrown.
+ */
+ static void onNullInjectedIntoNonNullableDependency(Object source, Dependency<?> dependency)
+ throws InternalProvisionException {
+ // Hack to allow null parameters to @Provides methods, for backwards compatibility.
+ if (dependency.getInjectionPoint().getMember() instanceof Method) {
+ Method annotated = (Method) dependency.getInjectionPoint().getMember();
+ if (annotated.isAnnotationPresent(Provides.class)) {
+ switch (InternalFlags.getNullableProvidesOption()) {
+ case ERROR:
+ break; // break out & let the below exception happen
+ case IGNORE:
+ return; // user doesn't care about injecting nulls to non-@Nullables.
+ case WARN:
+ // Warn only once, otherwise we spam logs too much.
+ if (warnedDependencies.add(dependency)) {
+ logger.log(
+ Level.WARNING,
+ "Guice injected null into {0} (a {1}), please mark it @Nullable."
+ + " Use -Dguice_check_nullable_provides_params=ERROR to turn this into an"
+ + " error.",
+ new Object[] {
+ Messages.formatParameter(dependency), Messages.convert(dependency.getKey())
+ });
+ }
+ return;
+ }
+ }
+ }
+
+ Object formattedDependency =
+ (dependency.getParameterIndex() != -1)
+ ? Messages.formatParameter(dependency)
+ : StackTraceElements.forMember(dependency.getInjectionPoint().getMember());
+
+ throw InternalProvisionException.create(
+ "null returned by binding at %s%n but %s is not @Nullable", source, formattedDependency)
+ .addSource(source);
+ }
+
+ private final List<Object> sourcesToPrepend = new ArrayList<>();
+ private final ImmutableList<Message> errors;
+
+ private InternalProvisionException(Message error) {
+ this(ImmutableList.of(error));
+ }
+
+ private InternalProvisionException(Iterable<Message> errors) {
+ this.errors = ImmutableList.copyOf(errors);
+ checkArgument(!this.errors.isEmpty(), "Can't create a provision exception with no errors");
+ }
+
+ /**
+ * Prepends the given {@code source} to the stack of binding sources for the errors reported in
+ * this exception.
+ *
+ * <p>See {@link Errors#withSource(Object)}
+ *
+ * <p>It is expected that this method is called as the exception propagates up the stack.
+ *
+ * @param source
+ * @return {@code this}
+ */
+ InternalProvisionException addSource(Object source) {
+ if (source == SourceProvider.UNKNOWN_SOURCE) {
+ return this;
+ }
+ int sz = sourcesToPrepend.size();
+ if (sz > 0 && sourcesToPrepend.get(sz - 1) == source) {
+ // This is for when there are two identical sources added in a row. This behavior is copied
+ // from Errors.withSource where it can happen when an constructor/provider method throws an
+ // exception
+ return this;
+ }
+ sourcesToPrepend.add(source);
+ return this;
+ }
+
+ ImmutableList<Message> getErrors() {
+ ImmutableList.Builder<Message> builder = ImmutableList.builder();
+ // reverse them since sources are added as the exception propagates (so the first source is the
+ // last one added)
+ List<Object> newSources = Lists.reverse(sourcesToPrepend);
+ for (Message error : errors) {
+ builder.add(Messages.mergeSources(newSources, error));
+ }
+ return builder.build();
+ }
+
+ /** Returns this exception convered to a ProvisionException. */
+ public ProvisionException toProvisionException() {
+ return new ProvisionException(getErrors());
+ }
+}
diff --git a/core/src/com/google/inject/internal/LinkedBindingImpl.java b/core/src/com/google/inject/internal/LinkedBindingImpl.java
index 8f833242..f2e1a03b 100644
--- a/core/src/com/google/inject/internal/LinkedBindingImpl.java
+++ b/core/src/com/google/inject/internal/LinkedBindingImpl.java
@@ -16,6 +16,7 @@
package com.google.inject.internal;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
@@ -24,15 +25,19 @@ import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.LinkedKeyBinding;
-
import java.util.Set;
-public final class LinkedBindingImpl<T> extends BindingImpl<T> implements LinkedKeyBinding<T>, HasDependencies {
+public final class LinkedBindingImpl<T> extends BindingImpl<T>
+ implements LinkedKeyBinding<T>, HasDependencies {
final Key<? extends T> targetKey;
- public LinkedBindingImpl(InjectorImpl injector, Key<T> key, Object source,
- InternalFactory<? extends T> internalFactory, Scoping scoping,
+ public LinkedBindingImpl(
+ InjectorImpl injector,
+ Key<T> key,
+ Object source,
+ InternalFactory<? extends T> internalFactory,
+ Scoping scoping,
Key<? extends T> targetKey) {
super(injector, key, source, internalFactory, scoping);
this.targetKey = targetKey;
@@ -43,32 +48,39 @@ public final class LinkedBindingImpl<T> extends BindingImpl<T> implements Linked
this.targetKey = targetKey;
}
+ @Override
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
return visitor.visit(this);
}
+ @Override
public Key<? extends T> getLinkedKey() {
return targetKey;
}
+ @Override
public Set<Dependency<?>> getDependencies() {
return ImmutableSet.<Dependency<?>>of(Dependency.get(targetKey));
}
+ @Override
public BindingImpl<T> withScoping(Scoping scoping) {
return new LinkedBindingImpl<T>(getSource(), getKey(), scoping, targetKey);
}
+ @Override
public BindingImpl<T> withKey(Key<T> key) {
return new LinkedBindingImpl<T>(getSource(), key, getScoping(), targetKey);
}
+ @Override
public void applyTo(Binder binder) {
getScoping().applyTo(binder.withSource(getSource()).bind(getKey()).to(getLinkedKey()));
}
- @Override public String toString() {
- return Objects.toStringHelper(LinkedKeyBinding.class)
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(LinkedKeyBinding.class)
.add("key", getKey())
.add("source", getSource())
.add("scope", getScoping())
@@ -78,11 +90,11 @@ public final class LinkedBindingImpl<T> extends BindingImpl<T> implements Linked
@Override
public boolean equals(Object obj) {
- if(obj instanceof LinkedBindingImpl) {
- LinkedBindingImpl<?> o = (LinkedBindingImpl<?>)obj;
+ if (obj instanceof LinkedBindingImpl) {
+ LinkedBindingImpl<?> o = (LinkedBindingImpl<?>) obj;
return getKey().equals(o.getKey())
- && getScoping().equals(o.getScoping())
- && Objects.equal(targetKey, o.targetKey);
+ && getScoping().equals(o.getScoping())
+ && Objects.equal(targetKey, o.targetKey);
} else {
return false;
}
diff --git a/core/src/com/google/inject/internal/LinkedProviderBindingImpl.java b/core/src/com/google/inject/internal/LinkedProviderBindingImpl.java
index a4a78a58..fa9d7926 100644
--- a/core/src/com/google/inject/internal/LinkedProviderBindingImpl.java
+++ b/core/src/com/google/inject/internal/LinkedProviderBindingImpl.java
@@ -16,6 +16,7 @@
package com.google.inject.internal;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
@@ -24,17 +25,20 @@ import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.ProviderKeyBinding;
-
import java.util.Set;
-final class LinkedProviderBindingImpl<T>
- extends BindingImpl<T> implements ProviderKeyBinding<T>, HasDependencies, DelayedInitialize {
+final class LinkedProviderBindingImpl<T> extends BindingImpl<T>
+ implements ProviderKeyBinding<T>, HasDependencies, DelayedInitialize {
final Key<? extends javax.inject.Provider<? extends T>> providerKey;
final DelayedInitialize delayedInitializer;
- private LinkedProviderBindingImpl(InjectorImpl injector, Key<T> key, Object source,
- InternalFactory<? extends T> internalFactory, Scoping scoping,
+ private LinkedProviderBindingImpl(
+ InjectorImpl injector,
+ Key<T> key,
+ Object source,
+ InternalFactory<? extends T> internalFactory,
+ Scoping scoping,
Key<? extends javax.inject.Provider<? extends T>> providerKey,
DelayedInitialize delayedInitializer) {
super(injector, key, source, internalFactory, scoping);
@@ -42,60 +46,79 @@ final class LinkedProviderBindingImpl<T>
this.delayedInitializer = delayedInitializer;
}
- public LinkedProviderBindingImpl(InjectorImpl injector, Key<T> key, Object source,
- InternalFactory<? extends T> internalFactory, Scoping scoping,
+ public LinkedProviderBindingImpl(
+ InjectorImpl injector,
+ Key<T> key,
+ Object source,
+ InternalFactory<? extends T> internalFactory,
+ Scoping scoping,
Key<? extends javax.inject.Provider<? extends T>> providerKey) {
this(injector, key, source, internalFactory, scoping, providerKey, null);
}
- LinkedProviderBindingImpl(Object source, Key<T> key, Scoping scoping,
+ LinkedProviderBindingImpl(
+ Object source,
+ Key<T> key,
+ Scoping scoping,
Key<? extends javax.inject.Provider<? extends T>> providerKey) {
super(source, key, scoping);
this.providerKey = providerKey;
this.delayedInitializer = null;
}
- static <T> LinkedProviderBindingImpl<T> createWithInitializer(InjectorImpl injector, Key<T> key,
- Object source, InternalFactory<? extends T> internalFactory, Scoping scoping,
+ static <T> LinkedProviderBindingImpl<T> createWithInitializer(
+ InjectorImpl injector,
+ Key<T> key,
+ Object source,
+ InternalFactory<? extends T> internalFactory,
+ Scoping scoping,
Key<? extends javax.inject.Provider<? extends T>> providerKey,
DelayedInitialize delayedInitializer) {
- return new LinkedProviderBindingImpl<T>(injector, key, source, internalFactory, scoping,
- providerKey, delayedInitializer);
+ return new LinkedProviderBindingImpl<T>(
+ injector, key, source, internalFactory, scoping, providerKey, delayedInitializer);
}
+ @Override
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
return visitor.visit(this);
}
+ @Override
public Key<? extends javax.inject.Provider<? extends T>> getProviderKey() {
return providerKey;
}
+ @Override
public void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
if (delayedInitializer != null) {
delayedInitializer.initialize(injector, errors);
}
}
+ @Override
public Set<Dependency<?>> getDependencies() {
return ImmutableSet.<Dependency<?>>of(Dependency.get(providerKey));
}
+ @Override
public BindingImpl<T> withScoping(Scoping scoping) {
return new LinkedProviderBindingImpl<T>(getSource(), getKey(), scoping, providerKey);
}
+ @Override
public BindingImpl<T> withKey(Key<T> key) {
return new LinkedProviderBindingImpl<T>(getSource(), key, getScoping(), providerKey);
}
+ @Override
public void applyTo(Binder binder) {
- getScoping().applyTo(binder.withSource(getSource())
- .bind(getKey()).toProvider(getProviderKey()));
+ getScoping()
+ .applyTo(binder.withSource(getSource()).bind(getKey()).toProvider(getProviderKey()));
}
- @Override public String toString() {
- return Objects.toStringHelper(ProviderKeyBinding.class)
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(ProviderKeyBinding.class)
.add("key", getKey())
.add("source", getSource())
.add("scope", getScoping())
@@ -105,11 +128,11 @@ final class LinkedProviderBindingImpl<T>
@Override
public boolean equals(Object obj) {
- if(obj instanceof LinkedProviderBindingImpl) {
- LinkedProviderBindingImpl<?> o = (LinkedProviderBindingImpl<?>)obj;
+ if (obj instanceof LinkedProviderBindingImpl) {
+ LinkedProviderBindingImpl<?> o = (LinkedProviderBindingImpl<?>) obj;
return getKey().equals(o.getKey())
- && getScoping().equals(o.getScoping())
- && Objects.equal(providerKey, o.providerKey);
+ && getScoping().equals(o.getScoping())
+ && Objects.equal(providerKey, o.providerKey);
} else {
return false;
}
diff --git a/core/src/com/google/inject/internal/ListenerBindingProcessor.java b/core/src/com/google/inject/internal/ListenerBindingProcessor.java
index e8ebed25..e70acb5a 100644
--- a/core/src/com/google/inject/internal/ListenerBindingProcessor.java
+++ b/core/src/com/google/inject/internal/ListenerBindingProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,13 +30,15 @@ final class ListenerBindingProcessor extends AbstractProcessor {
super(errors);
}
- @Override public Boolean visit(TypeListenerBinding binding) {
+ @Override
+ public Boolean visit(TypeListenerBinding binding) {
injector.state.addTypeListener(binding);
return true;
}
-
- @Override public Boolean visit(ProvisionListenerBinding binding) {
+
+ @Override
+ public Boolean visit(ProvisionListenerBinding binding) {
injector.state.addProvisionListener(binding);
return true;
}
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/internal/LookupProcessor.java b/core/src/com/google/inject/internal/LookupProcessor.java
index bf11b833..5e685055 100644
--- a/core/src/com/google/inject/internal/LookupProcessor.java
+++ b/core/src/com/google/inject/internal/LookupProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,10 +33,11 @@ final class LookupProcessor extends AbstractProcessor {
super(errors);
}
- @Override public <T> Boolean visit(MembersInjectorLookup<T> lookup) {
+ @Override
+ public <T> Boolean visit(MembersInjectorLookup<T> lookup) {
try {
- MembersInjector<T> membersInjector
- = injector.membersInjectorStore.get(lookup.getType(), errors);
+ MembersInjector<T> membersInjector =
+ injector.membersInjectorStore.get(lookup.getType(), errors);
lookup.initializeDelegate(membersInjector);
} catch (ErrorsException e) {
errors.merge(e.getErrors()); // TODO: source
@@ -45,7 +46,8 @@ final class LookupProcessor extends AbstractProcessor {
return true;
}
- @Override public <T> Boolean visit(ProviderLookup<T> lookup) {
+ @Override
+ public <T> Boolean visit(ProviderLookup<T> lookup) {
// ensure the provider can be created
try {
Provider<T> provider = injector.getProviderOrThrow(lookup.getDependency(), errors);
diff --git a/core/src/com/google/inject/internal/Lookups.java b/core/src/com/google/inject/internal/Lookups.java
index 2b32c7af..d3e64d8c 100644
--- a/core/src/com/google/inject/internal/Lookups.java
+++ b/core/src/com/google/inject/internal/Lookups.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/core/src/com/google/inject/internal/MembersInjectorImpl.java b/core/src/com/google/inject/internal/MembersInjectorImpl.java
index 498b441b..c1503ead 100644
--- a/core/src/com/google/inject/internal/MembersInjectorImpl.java
+++ b/core/src/com/google/inject/internal/MembersInjectorImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,71 +33,77 @@ import com.google.inject.spi.InjectionPoint;
final class MembersInjectorImpl<T> implements MembersInjector<T> {
private final TypeLiteral<T> typeLiteral;
private final InjectorImpl injector;
- private final ImmutableList<SingleMemberInjector> memberInjectors;
- private final ImmutableSet<MembersInjector<? super T>> userMembersInjectors;
- private final ImmutableSet<InjectionListener<? super T>> injectionListeners;
- /*if[AOP]*/
- private final ImmutableList<MethodAspect> addedAspects;
+ // a null list means empty. Since it is common for many of these lists to be empty we can save
+ // some memory lookups by representing empty as null.
+ /* @Nullable */ private final ImmutableList<SingleMemberInjector> memberInjectors;
+ /* @Nullable */ private final ImmutableList<MembersInjector<? super T>> userMembersInjectors;
+ /* @Nullable */ private final ImmutableList<InjectionListener<? super T>> injectionListeners;
+ /*if[AOP]*//* @Nullable */ private final ImmutableList<MethodAspect> addedAspects;
/*end[AOP]*/
- MembersInjectorImpl(InjectorImpl injector, TypeLiteral<T> typeLiteral,
- EncounterImpl<T> encounter, ImmutableList<SingleMemberInjector> memberInjectors) {
+ MembersInjectorImpl(
+ InjectorImpl injector,
+ TypeLiteral<T> typeLiteral,
+ EncounterImpl<T> encounter,
+ ImmutableList<SingleMemberInjector> memberInjectors) {
this.injector = injector;
this.typeLiteral = typeLiteral;
- this.memberInjectors = memberInjectors;
- this.userMembersInjectors = encounter.getMembersInjectors();
- this.injectionListeners = encounter.getInjectionListeners();
+ this.memberInjectors = memberInjectors.isEmpty() ? null : memberInjectors;
+ this.userMembersInjectors =
+ encounter.getMembersInjectors().isEmpty() ? null : encounter.getMembersInjectors().asList();
+ this.injectionListeners =
+ encounter.getInjectionListeners().isEmpty()
+ ? null
+ : encounter.getInjectionListeners().asList();
/*if[AOP]*/
- this.addedAspects = encounter.getAspects();
+ this.addedAspects = encounter.getAspects().isEmpty() ? null : encounter.getAspects();
/*end[AOP]*/
}
public ImmutableList<SingleMemberInjector> getMemberInjectors() {
- return memberInjectors;
+ return memberInjectors == null ? ImmutableList.<SingleMemberInjector>of() : memberInjectors;
}
+ @Override
public void injectMembers(T instance) {
- Errors errors = new Errors(typeLiteral);
+ TypeLiteral<T> localTypeLiteral = typeLiteral;
try {
- injectAndNotify(instance, errors, null, null, typeLiteral, false);
- } catch (ErrorsException e) {
- errors.merge(e.getErrors());
+ injectAndNotify(instance, null, null, localTypeLiteral, false);
+ } catch (InternalProvisionException ipe) {
+ throw ipe.addSource(localTypeLiteral).toProvisionException();
}
-
- errors.throwProvisionExceptionIfErrorsExist();
}
- void injectAndNotify(final T instance,
- final Errors errors,
+ void injectAndNotify(
+ final T instance,
final Key<T> key, // possibly null!
final ProvisionListenerStackCallback<T> provisionCallback, // possibly null!
final Object source,
- final boolean toolableOnly) throws ErrorsException {
+ final boolean toolableOnly)
+ throws InternalProvisionException {
if (instance == null) {
return;
}
-
- injector.callInContext(new ContextualCallable<Void>() {
- @Override
- public Void call(final InternalContext context) throws ErrorsException {
- context.pushState(key, source);
- try {
- if (provisionCallback != null && provisionCallback.hasListeners()) {
- provisionCallback.provision(errors, context, new ProvisionCallback<T>() {
- @Override public T call() {
- injectMembers(instance, errors, context, toolableOnly);
+ final InternalContext context = injector.enterContext();
+ context.pushState(key, source);
+ try {
+ if (provisionCallback != null && provisionCallback.hasListeners()) {
+ provisionCallback.provision(
+ context,
+ new ProvisionCallback<T>() {
+ @Override
+ public T call() throws InternalProvisionException {
+ injectMembers(instance, context, toolableOnly);
return instance;
}
});
- } else {
- injectMembers(instance, errors, context, toolableOnly);
- }
- } finally {
- context.popState();
- }
- return null;
+ } else {
+ injectMembers(instance, context, toolableOnly);
}
- });
+ } finally {
+ context.popState();
+ context.close();
+ }
// TODO: We *could* notify listeners too here,
// but it's not clear if we want to. There's no way to know
@@ -107,59 +113,80 @@ final class MembersInjectorImpl<T> implements MembersInjector<T> {
// if atleast one InjectionPoint was toolable, in which case
// the above callInContext could return 'true' if it injected
// anything.)
- if(!toolableOnly) {
- notifyListeners(instance, errors);
+ if (!toolableOnly) {
+ notifyListeners(instance);
}
}
- void notifyListeners(T instance, Errors errors) throws ErrorsException {
- int numErrorsBefore = errors.size();
- for (InjectionListener<? super T> injectionListener : injectionListeners) {
+ void notifyListeners(T instance) throws InternalProvisionException {
+ ImmutableList<InjectionListener<? super T>> localInjectionListeners = injectionListeners;
+ if (localInjectionListeners == null) {
+ // no listeners
+ return;
+ }
+ // optimization: use manual for/each to save allocating an iterator here
+ for (int i = 0; i < localInjectionListeners.size(); i++) {
+ InjectionListener<? super T> injectionListener = localInjectionListeners.get(i);
try {
injectionListener.afterInjection(instance);
} catch (RuntimeException e) {
- errors.errorNotifyingInjectionListener(injectionListener, typeLiteral, e);
+ throw InternalProvisionException.errorNotifyingInjectionListener(
+ injectionListener, typeLiteral, e);
}
}
- errors.throwIfNewErrors(numErrorsBefore);
}
- void injectMembers(T t, Errors errors, InternalContext context, boolean toolableOnly) {
- // optimization: use manual for/each to save allocating an iterator here
- for (int i = 0, size = memberInjectors.size(); i < size; i++) {
- SingleMemberInjector injector = memberInjectors.get(i);
- if(!toolableOnly || injector.getInjectionPoint().isToolable()) {
- injector.inject(errors, context, t);
+ void injectMembers(T t, InternalContext context, boolean toolableOnly)
+ throws InternalProvisionException {
+ ImmutableList<SingleMemberInjector> localMembersInjectors = memberInjectors;
+ if (localMembersInjectors != null) {
+ // optimization: use manual for/each to save allocating an iterator here
+ for (int i = 0, size = localMembersInjectors.size(); i < size; i++) {
+ SingleMemberInjector injector = localMembersInjectors.get(i);
+ if (!toolableOnly || injector.getInjectionPoint().isToolable()) {
+ injector.inject(context, t);
+ }
}
}
// TODO: There's no way to know if a user's MembersInjector wants toolable injections.
- if(!toolableOnly) {
- for (MembersInjector<? super T> userMembersInjector : userMembersInjectors) {
- try {
- userMembersInjector.injectMembers(t);
- } catch (RuntimeException e) {
- errors.errorInUserInjector(userMembersInjector, typeLiteral, e);
+ if (!toolableOnly) {
+ ImmutableList<MembersInjector<? super T>> localUsersMembersInjectors = userMembersInjectors;
+ if (localUsersMembersInjectors != null) {
+ // optimization: use manual for/each to save allocating an iterator here
+ for (int i = 0; i < localUsersMembersInjectors.size(); i++) {
+ MembersInjector<? super T> userMembersInjector = localUsersMembersInjectors.get(i);
+ try {
+ userMembersInjector.injectMembers(t);
+ } catch (RuntimeException e) {
+ throw InternalProvisionException.errorInUserInjector(
+ userMembersInjector, typeLiteral, e);
+ }
}
}
}
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "MembersInjector<" + typeLiteral + ">";
}
public ImmutableSet<InjectionPoint> getInjectionPoints() {
- ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder();
- for (SingleMemberInjector memberInjector : memberInjectors) {
- builder.add(memberInjector.getInjectionPoint());
+ ImmutableList<SingleMemberInjector> localMemberInjectors = memberInjectors;
+ if (localMemberInjectors != null) {
+ ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder();
+ for (SingleMemberInjector memberInjector : localMemberInjectors) {
+ builder.add(memberInjector.getInjectionPoint());
+ }
+ return builder.build();
}
- return builder.build();
+ return ImmutableSet.of();
}
/*if[AOP]*/
public ImmutableList<MethodAspect> getAddedAspects() {
- return addedAspects;
+ return addedAspects == null ? ImmutableList.<MethodAspect>of() : addedAspects;
}
/*end[AOP]*/
}
diff --git a/core/src/com/google/inject/internal/MembersInjectorStore.java b/core/src/com/google/inject/internal/MembersInjectorStore.java
index 8e2acdd0..6328902d 100644
--- a/core/src/com/google/inject/internal/MembersInjectorStore.java
+++ b/core/src/com/google/inject/internal/MembersInjectorStore.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,7 +24,6 @@ import com.google.inject.TypeLiteral;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.TypeListener;
import com.google.inject.spi.TypeListenerBinding;
-
import java.lang.reflect.Field;
import java.util.List;
import java.util.Set;
@@ -38,16 +37,16 @@ final class MembersInjectorStore {
private final InjectorImpl injector;
private final ImmutableList<TypeListenerBinding> typeListenerBindings;
- private final FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>> cache
- = new FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>>() {
- @Override protected MembersInjectorImpl<?> create(TypeLiteral<?> type, Errors errors)
- throws ErrorsException {
- return createWithListeners(type, errors);
- }
- };
+ private final FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>> cache =
+ new FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>>() {
+ @Override
+ protected MembersInjectorImpl<?> create(TypeLiteral<?> type, Errors errors)
+ throws ErrorsException {
+ return createWithListeners(type, errors);
+ }
+ };
- MembersInjectorStore(InjectorImpl injector,
- List<TypeListenerBinding> typeListenerBindings) {
+ MembersInjectorStore(InjectorImpl injector, List<TypeListenerBinding> typeListenerBindings) {
this.injector = injector;
this.typeListenerBindings = ImmutableList.copyOf(typeListenerBindings);
}
@@ -60,9 +59,7 @@ final class MembersInjectorStore {
return !typeListenerBindings.isEmpty();
}
- /**
- * Returns a new complete members injector with injection listeners registered.
- */
+ /** Returns a new complete members injector with injection listeners registered. */
@SuppressWarnings("unchecked") // the MembersInjector type always agrees with the passed type
public <T> MembersInjectorImpl<T> get(TypeLiteral<T> key, Errors errors) throws ErrorsException {
return (MembersInjectorImpl<T>) cache.get(key, errors);
@@ -74,16 +71,14 @@ final class MembersInjectorStore {
* ImplicitBindingTest#testCircularJitBindingsLeaveNoResidue and
* #testInstancesRequestingProvidersForThemselvesWithChildInjectors for examples of when this is
* necessary.)
- *
- * Returns true if the type was stored in the cache, false otherwise.
+ *
+ * <p>Returns true if the type was stored in the cache, false otherwise.
*/
boolean remove(TypeLiteral<?> type) {
return cache.remove(type);
}
- /**
- * Creates a new members injector and attaches both injection listeners and method aspects.
- */
+ /** Creates a new members injector and attaches both injection listeners and method aspects. */
private <T> MembersInjectorImpl<T> createWithListeners(TypeLiteral<T> type, Errors errors)
throws ErrorsException {
int numErrorsBefore = errors.size();
@@ -98,7 +93,7 @@ final class MembersInjectorStore {
ImmutableList<SingleMemberInjector> injectors = getInjectors(injectionPoints, errors);
errors.throwIfNewErrors(numErrorsBefore);
- EncounterImpl<T> encounter = new EncounterImpl<T>(errors, injector.lookups);
+ EncounterImpl<T> encounter = new EncounterImpl<>(errors, injector.lookups);
Set<TypeListener> alreadySeenListeners = Sets.newHashSet();
for (TypeListenerBinding binding : typeListenerBindings) {
TypeListener typeListener = binding.getListener();
@@ -117,20 +112,20 @@ final class MembersInjectorStore {
return new MembersInjectorImpl<T>(injector, type, encounter, injectors);
}
- /**
- * Returns the injectors for the specified injection points.
- */
+ /** Returns the injectors for the specified injection points. */
ImmutableList<SingleMemberInjector> getInjectors(
Set<InjectionPoint> injectionPoints, Errors errors) {
List<SingleMemberInjector> injectors = Lists.newArrayList();
for (InjectionPoint injectionPoint : injectionPoints) {
try {
- Errors errorsForMember = injectionPoint.isOptional()
- ? new Errors(injectionPoint)
- : errors.withSource(injectionPoint);
- SingleMemberInjector injector = injectionPoint.getMember() instanceof Field
- ? new SingleFieldInjector(this.injector, injectionPoint, errorsForMember)
- : new SingleMethodInjector(this.injector, injectionPoint, errorsForMember);
+ Errors errorsForMember =
+ injectionPoint.isOptional()
+ ? new Errors(injectionPoint)
+ : errors.withSource(injectionPoint);
+ SingleMemberInjector injector =
+ injectionPoint.getMember() instanceof Field
+ ? new SingleFieldInjector(this.injector, injectionPoint, errorsForMember)
+ : new SingleMethodInjector(this.injector, injectionPoint, errorsForMember);
injectors.add(injector);
} catch (ErrorsException ignoredForNow) {
// ignored for now
diff --git a/core/src/com/google/inject/internal/MessageProcessor.java b/core/src/com/google/inject/internal/MessageProcessor.java
index d7c607b1..cb9be021 100644
--- a/core/src/com/google/inject/internal/MessageProcessor.java
+++ b/core/src/com/google/inject/internal/MessageProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,6 @@ package com.google.inject.internal;
import com.google.inject.Guice;
import com.google.inject.spi.Message;
-
import java.util.logging.Level;
import java.util.logging.Logger;
@@ -36,10 +35,12 @@ final class MessageProcessor extends AbstractProcessor {
super(errors);
}
- @Override public Boolean visit(Message message) {
+ @Override
+ public Boolean visit(Message message) {
if (message.getCause() != null) {
String rootMessage = getRootMessage(message.getCause());
- logger.log(Level.INFO,
+ logger.log(
+ Level.INFO,
"An exception was caught and reported. Message: " + rootMessage,
message.getCause());
}
diff --git a/core/src/com/google/inject/internal/Messages.java b/core/src/com/google/inject/internal/Messages.java
new file mode 100644
index 00000000..2c80ab23
--- /dev/null
+++ b/core/src/com/google/inject/internal/Messages.java
@@ -0,0 +1,401 @@
+/*
+ * Copyright (C) 2017 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.internal;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.base.Equivalence;
+import com.google.common.base.Objects;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+import com.google.inject.internal.util.Classes;
+import com.google.inject.internal.util.StackTraceElements;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.ElementSource;
+import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.Message;
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Formatter;
+import java.util.List;
+import java.util.Map;
+
+/** Utility methods for {@link Message} objects */
+public final class Messages {
+ private Messages() {}
+
+ /** Prepends the list of sources to the given {@link Message} */
+ static Message mergeSources(List<Object> sources, Message message) {
+ List<Object> messageSources = message.getSources();
+ // It is possible that the end of getSources() and the beginning of message.getSources() are
+ // equivalent, in this case we should drop the repeated source when joining the lists. The
+ // most likely scenario where this would happen is when a scoped binding throws an exception,
+ // due to the fact that InternalFactoryToProviderAdapter applies the binding source when
+ // merging errors.
+ if (!sources.isEmpty()
+ && !messageSources.isEmpty()
+ && Objects.equal(messageSources.get(0), sources.get(sources.size() - 1))) {
+ messageSources = messageSources.subList(1, messageSources.size());
+ }
+ return new Message(
+ ImmutableList.builder().addAll(sources).addAll(messageSources).build(),
+ message.getMessage(),
+ message.getCause());
+ }
+
+ /**
+ * Calls {@link String#format} after converting the arguments using some standard guice formatting
+ * for {@link Key}, {@link Class} and {@link Member} objects.
+ */
+ public static String format(String messageFormat, Object... arguments) {
+ for (int i = 0; i < arguments.length; i++) {
+ arguments[i] = convert(arguments[i]);
+ }
+ return String.format(messageFormat, arguments);
+ }
+
+ /** Returns the formatted message for an exception with the specified messages. */
+ public static String formatMessages(String heading, Collection<Message> errorMessages) {
+ Formatter fmt = new Formatter().format(heading).format(":%n%n");
+ int index = 1;
+ boolean displayCauses = getOnlyCause(errorMessages) == null;
+
+ Map<Equivalence.Wrapper<Throwable>, Integer> causes = Maps.newHashMap();
+ for (Message errorMessage : errorMessages) {
+ int thisIdx = index++;
+ fmt.format("%s) %s%n", thisIdx, errorMessage.getMessage());
+
+ List<Object> dependencies = errorMessage.getSources();
+ for (int i = dependencies.size() - 1; i >= 0; i--) {
+ Object source = dependencies.get(i);
+ formatSource(fmt, source);
+ }
+
+ Throwable cause = errorMessage.getCause();
+ if (displayCauses && cause != null) {
+ Equivalence.Wrapper<Throwable> causeEquivalence = ThrowableEquivalence.INSTANCE.wrap(cause);
+ if (!causes.containsKey(causeEquivalence)) {
+ causes.put(causeEquivalence, thisIdx);
+ fmt.format("Caused by: %s", Throwables.getStackTraceAsString(cause));
+ } else {
+ int causeIdx = causes.get(causeEquivalence);
+ fmt.format(
+ "Caused by: %s (same stack trace as error #%s)",
+ cause.getClass().getName(), causeIdx);
+ }
+ }
+
+ fmt.format("%n");
+ }
+
+ if (errorMessages.size() == 1) {
+ fmt.format("1 error");
+ } else {
+ fmt.format("%s errors", errorMessages.size());
+ }
+
+ return fmt.toString();
+ }
+
+ /**
+ * Creates a new Message without a cause.
+ *
+ * @param messageFormat Format string
+ * @param arguments format string arguments
+ */
+ public static Message create(String messageFormat, Object... arguments) {
+ return create(null, messageFormat, arguments);
+ }
+
+ /**
+ * Creates a new Message with the given cause.
+ *
+ * @param cause The exception that caused the error
+ * @param messageFormat Format string
+ * @param arguments format string arguments
+ */
+ public static Message create(Throwable cause, String messageFormat, Object... arguments) {
+ return create(cause, ImmutableList.of(), messageFormat, arguments);
+ }
+
+ /**
+ * Creates a new Message with the given cause and a binding source stack.
+ *
+ * @param cause The exception that caused the error
+ * @param sources The binding sources for the source stack
+ * @param messageFormat Format string
+ * @param arguments format string arguments
+ */
+ public static Message create(
+ Throwable cause, List<Object> sources, String messageFormat, Object... arguments) {
+ String message = format(messageFormat, arguments);
+ return new Message(sources, message, cause);
+ }
+
+ /** Formats an object in a user friendly way. */
+ static Object convert(Object o) {
+ ElementSource source = null;
+ if (o instanceof ElementSource) {
+ source = (ElementSource) o;
+ o = source.getDeclaringSource();
+ }
+ return convert(o, source);
+ }
+
+ static Object convert(Object o, ElementSource source) {
+ for (Converter<?> converter : converters) {
+ if (converter.appliesTo(o)) {
+ return appendModules(converter.convert(o), source);
+ }
+ }
+ return appendModules(o, source);
+ }
+
+ private static Object appendModules(Object source, ElementSource elementSource) {
+ String modules = moduleSourceString(elementSource);
+ if (modules.length() == 0) {
+ return source;
+ } else {
+ return source + modules;
+ }
+ }
+
+ private static String moduleSourceString(ElementSource elementSource) {
+ // if we only have one module (or don't know what they are), then don't bother
+ // reporting it, because the source already is going to report exactly that module.
+ if (elementSource == null) {
+ return "";
+ }
+ List<String> modules = Lists.newArrayList(elementSource.getModuleClassNames());
+ // Insert any original element sources w/ module info into the path.
+ while (elementSource.getOriginalElementSource() != null) {
+ elementSource = elementSource.getOriginalElementSource();
+ modules.addAll(0, elementSource.getModuleClassNames());
+ }
+ if (modules.size() <= 1) {
+ return "";
+ }
+
+ // Ideally we'd do:
+ // return Joiner.on(" -> ")
+ // .appendTo(new StringBuilder(" (via modules: "), Lists.reverse(modules))
+ // .append(")").toString();
+ // ... but for some reason we can't find Lists.reverse, so do it the boring way.
+ StringBuilder builder = new StringBuilder(" (via modules: ");
+ for (int i = modules.size() - 1; i >= 0; i--) {
+ builder.append(modules.get(i));
+ if (i != 0) {
+ builder.append(" -> ");
+ }
+ }
+ builder.append(")");
+ return builder.toString();
+ }
+
+ static void formatSource(Formatter formatter, Object source) {
+ ElementSource elementSource = null;
+ if (source instanceof ElementSource) {
+ elementSource = (ElementSource) source;
+ source = elementSource.getDeclaringSource();
+ }
+ formatSource(formatter, source, elementSource);
+ }
+
+ static void formatSource(Formatter formatter, Object source, ElementSource elementSource) {
+ String modules = moduleSourceString(elementSource);
+ if (source instanceof Dependency) {
+ Dependency<?> dependency = (Dependency<?>) source;
+ InjectionPoint injectionPoint = dependency.getInjectionPoint();
+ if (injectionPoint != null) {
+ formatInjectionPoint(formatter, dependency, injectionPoint, elementSource);
+ } else {
+ formatSource(formatter, dependency.getKey(), elementSource);
+ }
+
+ } else if (source instanceof InjectionPoint) {
+ formatInjectionPoint(formatter, null, (InjectionPoint) source, elementSource);
+
+ } else if (source instanceof Class) {
+ formatter.format(" at %s%s%n", StackTraceElements.forType((Class<?>) source), modules);
+
+ } else if (source instanceof Member) {
+ formatter.format(" at %s%s%n", StackTraceElements.forMember((Member) source), modules);
+
+ } else if (source instanceof TypeLiteral) {
+ formatter.format(" while locating %s%s%n", source, modules);
+
+ } else if (source instanceof Key) {
+ Key<?> key = (Key<?>) source;
+ formatter.format(" while locating %s%n", convert(key, elementSource));
+
+ } else if (source instanceof Thread) {
+ formatter.format(" in thread %s%n", source);
+
+ } else {
+ formatter.format(" at %s%s%n", source, modules);
+ }
+ }
+
+ private static void formatInjectionPoint(
+ Formatter formatter,
+ Dependency<?> dependency,
+ InjectionPoint injectionPoint,
+ ElementSource elementSource) {
+ Member member = injectionPoint.getMember();
+ Class<? extends Member> memberType = Classes.memberType(member);
+
+ if (memberType == Field.class) {
+ dependency = injectionPoint.getDependencies().get(0);
+ formatter.format(" while locating %s%n", convert(dependency.getKey(), elementSource));
+ formatter.format(" for field at %s%n", StackTraceElements.forMember(member));
+
+ } else if (dependency != null) {
+ formatter.format(" while locating %s%n", convert(dependency.getKey(), elementSource));
+ formatter.format(" for %s%n", formatParameter(dependency));
+
+ } else {
+ formatSource(formatter, injectionPoint.getMember());
+ }
+ }
+
+ static String formatParameter(Dependency<?> dependency) {
+ int ordinal = dependency.getParameterIndex() + 1;
+ return String.format(
+ "the %s%s parameter of %s",
+ ordinal,
+ getOrdinalSuffix(ordinal),
+ StackTraceElements.forMember(dependency.getInjectionPoint().getMember()));
+ }
+
+ /**
+ * Maps {@code 1} to the string {@code "1st"} ditto for all non-negative numbers
+ *
+ * @see <a href="https://en.wikipedia.org/wiki/English_numerals#Ordinal_numbers">
+ * https://en.wikipedia.org/wiki/English_numerals#Ordinal_numbers</a>
+ */
+ private static String getOrdinalSuffix(int ordinal) {
+ // negative ordinals don't make sense, we allow zero though because we are programmers
+ checkArgument(ordinal >= 0);
+ if ((ordinal / 10) % 10 == 1) {
+ // all the 'teens' are weird
+ return "th";
+ } else {
+ // could use a lookup table? any better?
+ switch (ordinal % 10) {
+ case 1:
+ return "st";
+ case 2:
+ return "nd";
+ case 3:
+ return "rd";
+ default:
+ return "th";
+ }
+ }
+ }
+
+ private abstract static class Converter<T> {
+
+ final Class<T> type;
+
+ Converter(Class<T> type) {
+ this.type = type;
+ }
+
+ boolean appliesTo(Object o) {
+ return o != null && type.isAssignableFrom(o.getClass());
+ }
+
+ String convert(Object o) {
+ return toString(type.cast(o));
+ }
+
+ abstract String toString(T t);
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"}) // rawtypes aren't avoidable
+ private static final Collection<Converter<?>> converters =
+ ImmutableList.of(
+ new Converter<Class>(Class.class) {
+ @Override
+ public String toString(Class c) {
+ return c.getName();
+ }
+ },
+ new Converter<Member>(Member.class) {
+ @Override
+ public String toString(Member member) {
+ return Classes.toString(member);
+ }
+ },
+ new Converter<Key>(Key.class) {
+ @Override
+ public String toString(Key key) {
+ if (key.getAnnotationType() != null) {
+ return key.getTypeLiteral()
+ + " annotated with "
+ + (key.getAnnotation() != null ? key.getAnnotation() : key.getAnnotationType());
+ } else {
+ return key.getTypeLiteral().toString();
+ }
+ }
+ });
+
+ /**
+ * Returns the cause throwable if there is exactly one cause in {@code messages}. If there are
+ * zero or multiple messages with causes, null is returned.
+ */
+ public static Throwable getOnlyCause(Collection<Message> messages) {
+ Throwable onlyCause = null;
+ for (Message message : messages) {
+ Throwable messageCause = message.getCause();
+ if (messageCause == null) {
+ continue;
+ }
+
+ if (onlyCause != null && !ThrowableEquivalence.INSTANCE.equivalent(onlyCause, messageCause)) {
+ return null;
+ }
+
+ onlyCause = messageCause;
+ }
+
+ return onlyCause;
+ }
+
+ private static final class ThrowableEquivalence extends Equivalence<Throwable> {
+ static final ThrowableEquivalence INSTANCE = new ThrowableEquivalence();
+
+ @Override
+ protected boolean doEquivalent(Throwable a, Throwable b) {
+ return a.getClass().equals(b.getClass())
+ && Objects.equal(a.getMessage(), b.getMessage())
+ && Arrays.equals(a.getStackTrace(), b.getStackTrace())
+ && equivalent(a.getCause(), b.getCause());
+ }
+
+ @Override
+ protected int doHash(Throwable t) {
+ return Objects.hashCode(t.getClass().hashCode(), t.getMessage(), hash(t.getCause()));
+ }
+ }
+}
diff --git a/core/src/com/google/inject/internal/MethodAspect.java b/core/src/com/google/inject/internal/MethodAspect.java
index 7bdf193d..d04175fe 100644
--- a/core/src/com/google/inject/internal/MethodAspect.java
+++ b/core/src/com/google/inject/internal/MethodAspect.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,12 +19,10 @@ package com.google.inject.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.inject.matcher.Matcher;
-
-import org.aopalliance.intercept.MethodInterceptor;
-
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
+import org.aopalliance.intercept.MethodInterceptor;
/**
* Ties a matcher to a method interceptor.
@@ -44,15 +42,19 @@ final class MethodAspect {
* annotatedWith(Transactional.class)}.
* @param interceptors to apply
*/
- MethodAspect(Matcher<? super Class<?>> classMatcher,
- Matcher<? super Method> methodMatcher, List<MethodInterceptor> interceptors) {
+ MethodAspect(
+ Matcher<? super Class<?>> classMatcher,
+ Matcher<? super Method> methodMatcher,
+ List<MethodInterceptor> interceptors) {
this.classMatcher = checkNotNull(classMatcher, "class matcher");
this.methodMatcher = checkNotNull(methodMatcher, "method matcher");
this.interceptors = checkNotNull(interceptors, "interceptors");
}
- MethodAspect(Matcher<? super Class<?>> classMatcher,
- Matcher<? super Method> methodMatcher, MethodInterceptor... interceptors) {
+ MethodAspect(
+ Matcher<? super Class<?>> classMatcher,
+ Matcher<? super Method> methodMatcher,
+ MethodInterceptor... interceptors) {
this(classMatcher, methodMatcher, Arrays.asList(interceptors));
}
diff --git a/core/src/com/google/inject/internal/ModuleAnnotatedMethodScannerProcessor.java b/core/src/com/google/inject/internal/ModuleAnnotatedMethodScannerProcessor.java
index 85c721d8..74c64b00 100644
--- a/core/src/com/google/inject/internal/ModuleAnnotatedMethodScannerProcessor.java
+++ b/core/src/com/google/inject/internal/ModuleAnnotatedMethodScannerProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,7 +29,8 @@ final class ModuleAnnotatedMethodScannerProcessor extends AbstractProcessor {
super(errors);
}
- @Override public Boolean visit(ModuleAnnotatedMethodScannerBinding command) {
+ @Override
+ public Boolean visit(ModuleAnnotatedMethodScannerBinding command) {
injector.state.addScanner(command);
return true;
}
diff --git a/core/src/com/google/inject/internal/MoreTypes.java b/core/src/com/google/inject/internal/MoreTypes.java
index bdf6029a..11e6ab32 100644
--- a/core/src/com/google/inject/internal/MoreTypes.java
+++ b/core/src/com/google/inject/internal/MoreTypes.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package com.google.inject.internal;
import static com.google.common.base.Preconditions.checkArgument;
@@ -26,7 +25,6 @@ import com.google.inject.ConfigurationException;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import com.google.inject.util.Types;
-
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
@@ -36,12 +34,10 @@ import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
-import java.util.Map;
import java.util.NoSuchElementException;
/**
- * Static methods for working with types that we aren't publishing in the
- * public {@code Types} API.
+ * Static methods for working with types that we aren't publishing in the public {@code Types} API.
*
* @author jessewilson@google.com (Jesse Wilson)
*/
@@ -51,8 +47,8 @@ public class MoreTypes {
private MoreTypes() {}
- private static final Map<TypeLiteral<?>, TypeLiteral<?>> PRIMITIVE_TO_WRAPPER
- = new ImmutableMap.Builder<TypeLiteral<?>, TypeLiteral<?>>()
+ private static final ImmutableMap<TypeLiteral<?>, TypeLiteral<?>> PRIMITIVE_TO_WRAPPER =
+ new ImmutableMap.Builder<TypeLiteral<?>, TypeLiteral<?>>()
.put(TypeLiteral.get(boolean.class), TypeLiteral.get(Boolean.class))
.put(TypeLiteral.get(byte.class), TypeLiteral.get(Byte.class))
.put(TypeLiteral.get(short.class), TypeLiteral.get(Short.class))
@@ -65,13 +61,12 @@ public class MoreTypes {
.build();
/**
- * Returns a key that doesn't hold any references to parent classes.
- * This is necessary for anonymous keys, so ensure we don't hold a ref
- * to the containing module (or class) forever.
+ * Returns a key that doesn't hold any references to parent classes. This is necessary for
+ * anonymous keys, so ensure we don't hold a ref to the containing module (or class) forever.
*/
public static <T> Key<T> canonicalizeKey(Key<T> key) {
// If we know this isn't a subclass, return as-is.
- // Otherwise, recreate the key to avoid the subclass
+ // Otherwise, recreate the key to avoid the subclass
if (key.getClass() == Key.class) {
return key;
} else if (key.getAnnotation() != null) {
@@ -106,8 +101,9 @@ public class MoreTypes {
// the following casts are generally unsafe, but com.google.inject.Provider extends
// javax.inject.Provider and is covariant
@SuppressWarnings("unchecked")
- TypeLiteral<T> guiceProviderType = (TypeLiteral<T>) TypeLiteral.get(
- Types.providerOf(parameterizedType.getActualTypeArguments()[0]));
+ TypeLiteral<T> guiceProviderType =
+ (TypeLiteral<T>)
+ TypeLiteral.get(Types.providerOf(parameterizedType.getActualTypeArguments()[0]));
return guiceProviderType;
}
@@ -129,9 +125,7 @@ public class MoreTypes {
return recreated;
}
- /**
- * Returns true if {@code type} is free from type variables.
- */
+ /** Returns true if {@code type} is free from type variables. */
private static boolean isFullySpecified(Type type) {
if (type instanceof Class) {
return true;
@@ -139,7 +133,7 @@ public class MoreTypes {
} else if (type instanceof CompositeType) {
return ((CompositeType) type).isFullySpecified();
- } else if (type instanceof TypeVariable){
+ } else if (type instanceof TypeVariable) {
return false;
} else {
@@ -148,9 +142,8 @@ public class MoreTypes {
}
/**
- * Returns a type that is functionally equal but not necessarily equal
- * according to {@link Object#equals(Object) Object.equals()}. The returned
- * type is {@link Serializable}.
+ * Returns a type that is functionally equal but not necessarily equal according to {@link
+ * Object#equals(Object) Object.equals()}. The returned type is {@link Serializable}.
*/
public static Type canonicalize(Type type) {
if (type instanceof Class) {
@@ -162,8 +155,8 @@ public class MoreTypes {
} else if (type instanceof ParameterizedType) {
ParameterizedType p = (ParameterizedType) type;
- return new ParameterizedTypeImpl(p.getOwnerType(),
- p.getRawType(), p.getActualTypeArguments());
+ return new ParameterizedTypeImpl(
+ p.getOwnerType(), p.getRawType(), p.getActualTypeArguments());
} else if (type instanceof GenericArrayType) {
GenericArrayType g = (GenericArrayType) type;
@@ -191,28 +184,33 @@ public class MoreTypes {
// Neal isn't either but suspects some pathological case related
// to nested classes exists.
Type rawType = parameterizedType.getRawType();
- checkArgument(rawType instanceof Class,
- "Expected a Class, but <%s> is of type %s", type, type.getClass().getName());
+ checkArgument(
+ rawType instanceof Class,
+ "Expected a Class, but <%s> is of type %s",
+ type,
+ type.getClass().getName());
return (Class<?>) rawType;
} else if (type instanceof GenericArrayType) {
- Type componentType = ((GenericArrayType)type).getGenericComponentType();
+ Type componentType = ((GenericArrayType) type).getGenericComponentType();
return Array.newInstance(getRawType(componentType), 0).getClass();
- } else if (type instanceof TypeVariable) {
+ } else if (type instanceof TypeVariable || type instanceof WildcardType) {
// we could use the variable's bounds, but that'll won't work if there are multiple.
- // having a raw type that's more general than necessary is okay
+ // having a raw type that's more general than necessary is okay
return Object.class;
} else {
- throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
- + "GenericArrayType, but <" + type + "> is of type " + type.getClass().getName());
+ throw new IllegalArgumentException(
+ "Expected a Class, ParameterizedType, or "
+ + "GenericArrayType, but <"
+ + type
+ + "> is of type "
+ + type.getClass().getName());
}
}
- /**
- * Returns true if {@code a} and {@code b} are equal.
- */
+ /** Returns true if {@code a} and {@code b} are equal. */
public static boolean equals(Type a, Type b) {
if (a == b) {
// also handles (a == null && b == null)
@@ -278,8 +276,8 @@ public class MoreTypes {
/**
* Returns the generic supertype for {@code type}. For example, given a class {@code IntegerSet},
- * the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the result
- * when the supertype is {@code Collection.class} is {@code Collection<Integer>}.
+ * the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the result when
+ * the supertype is {@code Collection.class} is {@code Collection<Integer>}.
*/
public static Type getGenericSupertype(Type type, Class<?> rawType, Class<?> toResolve) {
if (toResolve == rawType) {
@@ -347,9 +345,7 @@ public class MoreTypes {
*/
private static Class<?> declaringClassOf(TypeVariable typeVariable) {
GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
- return genericDeclaration instanceof Class
- ? (Class<?>) genericDeclaration
- : null;
+ return genericDeclaration instanceof Class ? (Class<?>) genericDeclaration : null;
}
public static class ParameterizedTypeImpl
@@ -372,18 +368,22 @@ public class MoreTypes {
}
}
+ @Override
public Type[] getActualTypeArguments() {
return typeArguments.clone();
}
+ @Override
public Type getRawType() {
return rawType;
}
+ @Override
public Type getOwnerType() {
return ownerType;
}
+ @Override
public boolean isFullySpecified() {
if (ownerType != null && !MoreTypes.isFullySpecified(ownerType)) {
return false;
@@ -402,18 +402,19 @@ public class MoreTypes {
return true;
}
- @Override public boolean equals(Object other) {
+ @Override
+ public boolean equals(Object other) {
return other instanceof ParameterizedType
&& MoreTypes.equals(this, (ParameterizedType) other);
}
- @Override public int hashCode() {
- return Arrays.hashCode(typeArguments)
- ^ rawType.hashCode()
- ^ hashCodeOrZero(ownerType);
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(typeArguments) ^ rawType.hashCode() ^ hashCodeOrZero(ownerType);
}
- @Override public String toString() {
+ @Override
+ public String toString() {
StringBuilder stringBuilder = new StringBuilder(30 * (typeArguments.length + 1));
stringBuilder.append(typeToString(rawType));
@@ -431,10 +432,14 @@ public class MoreTypes {
private static void ensureOwnerType(Type ownerType, Type rawType) {
if (rawType instanceof Class<?>) {
Class rawTypeAsClass = (Class) rawType;
- checkArgument(ownerType != null || rawTypeAsClass.getEnclosingClass() == null,
- "No owner type for enclosed %s", rawType);
- checkArgument(ownerType == null || rawTypeAsClass.getEnclosingClass() != null,
- "Owner type for unenclosed %s", rawType);
+ checkArgument(
+ ownerType != null || rawTypeAsClass.getEnclosingClass() == null,
+ "No owner type for enclosed %s",
+ rawType);
+ checkArgument(
+ ownerType == null || rawTypeAsClass.getEnclosingClass() != null,
+ "Owner type for unenclosed %s",
+ rawType);
}
}
@@ -449,24 +454,28 @@ public class MoreTypes {
this.componentType = canonicalize(componentType);
}
+ @Override
public Type getGenericComponentType() {
return componentType;
}
+ @Override
public boolean isFullySpecified() {
return MoreTypes.isFullySpecified(componentType);
}
- @Override public boolean equals(Object o) {
- return o instanceof GenericArrayType
- && MoreTypes.equals(this, (GenericArrayType) o);
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof GenericArrayType && MoreTypes.equals(this, (GenericArrayType) o);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return componentType.hashCode();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return typeToString(componentType) + "[]";
}
@@ -474,9 +483,9 @@ public class MoreTypes {
}
/**
- * The WildcardType interface supports multiple upper bounds and multiple
- * lower bounds. We only support what the Java 6 language needs - at most one
- * bound. If a lower bound is set, the upper bound must be Object.class.
+ * The WildcardType interface supports multiple upper bounds and multiple lower bounds. We only
+ * support what the Java 6 language needs - at most one bound. If a lower bound is set, the upper
+ * bound must be Object.class.
*/
public static class WildcardTypeImpl implements WildcardType, Serializable, CompositeType {
private final Type upperBound;
@@ -501,31 +510,35 @@ public class MoreTypes {
}
}
+ @Override
public Type[] getUpperBounds() {
- return new Type[] { upperBound };
+ return new Type[] {upperBound};
}
+ @Override
public Type[] getLowerBounds() {
- return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY;
+ return lowerBound != null ? new Type[] {lowerBound} : EMPTY_TYPE_ARRAY;
}
+ @Override
public boolean isFullySpecified() {
return MoreTypes.isFullySpecified(upperBound)
&& (lowerBound == null || MoreTypes.isFullySpecified(lowerBound));
}
- @Override public boolean equals(Object other) {
- return other instanceof WildcardType
- && MoreTypes.equals(this, (WildcardType) other);
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof WildcardType && MoreTypes.equals(this, (WildcardType) other);
}
- @Override public int hashCode() {
- // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds());
- return (lowerBound != null ? 31 + lowerBound.hashCode() : 1)
- ^ (31 + upperBound.hashCode());
+ @Override
+ public int hashCode() {
+ // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds());
+ return (lowerBound != null ? 31 + lowerBound.hashCode() : 1) ^ (31 + upperBound.hashCode());
}
- @Override public String toString() {
+ @Override
+ public String toString() {
if (lowerBound != null) {
return "? super " + typeToString(lowerBound);
} else if (upperBound == Object.class) {
@@ -539,8 +552,11 @@ public class MoreTypes {
}
private static void checkNotPrimitive(Type type, String use) {
- checkArgument(!(type instanceof Class<?>) || !((Class) type).isPrimitive(),
- "Primitive types are not allowed in %s: %s", use, type);
+ checkArgument(
+ !(type instanceof Class<?>) || !((Class) type).isPrimitive(),
+ "Primitive types are not allowed in %s: %s",
+ use,
+ type);
}
/** A type formed from other types, such as arrays, parameterized types or wildcard types */
diff --git a/core/src/com/google/inject/internal/Nullability.java b/core/src/com/google/inject/internal/Nullability.java
index 76f7e765..c8da51de 100644
--- a/core/src/com/google/inject/internal/Nullability.java
+++ b/core/src/com/google/inject/internal/Nullability.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,14 +21,13 @@ import java.lang.annotation.Annotation;
/**
* Whether a member supports null values injected.
*
- * <p>Support for {@code Nullable} annotations in Guice is loose.
- * Any annotation type whose simplename is "Nullable" is sufficient to indicate
- * support for null values injected.
+ * <p>Support for {@code Nullable} annotations in Guice is loose. Any annotation type whose
+ * simplename is "Nullable" is sufficient to indicate support for null values injected.
*
- * <p>This allows support for JSR-305's
- * <a href="http://groups.google.com/group/jsr-305/web/proposed-annotations">
- * javax.annotation.meta.Nullable</a> annotation and IntelliJ IDEA's
- * <a href="http://www.jetbrains.com/idea/documentation/howto.html">
+ * <p>This allows support for JSR-305's <a
+ * href="http://groups.google.com/group/jsr-305/web/proposed-annotations">
+ * javax.annotation.meta.Nullable</a> annotation and IntelliJ IDEA's <a
+ * href="http://www.jetbrains.com/idea/documentation/howto.html">
* org.jetbrains.annotations.Nullable</a>.
*
* @author jessewilson@google.com (Jesse Wilson)
@@ -37,7 +36,7 @@ public class Nullability {
private Nullability() {}
public static boolean allowsNull(Annotation[] annotations) {
- for(Annotation a : annotations) {
+ for (Annotation a : annotations) {
Class<? extends Annotation> type = a.annotationType();
if ("Nullable".equals(type.getSimpleName())) {
return true;
diff --git a/core/src/com/google/inject/internal/PrivateElementProcessor.java b/core/src/com/google/inject/internal/PrivateElementProcessor.java
index 4a641a98..7d45a7dd 100644
--- a/core/src/com/google/inject/internal/PrivateElementProcessor.java
+++ b/core/src/com/google/inject/internal/PrivateElementProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,6 @@ package com.google.inject.internal;
import com.google.common.collect.Lists;
import com.google.inject.spi.PrivateElements;
-
import java.util.List;
/**
@@ -34,10 +33,10 @@ final class PrivateElementProcessor extends AbstractProcessor {
super(errors);
}
- @Override public Boolean visit(PrivateElements privateElements) {
- InjectorShell.Builder builder = new InjectorShell.Builder()
- .parent(injector)
- .privateElements(privateElements);
+ @Override
+ public Boolean visit(PrivateElements privateElements) {
+ InjectorShell.Builder builder =
+ new InjectorShell.Builder().parent(injector).privateElements(privateElements);
injectorShellBuilders.add(builder);
return true;
}
diff --git a/core/src/com/google/inject/internal/PrivateElementsImpl.java b/core/src/com/google/inject/internal/PrivateElementsImpl.java
index 6a3d9158..3ae71ccc 100644
--- a/core/src/com/google/inject/internal/PrivateElementsImpl.java
+++ b/core/src/com/google/inject/internal/PrivateElementsImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
-import com.google.common.base.Objects;
+import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
@@ -32,14 +32,11 @@ import com.google.inject.PrivateBinder;
import com.google.inject.spi.Element;
import com.google.inject.spi.ElementVisitor;
import com.google.inject.spi.PrivateElements;
-
import java.util.List;
import java.util.Map;
import java.util.Set;
-/**
- * @author jessewilson@google.com (Jesse Wilson)
- */
+/** @author jessewilson@google.com (Jesse Wilson) */
public final class PrivateElementsImpl implements PrivateElements {
/*
@@ -58,16 +55,19 @@ public final class PrivateElementsImpl implements PrivateElements {
/** lazily instantiated */
private ImmutableMap<Key<?>, Object> exposedKeysToSources;
+
private Injector injector;
public PrivateElementsImpl(Object source) {
this.source = checkNotNull(source, "source");
}
+ @Override
public Object getSource() {
return source;
}
+ @Override
public List<Element> getElements() {
if (elements == null) {
elements = ImmutableList.copyOf(elementsMutable);
@@ -77,6 +77,7 @@ public final class PrivateElementsImpl implements PrivateElements {
return elements;
}
+ @Override
public Injector getInjector() {
return injector;
}
@@ -86,6 +87,7 @@ public final class PrivateElementsImpl implements PrivateElements {
this.injector = checkNotNull(injector, "injector");
}
+ @Override
public Set<Key<?>> getExposedKeys() {
if (exposedKeysToSources == null) {
Map<Key<?>, Object> exposedKeysToSourcesMutable = Maps.newLinkedHashMap();
@@ -99,6 +101,7 @@ public final class PrivateElementsImpl implements PrivateElements {
return exposedKeysToSources.keySet();
}
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
@@ -111,6 +114,7 @@ public final class PrivateElementsImpl implements PrivateElements {
exposureBuilders.add(exposureBuilder);
}
+ @Override
public void applyTo(Binder binder) {
PrivateBinder privateBinder = binder.withSource(source).newPrivateBinder();
@@ -124,6 +128,7 @@ public final class PrivateElementsImpl implements PrivateElements {
}
}
+ @Override
public Object getExposedSource(Key<?> key) {
getExposedKeys(); // ensure exposedKeysToSources is populated
Object source = exposedKeysToSources.get(key);
@@ -131,8 +136,9 @@ public final class PrivateElementsImpl implements PrivateElements {
return source;
}
- @Override public String toString() {
- return Objects.toStringHelper(PrivateElements.class)
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(PrivateElements.class)
.add("exposedKeys", getExposedKeys())
.add("source", getSource())
.toString();
diff --git a/core/src/com/google/inject/internal/ProcessedBindingData.java b/core/src/com/google/inject/internal/ProcessedBindingData.java
index 8cd26027..86a26c60 100644
--- a/core/src/com/google/inject/internal/ProcessedBindingData.java
+++ b/core/src/com/google/inject/internal/ProcessedBindingData.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,38 +17,58 @@
package com.google.inject.internal;
import com.google.common.collect.Lists;
-
import java.util.List;
/**
- * Keeps track of creation listeners & uninitialized bindings,
- * so they can be processed after bindings are recorded.
- *
+ * Keeps track of creation listeners & uninitialized bindings, so they can be processed after
+ * bindings are recorded.
+ *
* @author sameb@google.com (Sam Berlin)
*/
class ProcessedBindingData {
-
+
private final List<CreationListener> creationListeners = Lists.newArrayList();
private final List<Runnable> uninitializedBindings = Lists.newArrayList();
-
+ private final List<Runnable> delayedUninitializedBindings = Lists.newArrayList();
+
void addCreationListener(CreationListener listener) {
creationListeners.add(listener);
}
-
+
void addUninitializedBinding(Runnable runnable) {
uninitializedBindings.add(runnable);
}
-
+
+ void addDelayedUninitializedBinding(Runnable runnable) {
+ delayedUninitializedBindings.add(runnable);
+ }
+
+ /** Initialize bindings. This may be done eagerly */
void initializeBindings() {
for (Runnable initializer : uninitializedBindings) {
initializer.run();
}
}
+ /**
+ * Runs creation listeners.
+ *
+ * <p>TODO(lukes): figure out exactly why this case exists.
+ */
void runCreationListeners(Errors errors) {
for (CreationListener creationListener : creationListeners) {
creationListener.notify(errors);
}
}
+ /**
+ * Initialized bindings that need to be delayed until after all injection points and other
+ * bindings are processed. The main current usecase for this is resolving Optional dependencies
+ * for OptionalBinder bindings.
+ */
+ void initializeDelayedBindings() {
+ for (Runnable initializer : delayedUninitializedBindings) {
+ initializer.run();
+ }
+ }
}
diff --git a/core/src/com/google/inject/internal/ProvidedByInternalFactory.java b/core/src/com/google/inject/internal/ProvidedByInternalFactory.java
index 1591c508..9d67374d 100644
--- a/core/src/com/google/inject/internal/ProvidedByInternalFactory.java
+++ b/core/src/com/google/inject/internal/ProvidedByInternalFactory.java
@@ -14,79 +14,85 @@
* limitations under the License.
*/
-
package com.google.inject.internal;
-import static com.google.common.base.Preconditions.checkState;
-
import com.google.inject.Key;
import com.google.inject.ProvidedBy;
-import com.google.inject.Provider;
import com.google.inject.internal.InjectorImpl.JitLimitation;
import com.google.inject.spi.Dependency;
+import javax.inject.Provider;
/**
* An {@link InternalFactory} for {@literal @}{@link ProvidedBy} bindings.
- *
+ *
* @author sameb@google.com (Sam Berlin)
*/
-class ProvidedByInternalFactory<T> extends ProviderInternalFactory<T>
- implements DelayedInitialize {
-
+class ProvidedByInternalFactory<T> extends ProviderInternalFactory<T> implements DelayedInitialize {
+
private final Class<?> rawType;
private final Class<? extends Provider<?>> providerType;
private final Key<? extends Provider<T>> providerKey;
private BindingImpl<? extends Provider<T>> providerBinding;
private ProvisionListenerStackCallback<T> provisionCallback;
-
+
ProvidedByInternalFactory(
Class<?> rawType,
Class<? extends Provider<?>> providerType,
Key<? extends Provider<T>> providerKey) {
super(providerKey);
this.rawType = rawType;
- this.providerType = providerType;
+ this.providerType = providerType;
this.providerKey = providerKey;
}
-
+
void setProvisionListenerCallback(ProvisionListenerStackCallback<T> listener) {
provisionCallback = listener;
}
-
+
+ @Override
public void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
providerBinding =
injector.getBindingOrThrow(providerKey, errors, JitLimitation.NEW_OR_EXISTING_JIT);
}
- public T get(Errors errors, InternalContext context, Dependency dependency, boolean linked)
- throws ErrorsException {
- checkState(providerBinding != null, "not initialized");
-
- context.pushState(providerKey, providerBinding.getSource());
+ @Override
+ public T get(InternalContext context, Dependency<?> dependency, boolean linked)
+ throws InternalProvisionException {
+ BindingImpl<? extends Provider<T>> localProviderBinding = providerBinding;
+ if (localProviderBinding == null) {
+ throw new IllegalStateException("not initialized");
+ }
+ Key<? extends Provider<T>> localProviderKey = providerKey;
+ context.pushState(localProviderKey, localProviderBinding.getSource());
+
try {
- errors = errors.withSource(providerKey);
- Provider<? extends T> provider = providerBinding.getInternalFactory().get(
- errors, context, dependency, true);
- return circularGet(provider, errors, context, dependency, provisionCallback);
- } finally {
- context.popState();
+ Provider<? extends T> provider =
+ localProviderBinding.getInternalFactory().get(context, dependency, true);
+ return circularGet(provider, context, dependency, provisionCallback);
+ } catch (InternalProvisionException ipe) {
+ throw ipe.addSource(localProviderKey);
+ } finally {
+ context.popState();
+
}
}
-
+
@Override
- protected T provision(javax.inject.Provider<? extends T> provider, Errors errors,
- Dependency<?> dependency, ConstructionContext<T> constructionContext)
- throws ErrorsException {
+ protected T provision(
+ javax.inject.Provider<? extends T> provider,
+ Dependency<?> dependency,
+ ConstructionContext<T> constructionContext)
+ throws InternalProvisionException {
try {
- Object o = super.provision(provider, errors, dependency, constructionContext);
+ Object o = super.provision(provider, dependency, constructionContext);
if (o != null && !rawType.isInstance(o)) {
- throw errors.subtypeNotProvided(providerType, rawType).toException();
+ throw InternalProvisionException.subtypeNotProvided(providerType, rawType);
}
@SuppressWarnings("unchecked") // protected by isInstance() check above
T t = (T) o;
return t;
} catch (RuntimeException e) {
- throw errors.errorInProvider(e).toException();
+ throw InternalProvisionException.errorInProvider(e).addSource(source);
}
}
}
diff --git a/core/src/com/google/inject/internal/ProviderInstanceBindingImpl.java b/core/src/com/google/inject/internal/ProviderInstanceBindingImpl.java
index f254b418..8db5a3e9 100644
--- a/core/src/com/google/inject/internal/ProviderInstanceBindingImpl.java
+++ b/core/src/com/google/inject/internal/ProviderInstanceBindingImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +16,7 @@
package com.google.inject.internal;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
@@ -28,17 +29,19 @@ import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.ProviderWithExtensionVisitor;
import com.google.inject.util.Providers;
-
import java.util.Set;
-final class ProviderInstanceBindingImpl<T> extends BindingImpl<T>
- implements ProviderInstanceBinding<T> {
+class ProviderInstanceBindingImpl<T> extends BindingImpl<T> implements ProviderInstanceBinding<T> {
final javax.inject.Provider<? extends T> providerInstance;
final ImmutableSet<InjectionPoint> injectionPoints;
- public ProviderInstanceBindingImpl(InjectorImpl injector, Key<T> key,
- Object source, InternalFactory<? extends T> internalFactory, Scoping scoping,
+ public ProviderInstanceBindingImpl(
+ InjectorImpl injector,
+ Key<T> key,
+ Object source,
+ InternalFactory<? extends T> internalFactory,
+ Scoping scoping,
javax.inject.Provider<? extends T> providerInstance,
Set<InjectionPoint> injectionPoints) {
super(injector, key, source, internalFactory, scoping);
@@ -46,16 +49,21 @@ final class ProviderInstanceBindingImpl<T> extends BindingImpl<T>
this.injectionPoints = ImmutableSet.copyOf(injectionPoints);
}
- public ProviderInstanceBindingImpl(Object source, Key<T> key, Scoping scoping,
- Set<InjectionPoint> injectionPoints, javax.inject.Provider<? extends T> providerInstance) {
+ public ProviderInstanceBindingImpl(
+ Object source,
+ Key<T> key,
+ Scoping scoping,
+ Set<InjectionPoint> injectionPoints,
+ javax.inject.Provider<? extends T> providerInstance) {
super(source, key, scoping);
this.injectionPoints = ImmutableSet.copyOf(injectionPoints);
this.providerInstance = providerInstance;
}
+ @Override
@SuppressWarnings("unchecked") // the extension type is always consistent with the provider type
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
- if(providerInstance instanceof ProviderWithExtensionVisitor) {
+ if (providerInstance instanceof ProviderWithExtensionVisitor) {
return ((ProviderWithExtensionVisitor<? extends T>) providerInstance)
.acceptExtensionVisitor(visitor, this);
} else {
@@ -66,39 +74,46 @@ final class ProviderInstanceBindingImpl<T> extends BindingImpl<T>
public Provider<? extends T> getProviderInstance() {
return Providers.guicify(providerInstance);
}
-
+
+ @Override
public javax.inject.Provider<? extends T> getUserSuppliedProvider() {
return providerInstance;
}
+ @Override
public Set<InjectionPoint> getInjectionPoints() {
return injectionPoints;
}
+ @Override
public Set<Dependency<?>> getDependencies() {
return providerInstance instanceof HasDependencies
? ImmutableSet.copyOf(((HasDependencies) providerInstance).getDependencies())
: Dependency.forInjectionPoints(injectionPoints);
}
+ @Override
public BindingImpl<T> withScoping(Scoping scoping) {
return new ProviderInstanceBindingImpl<T>(
getSource(), getKey(), scoping, injectionPoints, providerInstance);
}
+ @Override
public BindingImpl<T> withKey(Key<T> key) {
return new ProviderInstanceBindingImpl<T>(
getSource(), key, getScoping(), injectionPoints, providerInstance);
}
+ @Override
public void applyTo(Binder binder) {
- getScoping().applyTo(
- binder.withSource(getSource()).bind(getKey()).toProvider(getUserSuppliedProvider()));
+ getScoping()
+ .applyTo(
+ binder.withSource(getSource()).bind(getKey()).toProvider(getUserSuppliedProvider()));
}
@Override
public String toString() {
- return Objects.toStringHelper(ProviderInstanceBinding.class)
+ return MoreObjects.toStringHelper(ProviderInstanceBinding.class)
.add("key", getKey())
.add("source", getSource())
.add("scope", getScoping())
@@ -108,11 +123,11 @@ final class ProviderInstanceBindingImpl<T> extends BindingImpl<T>
@Override
public boolean equals(Object obj) {
- if(obj instanceof ProviderInstanceBindingImpl) {
- ProviderInstanceBindingImpl<?> o = (ProviderInstanceBindingImpl<?>)obj;
+ if (obj instanceof ProviderInstanceBindingImpl) {
+ ProviderInstanceBindingImpl<?> o = (ProviderInstanceBindingImpl<?>) obj;
return getKey().equals(o.getKey())
- && getScoping().equals(o.getScoping())
- && Objects.equal(providerInstance, o.providerInstance);
+ && getScoping().equals(o.getScoping())
+ && Objects.equal(providerInstance, o.providerInstance);
} else {
return false;
}
diff --git a/core/src/com/google/inject/internal/ProviderInternalFactory.java b/core/src/com/google/inject/internal/ProviderInternalFactory.java
index 8574535d..0cd6fc2b 100644
--- a/core/src/com/google/inject/internal/ProviderInternalFactory.java
+++ b/core/src/com/google/inject/internal/ProviderInternalFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,57 +14,58 @@
* limitations under the License.
*/
-
package com.google.inject.internal;
import static com.google.common.base.Preconditions.checkNotNull;
import com.google.inject.internal.ProvisionListenerStackCallback.ProvisionCallback;
import com.google.inject.spi.Dependency;
-
import javax.inject.Provider;
/**
- * Base class for InternalFactories that are used by Providers, to handle
- * circular dependencies.
+ * Base class for InternalFactories that are used by Providers, to handle circular dependencies.
*
* @author sameb@google.com (Sam Berlin)
*/
abstract class ProviderInternalFactory<T> implements InternalFactory<T> {
-
+
protected final Object source;
-
+
ProviderInternalFactory(Object source) {
this.source = checkNotNull(source, "source");
}
-
- protected T circularGet(final Provider<? extends T> provider, final Errors errors,
- InternalContext context, final Dependency<?> dependency,
- ProvisionListenerStackCallback<T> provisionCallback)
- throws ErrorsException {
+
+ protected T circularGet(
+ final Provider<? extends T> provider,
+ InternalContext context,
+ final Dependency<?> dependency,
+ /* @Nullable */ ProvisionListenerStackCallback<T> provisionCallback)
+ throws InternalProvisionException {
final ConstructionContext<T> constructionContext = context.getConstructionContext(this);
// We have a circular reference between constructors. Return a proxy.
if (constructionContext.isConstructing()) {
- Class<?> expectedType = dependency.getKey().getTypeLiteral().getRawType();
- // TODO: if we can't proxy this object, can we proxy the other object?
- @SuppressWarnings("unchecked")
- T proxyType = (T) constructionContext.createProxy(
- errors, context.getInjectorOptions(), expectedType);
- return proxyType;
+ Class<?> expectedType = dependency.getKey().getTypeLiteral().getRawType();
+ // TODO: if we can't proxy this object, can we proxy the other object?
+ @SuppressWarnings("unchecked")
+ T proxyType = (T) constructionContext.createProxy(context.getInjectorOptions(), expectedType);
+ return proxyType;
}
// Optimization: Don't go through the callback stack if no one's listening.
constructionContext.startConstruction();
try {
- if (!provisionCallback.hasListeners()) {
- return provision(provider, errors, dependency, constructionContext);
+ if (provisionCallback == null) {
+ return provision(provider, dependency, constructionContext);
} else {
- return provisionCallback.provision(errors, context, new ProvisionCallback<T>() {
- public T call() throws ErrorsException {
- return provision(provider, errors, dependency, constructionContext);
- }
- });
+ return provisionCallback.provision(
+ context,
+ new ProvisionCallback<T>() {
+ @Override
+ public T call() throws InternalProvisionException {
+ return provision(provider, dependency, constructionContext);
+ }
+ });
}
} finally {
constructionContext.removeCurrentReference();
@@ -73,12 +74,18 @@ abstract class ProviderInternalFactory<T> implements InternalFactory<T> {
}
/**
- * Provisions a new instance. Subclasses should override this to catch
- * exceptions & rethrow as ErrorsExceptions.
+ * Provisions a new instance. Subclasses should override this to catch exceptions & rethrow as
+ * ErrorsExceptions.
*/
- protected T provision(Provider<? extends T> provider, Errors errors, Dependency<?> dependency,
- ConstructionContext<T> constructionContext) throws ErrorsException {
- T t = errors.checkForNull(provider.get(), source, dependency);
+ protected T provision(
+ Provider<? extends T> provider,
+ Dependency<?> dependency,
+ ConstructionContext<T> constructionContext)
+ throws InternalProvisionException {
+ T t = provider.get();
+ if (t == null && !dependency.isNullable()) {
+ InternalProvisionException.onNullInjectedIntoNonNullableDependency(source, dependency);
+ }
constructionContext.setProxyDelegates(t);
return t;
}
diff --git a/core/src/com/google/inject/internal/ProviderMethod.java b/core/src/com/google/inject/internal/ProviderMethod.java
index beaf406e..0723252d 100644
--- a/core/src/com/google/inject/internal/ProviderMethod.java
+++ b/core/src/com/google/inject/internal/ProviderMethod.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,15 +17,13 @@
package com.google.inject.internal;
import com.google.common.base.Objects;
-import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
import com.google.inject.Exposed;
import com.google.inject.Key;
import com.google.inject.PrivateBinder;
-import com.google.inject.Provider;
import com.google.inject.Provides;
-import com.google.inject.internal.BytecodeGen.Visibility;
+import com.google.inject.internal.InternalProviderInstanceBindingImpl.InitializationTiming;
import com.google.inject.internal.util.StackTraceElements;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
@@ -34,12 +32,10 @@ import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.ProviderWithExtensionVisitor;
import com.google.inject.spi.ProvidesMethodBinding;
import com.google.inject.spi.ProvidesMethodTargetVisitor;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-import java.util.List;
import java.util.Set;
/**
@@ -47,50 +43,47 @@ import java.util.Set;
*
* @author jessewilson@google.com (Jesse Wilson)
*/
-public abstract class ProviderMethod<T> implements ProviderWithExtensionVisitor<T>, HasDependencies,
- ProvidesMethodBinding<T> {
+public abstract class ProviderMethod<T> extends InternalProviderInstanceBindingImpl.CyclicFactory<T>
+ implements HasDependencies, ProvidesMethodBinding<T>, ProviderWithExtensionVisitor<T> {
/**
* Creates a {@link ProviderMethod}.
*
- * <p>Unless {@code skipFastClassGeneration} is set, this will use
- * {@link net.sf.cglib.reflect.FastClass} to invoke the actual method, since it is significantly
- * faster. However, this will fail if the method is {@code private} or {@code protected}, since
- * fastclass is subject to java access policies.
+ * <p>Unless {@code skipFastClassGeneration} is set, this will use {@link
+ * net.sf.cglib.reflect.FastClass} to invoke the actual method, since it is significantly faster.
+ * However, this will fail if the method is {@code private} or {@code protected}, since fastclass
+ * is subject to java access policies.
*/
- static <T> ProviderMethod<T> create(Key<T> key, Method method, Object instance,
- ImmutableSet<Dependency<?>> dependencies, List<Provider<?>> parameterProviders,
- Class<? extends Annotation> scopeAnnotation, boolean skipFastClassGeneration,
+ static <T> ProviderMethod<T> create(
+ Key<T> key,
+ Method method,
+ Object instance,
+ ImmutableSet<Dependency<?>> dependencies,
+ Class<? extends Annotation> scopeAnnotation,
+ boolean skipFastClassGeneration,
Annotation annotation) {
int modifiers = method.getModifiers();
/*if[AOP]*/
- if (!skipFastClassGeneration && !Modifier.isPrivate(modifiers)
- && !Modifier.isProtected(modifiers)) {
+ if (!skipFastClassGeneration) {
try {
- // We use an index instead of FastMethod to save a stack frame.
- return new FastClassProviderMethod<T>(key,
- method,
- instance,
- dependencies,
- parameterProviders,
- scopeAnnotation,
- annotation);
- } catch (net.sf.cglib.core.CodeGenerationException e) {/* fall-through */}
+ net.sf.cglib.reflect.FastClass fc = BytecodeGen.newFastClassForMember(method);
+ if (fc != null) {
+ return new FastClassProviderMethod<T>(
+ key, fc, method, instance, dependencies, scopeAnnotation, annotation);
+ }
+ } catch (net.sf.cglib.core.CodeGenerationException e) {
+ /* fall-through */
+ }
}
/*end[AOP]*/
- if (!Modifier.isPublic(modifiers) ||
- !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
+ if (!Modifier.isPublic(modifiers)
+ || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
method.setAccessible(true);
}
- return new ReflectionProviderMethod<T>(key,
- method,
- instance,
- dependencies,
- parameterProviders,
- scopeAnnotation,
- annotation);
+ return new ReflectionProviderMethod<T>(
+ key, method, instance, dependencies, scopeAnnotation, annotation);
}
protected final Object instance;
@@ -99,22 +92,30 @@ public abstract class ProviderMethod<T> implements ProviderWithExtensionVisitor<
private final Key<T> key;
private final Class<? extends Annotation> scopeAnnotation;
private final ImmutableSet<Dependency<?>> dependencies;
- private final List<Provider<?>> parameterProviders;
private final boolean exposed;
private final Annotation annotation;
/**
- * @param method the method to invoke. It's return type must be the same type as {@code key}.
+ * Set by {@link #initialize(InjectorImpl, Errors)} so it is always available prior to injection.
*/
- private ProviderMethod(Key<T> key, Method method, Object instance,
- ImmutableSet<Dependency<?>> dependencies, List<Provider<?>> parameterProviders,
- Class<? extends Annotation> scopeAnnotation, Annotation annotation) {
+ private SingleParameterInjector<?>[] parameterInjectors;
+
+ /** @param method the method to invoke. It's return type must be the same type as {@code key}. */
+ private ProviderMethod(
+ Key<T> key,
+ Method method,
+ Object instance,
+ ImmutableSet<Dependency<?>> dependencies,
+ Class<? extends Annotation> scopeAnnotation,
+ Annotation annotation) {
+ // We can be safely initialized eagerly since our bindings must exist statically and it is an
+ // error for them not to.
+ super(InitializationTiming.EAGER);
this.key = key;
this.scopeAnnotation = scopeAnnotation;
this.instance = instance;
this.dependencies = dependencies;
this.method = method;
- this.parameterProviders = parameterProviders;
this.exposed = method.isAnnotationPresent(Exposed.class);
this.annotation = annotation;
}
@@ -133,12 +134,12 @@ public abstract class ProviderMethod<T> implements ProviderWithExtensionVisitor<
public Object getInstance() {
return instance;
}
-
+
@Override
public Object getEnclosingInstance() {
return instance;
}
-
+
@Override
public Annotation getAnnotation() {
return annotation;
@@ -161,43 +162,48 @@ public abstract class ProviderMethod<T> implements ProviderWithExtensionVisitor<
}
@Override
- public T get() {
- Object[] parameters = new Object[parameterProviders.size()];
- for (int i = 0; i < parameters.length; i++) {
- parameters[i] = parameterProviders.get(i).get();
- }
+ void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
+ parameterInjectors = injector.getParametersInjectors(dependencies.asList(), errors);
+ }
+ @Override
+ protected T doProvision(InternalContext context, Dependency<?> dependency)
+ throws InternalProvisionException {
try {
- @SuppressWarnings({ "unchecked", "UnnecessaryLocalVariable" })
- T result = (T) doProvision(parameters);
- return result;
+ T t = doProvision(SingleParameterInjector.getAll(context, parameterInjectors));
+ if (t == null && !dependency.isNullable()) {
+ InternalProvisionException.onNullInjectedIntoNonNullableDependency(getMethod(), dependency);
+ }
+ return t;
} catch (IllegalAccessException e) {
throw new AssertionError(e);
- } catch (InvocationTargetException e) {
- throw Exceptions.rethrowCause(e);
+ } catch (InvocationTargetException userException) {
+ Throwable cause = userException.getCause() != null ? userException.getCause() : userException;
+ throw InternalProvisionException.errorInProvider(cause).addSource(getSource());
}
}
/** Extension point for our subclasses to implement the provisioning strategy. */
- abstract Object doProvision(Object[] parameters)
+ abstract T doProvision(Object[] parameters)
throws IllegalAccessException, InvocationTargetException;
@Override
public Set<Dependency<?>> getDependencies() {
return dependencies;
}
-
+
@Override
@SuppressWarnings("unchecked")
- public <B, V> V acceptExtensionVisitor(BindingTargetVisitor<B, V> visitor,
- ProviderInstanceBinding<? extends B> binding) {
+ public <B, V> V acceptExtensionVisitor(
+ BindingTargetVisitor<B, V> visitor, ProviderInstanceBinding<? extends B> binding) {
if (visitor instanceof ProvidesMethodTargetVisitor) {
- return ((ProvidesMethodTargetVisitor<T, V>)visitor).visit(this);
+ return ((ProvidesMethodTargetVisitor<T, V>) visitor).visit(this);
}
return visitor.visit(binding);
}
- @Override public String toString() {
+ @Override
+ public String toString() {
String annotationString = annotation.toString();
// Show @Provides w/o the com.google.inject prefix.
if (annotation.annotationType() == Provides.class) {
@@ -208,19 +214,19 @@ public abstract class ProviderMethod<T> implements ProviderWithExtensionVisitor<
}
return annotationString + " " + StackTraceElements.forMember(method);
}
-
+
@Override
public boolean equals(Object obj) {
if (obj instanceof ProviderMethod) {
ProviderMethod<?> o = (ProviderMethod<?>) obj;
return method.equals(o.method)
- && instance.equals(o.instance)
- && annotation.equals(o.annotation);
+ && instance.equals(o.instance)
+ && annotation.equals(o.annotation);
} else {
return false;
}
}
-
+
@Override
public int hashCode() {
// Avoid calling hashCode on 'instance', which is a user-object
@@ -238,65 +244,46 @@ public abstract class ProviderMethod<T> implements ProviderWithExtensionVisitor<
final net.sf.cglib.reflect.FastClass fastClass;
final int methodIndex;
- FastClassProviderMethod(Key<T> key,
+ FastClassProviderMethod(
+ Key<T> key,
+ net.sf.cglib.reflect.FastClass fc,
Method method,
Object instance,
ImmutableSet<Dependency<?>> dependencies,
- List<Provider<?>> parameterProviders,
Class<? extends Annotation> scopeAnnotation,
Annotation annotation) {
- super(key,
- method,
- instance,
- dependencies,
- parameterProviders,
- scopeAnnotation,
- annotation);
- // We need to generate a FastClass for the method's class, not the object's class.
- this.fastClass =
- BytecodeGen.newFastClass(method.getDeclaringClass(), Visibility.forMember(method));
- // Use the Signature overload of getIndex because it properly uses return types to identify
- // particular methods. This is normally irrelevant, except in the case of covariant overrides
- // which java implements with a compiler generated bridge method to implement the override.
- this.methodIndex = fastClass.getIndex(
- new net.sf.cglib.core.Signature(
- method.getName(), org.objectweb.asm.Type.getMethodDescriptor(method)));
- Preconditions.checkArgument(this.methodIndex >= 0,
- "Could not find method %s in fast class for class %s",
- method,
- method.getDeclaringClass());
+ super(key, method, instance, dependencies, scopeAnnotation, annotation);
+ this.fastClass = fc;
+ this.methodIndex = fc.getMethod(method).getIndex();
}
- @Override public Object doProvision(Object[] parameters)
+ @SuppressWarnings("unchecked")
+ @Override
+ public T doProvision(Object[] parameters)
throws IllegalAccessException, InvocationTargetException {
- return fastClass.invoke(methodIndex, instance, parameters);
+ return (T) fastClass.invoke(methodIndex, instance, parameters);
}
}
/*end[AOP]*/
/**
- * A {@link ProviderMethod} implementation that invokes the method using normal java reflection.
+ * A {@link ProviderMethod} implementation that invokes the method using normal java reflection.
*/
private static final class ReflectionProviderMethod<T> extends ProviderMethod<T> {
- ReflectionProviderMethod(Key<T> key,
+ ReflectionProviderMethod(
+ Key<T> key,
Method method,
Object instance,
ImmutableSet<Dependency<?>> dependencies,
- List<Provider<?>> parameterProviders,
Class<? extends Annotation> scopeAnnotation,
Annotation annotation) {
- super(key,
- method,
- instance,
- dependencies,
- parameterProviders,
- scopeAnnotation,
- annotation);
+ super(key, method, instance, dependencies, scopeAnnotation, annotation);
}
- @Override Object doProvision(Object[] parameters) throws IllegalAccessException,
- InvocationTargetException {
- return method.invoke(instance, parameters);
+ @SuppressWarnings("unchecked")
+ @Override
+ T doProvision(Object[] parameters) throws IllegalAccessException, InvocationTargetException {
+ return (T) method.invoke(instance, parameters);
}
}
}
diff --git a/core/src/com/google/inject/internal/ProviderMethodsModule.java b/core/src/com/google/inject/internal/ProviderMethodsModule.java
index 7682dab5..a854f73f 100644
--- a/core/src/com/google/inject/internal/ProviderMethodsModule.java
+++ b/core/src/com/google/inject/internal/ProviderMethodsModule.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,30 +18,26 @@ package com.google.inject.internal;
import static com.google.common.base.Preconditions.checkNotNull;
-import com.google.common.base.Optional;
import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.inject.Binder;
import com.google.inject.Key;
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.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;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.List;
-import java.util.Set;
/**
* Creates bindings to methods annotated with {@literal @}{@link Provides}. Use the scope and
@@ -51,61 +47,42 @@ import java.util.Set;
* @author jessewilson@google.com (Jesse Wilson)
*/
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) {
- return key;
- }
-
- @Override
- public Set<? extends Class<? extends Annotation>> annotationClasses() {
- return ImmutableSet.of(Provides.class);
- }
- };
-
private final Object delegate;
private final TypeLiteral<?> typeLiteral;
private final boolean skipFastClassGeneration;
private final ModuleAnnotatedMethodScanner scanner;
- private ProviderMethodsModule(Object delegate, boolean skipFastClassGeneration,
- ModuleAnnotatedMethodScanner scanner) {
+ private ProviderMethodsModule(
+ Object delegate, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner) {
this.delegate = checkNotNull(delegate, "delegate");
this.typeLiteral = TypeLiteral.get(this.delegate.getClass());
this.skipFastClassGeneration = skipFastClassGeneration;
this.scanner = scanner;
}
- /**
- * Returns a module which creates bindings for provider methods from the given module.
- */
+ /** Returns a module which creates bindings for provider methods from the given module. */
public static Module forModule(Module module) {
- return forObject(module, false, PROVIDES_BUILDER);
+ return forObject(module, false, ProvidesMethodScanner.INSTANCE);
}
- /**
- * Returns a module which creates bindings methods in the module that match the scanner.
- */
+ /** Returns a module which creates bindings methods in the module that match the scanner. */
public static Module forModule(Object module, ModuleAnnotatedMethodScanner scanner) {
return forObject(module, false, scanner);
}
/**
- * Returns a module which creates bindings for provider methods from the given object.
- * This is useful notably for <a href="http://code.google.com/p/google-gin/">GIN</a>
+ * Returns a module which creates bindings for provider methods from the given object. This is
+ * useful notably for <a href="http://code.google.com/p/google-gin/">GIN</a>
*
* <p>This will skip bytecode generation for provider methods, since it is assumed that callers
* are only interested in Module metadata.
*/
public static Module forObject(Object object) {
- return forObject(object, true, PROVIDES_BUILDER);
+ return forObject(object, true, ProvidesMethodScanner.INSTANCE);
}
- private static Module forObject(Object object, boolean skipFastClassGeneration,
- ModuleAnnotatedMethodScanner scanner) {
+ private static Module forObject(
+ Object object, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner) {
// avoid infinite recursion, since installing a module always installs itself
if (object instanceof ProviderMethodsModule) {
return Modules.EMPTY_MODULE;
@@ -119,91 +96,115 @@ public final class ProviderMethodsModule implements Module {
}
@Override
- public synchronized void configure(Binder binder) {
+ public void configure(Binder binder) {
for (ProviderMethod<?> providerMethod : getProviderMethods(binder)) {
providerMethod.configure(binder);
}
}
public List<ProviderMethod<?>> getProviderMethods(Binder binder) {
- List<ProviderMethod<?>> result = Lists.newArrayList();
- Multimap<Signature, Method> methodsBySignature = HashMultimap.create();
+ List<ProviderMethod<?>> result = null;
+ // The highest class in the type hierarchy that contained a provider method definition.
+ Class<?> superMostClass = delegate.getClass();
for (Class<?> c = delegate.getClass(); c != Object.class; c = c.getSuperclass()) {
for (Method method : c.getDeclaredMethods()) {
- // private/static methods cannot override or be overridden by other methods, so there is no
- // point in indexing them.
- // Skip synthetic methods and bridge methods since java will automatically generate
- // synthetic overrides in some cases where we don't want to generate an error (e.g.
- // increasing visibility of a subclass).
- if (((method.getModifiers() & (Modifier.PRIVATE | Modifier.STATIC)) == 0)
- && !method.isBridge() && !method.isSynthetic()) {
- methodsBySignature.put(new Signature(method), method);
- }
- Optional<Annotation> annotation = isProvider(binder, method);
- if (annotation.isPresent()) {
- result.add(createProviderMethod(binder, method, annotation.get()));
+ Annotation annotation = getAnnotation(binder, method);
+ if (annotation != null) {
+ if (result == null) {
+ result = Lists.newArrayList();
+ }
+ result.add(createProviderMethod(binder, method, annotation));
+ superMostClass = c;
}
}
}
- // we have found all the providers and now need to identify if any were overridden
- // In the worst case this will have O(n^2) in the number of @Provides methods, but that is only
- // assuming that every method is an override, in general it should be very quick.
- for (ProviderMethod<?> provider : result) {
- Method method = provider.getMethod();
- for (Method matchingSignature : methodsBySignature.get(new Signature(method))) {
- // matching signature is in the same class or a super class, therefore method cannot be
- // overridding it.
- if (matchingSignature.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) {
- continue;
+ if (result == null) {
+ // We didn't find anything
+ return ImmutableList.of();
+ }
+ // We have found some provider methods, now we need to check if any were overridden.
+ // We do this as a separate pass to avoid calculating all the signatures when there are no
+ // provides methods, or when all provides methods are defined in a single class.
+ Multimap<Signature, Method> methodsBySignature = null;
+ // We can stop scanning when we see superMostClass, since no superclass method can override
+ // a method in a subclass. Corrollary, if superMostClass == delegate.getClass(), there can be
+ // no overrides of a provides method.
+ for (Class<?> c = delegate.getClass(); c != superMostClass; c = c.getSuperclass()) {
+ for (Method method : c.getDeclaredMethods()) {
+ if (((method.getModifiers() & (Modifier.PRIVATE | Modifier.STATIC)) == 0)
+ && !method.isBridge()
+ && !method.isSynthetic()) {
+ if (methodsBySignature == null) {
+ methodsBySignature = HashMultimap.create();
+ }
+ methodsBySignature.put(new Signature(typeLiteral, method), method);
}
- // now we know matching signature is in a subtype of method.getDeclaringClass()
- if (overrides(matchingSignature, method)) {
- String annotationString = provider.getAnnotation().annotationType() == Provides.class
- ? "@Provides" : "@" + provider.getAnnotation().annotationType().getCanonicalName();
- binder.addError(
- "Overriding " + annotationString + " methods is not allowed."
- + "\n\t" + annotationString + " method: %s\n\toverridden by: %s",
- method,
- matchingSignature);
- break;
+ }
+ }
+ if (methodsBySignature != null) {
+ // we have found all the signatures and now need to identify if any were overridden
+ // In the worst case this will have O(n^2) in the number of @Provides methods, but that is
+ // only assuming that every method is an override, in general it should be very quick.
+ for (ProviderMethod<?> provider : result) {
+ Method method = provider.getMethod();
+ for (Method matchingSignature :
+ methodsBySignature.get(new Signature(typeLiteral, method))) {
+ // matching signature is in the same class or a super class, therefore method cannot be
+ // overridding it.
+ if (matchingSignature.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) {
+ continue;
+ }
+ // now we know matching signature is in a subtype of method.getDeclaringClass()
+ if (overrides(matchingSignature, method)) {
+ String annotationString =
+ provider.getAnnotation().annotationType() == Provides.class
+ ? "@Provides"
+ : "@" + provider.getAnnotation().annotationType().getCanonicalName();
+ binder.addError(
+ "Overriding "
+ + annotationString
+ + " methods is not allowed."
+ + "\n\t"
+ + annotationString
+ + " method: %s\n\toverridden by: %s",
+ method,
+ matchingSignature);
+ break;
+ }
}
}
}
return result;
}
- /**
- * Returns true if the method is a provider.
- *
- * Synthetic bridge methods are excluded. Starting with JDK 8, javac copies annotations onto
- * bridge methods (which always have erased signatures).
- */
- private Optional<Annotation> isProvider(Binder binder, Method method) {
+ /** Returns the annotation that is claimed by the scanner, or null if there is none. */
+ private Annotation getAnnotation(Binder binder, Method method) {
if (method.isBridge() || method.isSynthetic()) {
- return Optional.absent();
+ return null;
}
Annotation annotation = null;
for (Class<? extends Annotation> annotationClass : scanner.annotationClasses()) {
Annotation foundAnnotation = method.getAnnotation(annotationClass);
if (foundAnnotation != null) {
if (annotation != null) {
- binder.addError("More than one annotation claimed by %s on method %s."
- + " Methods can only have one annotation claimed per scanner.",
+ binder.addError(
+ "More than one annotation claimed by %s on method %s."
+ + " Methods can only have one annotation claimed per scanner.",
scanner, method);
- return Optional.absent();
+ return null;
}
annotation = foundAnnotation;
}
}
- return Optional.fromNullable(annotation);
+ return annotation;
}
- private final class Signature {
+ private static final class Signature {
final Class<?>[] parameters;
final String name;
final int hashCode;
- Signature(Method method) {
+ Signature(TypeLiteral<?> typeLiteral, Method method) {
this.name = method.getName();
// We need to 'resolve' the parameters against the actual class type in case this method uses
// type parameters. This is so we can detect overrides of generic superclass methods where
@@ -219,7 +220,8 @@ public final class ProviderMethodsModule implements Module {
this.hashCode = name.hashCode() + 31 * Arrays.hashCode(parameters);
}
- @Override public boolean equals(Object obj) {
+ @Override
+ public boolean equals(Object obj) {
if (obj instanceof Signature) {
Signature other = (Signature) obj;
return other.name.equals(name) && Arrays.equals(parameters, other.parameters);
@@ -227,7 +229,8 @@ public final class ProviderMethodsModule implements Module {
return false;
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return hashCode;
}
}
@@ -246,34 +249,34 @@ public final class ProviderMethodsModule implements Module {
return a.getDeclaringClass().getPackage().equals(b.getDeclaringClass().getPackage());
}
- private <T> ProviderMethod<T> createProviderMethod(Binder binder, Method method,
- Annotation annotation) {
+ private <T> ProviderMethod<T> createProviderMethod(
+ Binder binder, Method method, Annotation annotation) {
binder = binder.withSource(method);
Errors errors = new Errors(method);
// prepare the parameter providers
InjectionPoint point = InjectionPoint.forMethod(method, typeLiteral);
- List<Dependency<?>> dependencies = point.getDependencies();
- List<Provider<?>> parameterProviders = Lists.newArrayList();
- for (Dependency<?> dependency : point.getDependencies()) {
- parameterProviders.add(binder.getProvider(dependency));
- }
-
@SuppressWarnings("unchecked") // Define T as the method's return type.
TypeLiteral<T> returnType = (TypeLiteral<T>) typeLiteral.getReturnType(method);
Key<T> key = getKey(errors, returnType, method, method.getAnnotations());
try {
key = scanner.prepareMethod(binder, annotation, key, point);
- } catch(Throwable t) {
+ } catch (Throwable t) {
binder.addError(t);
}
- Class<? extends Annotation> scopeAnnotation
- = Annotations.findScopeAnnotation(errors, method.getAnnotations());
+ Class<? extends Annotation> scopeAnnotation =
+ Annotations.findScopeAnnotation(errors, method.getAnnotations());
for (Message message : errors.getMessages()) {
binder.addError(message);
}
- return ProviderMethod.create(key, method, delegate, ImmutableSet.copyOf(dependencies),
- parameterProviders, scopeAnnotation, skipFastClassGeneration, annotation);
+ return ProviderMethod.create(
+ key,
+ method,
+ delegate,
+ ImmutableSet.copyOf(point.getDependencies()),
+ scopeAnnotation,
+ skipFastClassGeneration,
+ annotation);
}
<T> Key<T> getKey(Errors errors, TypeLiteral<T> type, Member member, Annotation[] annotations) {
@@ -281,13 +284,15 @@ public final class ProviderMethodsModule implements Module {
return bindingAnnotation == null ? Key.get(type) : Key.get(type, bindingAnnotation);
}
- @Override public boolean equals(Object o) {
+ @Override
+ public boolean equals(Object o) {
return o instanceof ProviderMethodsModule
&& ((ProviderMethodsModule) o).delegate == delegate
&& ((ProviderMethodsModule) o).scanner == scanner;
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return delegate.hashCode();
}
}
diff --git a/core/src/com/google/inject/internal/ProviderToInternalFactoryAdapter.java b/core/src/com/google/inject/internal/ProviderToInternalFactoryAdapter.java
index 672cf25c..490684dc 100644
--- a/core/src/com/google/inject/internal/ProviderToInternalFactoryAdapter.java
+++ b/core/src/com/google/inject/internal/ProviderToInternalFactoryAdapter.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,43 +17,42 @@
package com.google.inject.internal;
import com.google.inject.Provider;
-import com.google.inject.ProvisionException;
-import com.google.inject.spi.Dependency;
-/**
- * @author crazybob@google.com (Bob Lee)
- */
+/** @author crazybob@google.com (Bob Lee) */
final class ProviderToInternalFactoryAdapter<T> implements Provider<T> {
private final InjectorImpl injector;
private final InternalFactory<? extends T> internalFactory;
- public ProviderToInternalFactoryAdapter(InjectorImpl injector,
- InternalFactory<? extends T> internalFactory) {
+ public ProviderToInternalFactoryAdapter(
+ InjectorImpl injector, InternalFactory<? extends T> internalFactory) {
this.injector = injector;
this.internalFactory = internalFactory;
}
+ @Override
public T get() {
- final Errors errors = new Errors();
+ InternalContext context = injector.enterContext();
try {
- T t = injector.callInContext(new ContextualCallable<T>() {
- public T call(InternalContext context) throws ErrorsException {
- Dependency dependency = context.getDependency();
- // Always pretend that we are a linked binding, to support
- // scoping implicit bindings. If we are not actually a linked
- // binding, we'll fail properly elsewhere in the chain.
- return internalFactory.get(errors, context, dependency, true);
- }
- });
- errors.throwIfNewErrors(0);
+ // Always pretend that we are a linked binding, to support
+ // scoping implicit bindings. If we are not actually a linked
+ // binding, we'll fail properly elsewhere in the chain.
+ T t = internalFactory.get(context, context.getDependency(), true);
return t;
- } catch (ErrorsException e) {
- throw new ProvisionException(errors.merge(e.getErrors()).getMessages());
+ } catch (InternalProvisionException e) {
+ throw e.toProvisionException();
+ } finally {
+ context.close();
}
}
- @Override public String toString() {
+ /** Exposed for SingletonScope. */
+ InjectorImpl getInjector() {
+ return injector;
+ }
+
+ @Override
+ public String toString() {
return internalFactory.toString();
}
}
diff --git a/core/src/com/google/inject/internal/ProvidesMethodScanner.java b/core/src/com/google/inject/internal/ProvidesMethodScanner.java
new file mode 100644
index 00000000..f7709b21
--- /dev/null
+++ b/core/src/com/google/inject/internal/ProvidesMethodScanner.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2016 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.internal;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Binder;
+import com.google.inject.Key;
+import com.google.inject.Provides;
+import com.google.inject.TypeLiteral;
+import com.google.inject.multibindings.MapKey;
+import com.google.inject.multibindings.ProvidesIntoMap;
+import com.google.inject.multibindings.ProvidesIntoOptional;
+import com.google.inject.multibindings.ProvidesIntoSet;
+import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.ModuleAnnotatedMethodScanner;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Set;
+
+/**
+ * A {@link ModuleAnnotatedMethodScanner} that handles the {@Provides}, {@link ProvidesIntoSet},
+ * {@link ProvidesIntoMap} and {@link ProvidesIntoOptional} annotations.
+ *
+ * <p>This is the default scanner used by ProviderMethodsModule and handles all the built in
+ * annotations.
+ */
+final class ProvidesMethodScanner extends ModuleAnnotatedMethodScanner {
+ static final ProvidesMethodScanner INSTANCE = new ProvidesMethodScanner();
+ private static final ImmutableSet<Class<? extends Annotation>> ANNOTATIONS =
+ ImmutableSet.of(
+ Provides.class, ProvidesIntoSet.class, ProvidesIntoMap.class, ProvidesIntoOptional.class);
+
+ private ProvidesMethodScanner() {}
+
+ @Override
+ public Set<? extends Class<? extends Annotation>> annotationClasses() {
+ return ANNOTATIONS;
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"}) // mapKey doesn't know its key type
+ @Override
+ public <T> Key<T> prepareMethod(
+ Binder binder, Annotation annotation, Key<T> key, InjectionPoint injectionPoint) {
+ Method method = (Method) injectionPoint.getMember();
+ AnnotationOrError mapKey = findMapKeyAnnotation(binder, method);
+ if (annotation instanceof Provides) {
+ if (mapKey.annotation != null) {
+ binder.addError("Found a MapKey annotation on non map binding at %s.", method);
+ }
+ // no key rewriting for plain old @Provides
+ return key;
+ }
+ if (annotation instanceof ProvidesIntoSet) {
+ if (mapKey.annotation != null) {
+ binder.addError("Found a MapKey annotation on non map binding at %s.", method);
+ }
+ return RealMultibinder.newRealSetBinder(binder, key).getKeyForNewItem();
+ } else if (annotation instanceof ProvidesIntoMap) {
+ if (mapKey.error) {
+ // Already failed on the MapKey, don't bother doing more work.
+ return key;
+ }
+ if (mapKey.annotation == null) {
+ // If no MapKey, make an error and abort.
+ binder.addError("No MapKey found for map binding at %s.", method);
+ return key;
+ }
+ TypeAndValue typeAndValue = typeAndValueOfMapKey(mapKey.annotation);
+ return RealMapBinder.newRealMapBinder(binder, typeAndValue.type, key)
+ .getKeyForNewValue(typeAndValue.value);
+ } else if (annotation instanceof ProvidesIntoOptional) {
+ if (mapKey.annotation != null) {
+ binder.addError("Found a MapKey annotation on non map binding at %s.", method);
+ }
+ switch (((ProvidesIntoOptional) annotation).value()) {
+ case DEFAULT:
+ return RealOptionalBinder.newRealOptionalBinder(binder, key).getKeyForDefaultBinding();
+ case ACTUAL:
+ return RealOptionalBinder.newRealOptionalBinder(binder, key).getKeyForActualBinding();
+ }
+ }
+ throw new IllegalStateException("Invalid annotation: " + annotation);
+ }
+
+ private static class AnnotationOrError {
+ final Annotation annotation;
+ final boolean error;
+
+ AnnotationOrError(Annotation annotation, boolean error) {
+ this.annotation = annotation;
+ this.error = error;
+ }
+
+ static AnnotationOrError forPossiblyNullAnnotation(Annotation annotation) {
+ return new AnnotationOrError(annotation, false);
+ }
+
+ static AnnotationOrError forError() {
+ return new AnnotationOrError(null, true);
+ }
+ }
+
+ private static AnnotationOrError findMapKeyAnnotation(Binder binder, Method method) {
+ Annotation foundAnnotation = null;
+ for (Annotation annotation : method.getAnnotations()) {
+ MapKey mapKey = annotation.annotationType().getAnnotation(MapKey.class);
+ if (mapKey != null) {
+ if (foundAnnotation != null) {
+ binder.addError("Found more than one MapKey annotations on %s.", method);
+ return AnnotationOrError.forError();
+ }
+ if (mapKey.unwrapValue()) {
+ try {
+ // validate there's a declared method called "value"
+ Method valueMethod = annotation.annotationType().getDeclaredMethod("value");
+ if (valueMethod.getReturnType().isArray()) {
+ binder.addError(
+ "Array types are not allowed in a MapKey with unwrapValue=true: %s",
+ annotation.annotationType());
+ return AnnotationOrError.forError();
+ }
+ } catch (NoSuchMethodException invalid) {
+ binder.addError(
+ "No 'value' method in MapKey with unwrapValue=true: %s",
+ annotation.annotationType());
+ return AnnotationOrError.forError();
+ }
+ }
+ foundAnnotation = annotation;
+ }
+ }
+ return AnnotationOrError.forPossiblyNullAnnotation(foundAnnotation);
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ static TypeAndValue<?> typeAndValueOfMapKey(Annotation mapKeyAnnotation) {
+ if (!mapKeyAnnotation.annotationType().getAnnotation(MapKey.class).unwrapValue()) {
+ return new TypeAndValue(TypeLiteral.get(mapKeyAnnotation.annotationType()), mapKeyAnnotation);
+ } else {
+ try {
+ Method valueMethod = mapKeyAnnotation.annotationType().getDeclaredMethod("value");
+ valueMethod.setAccessible(true);
+ TypeLiteral<?> returnType =
+ TypeLiteral.get(mapKeyAnnotation.annotationType()).getReturnType(valueMethod);
+ return new TypeAndValue(returnType, valueMethod.invoke(mapKeyAnnotation));
+ } catch (NoSuchMethodException e) {
+ throw new IllegalStateException(e);
+ } catch (SecurityException e) {
+ throw new IllegalStateException(e);
+ } catch (IllegalAccessException e) {
+ throw new IllegalStateException(e);
+ } catch (InvocationTargetException e) {
+ throw new IllegalStateException(e);
+ }
+ }
+ }
+
+ private static class TypeAndValue<T> {
+ final TypeLiteral<T> type;
+ final T value;
+
+ TypeAndValue(TypeLiteral<T> type, T value) {
+ this.type = type;
+ this.value = value;
+ }
+ }
+}
diff --git a/core/src/com/google/inject/internal/ProvisionListenerCallbackStore.java b/core/src/com/google/inject/internal/ProvisionListenerCallbackStore.java
index 10746285..0e000dd9 100644
--- a/core/src/com/google/inject/internal/ProvisionListenerCallbackStore.java
+++ b/core/src/com/google/inject/internal/ProvisionListenerCallbackStore.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,9 +28,7 @@ import com.google.inject.Key;
import com.google.inject.Stage;
import com.google.inject.spi.ProvisionListener;
import com.google.inject.spi.ProvisionListenerBinding;
-
import java.util.List;
-import java.util.Set;
import java.util.logging.Logger;
/**
@@ -42,51 +40,57 @@ final class ProvisionListenerCallbackStore {
// TODO(sameb): Consider exposing this in the API somehow? Maybe?
// Lots of code often want to skip over the internal stuffs.
- private static final Set<Key<?>> INTERNAL_BINDINGS =
+ private static final ImmutableSet<Key<?>> INTERNAL_BINDINGS =
ImmutableSet.of(Key.get(Injector.class), Key.get(Stage.class), Key.get(Logger.class));
-
+
private final ImmutableList<ProvisionListenerBinding> listenerBindings;
- private final LoadingCache<KeyBinding, ProvisionListenerStackCallback<?>> cache
- = CacheBuilder.newBuilder().build(
- new CacheLoader<KeyBinding, ProvisionListenerStackCallback<?>>() {
- public ProvisionListenerStackCallback<?> load(KeyBinding key) {
- return create(key.binding);
- }
- });
+ private final LoadingCache<KeyBinding, ProvisionListenerStackCallback<?>> cache =
+ CacheBuilder.newBuilder()
+ .build(
+ new CacheLoader<KeyBinding, ProvisionListenerStackCallback<?>>() {
+ @Override
+ public ProvisionListenerStackCallback<?> load(KeyBinding key) {
+ return create(key.binding);
+ }
+ });
ProvisionListenerCallbackStore(List<ProvisionListenerBinding> listenerBindings) {
this.listenerBindings = ImmutableList.copyOf(listenerBindings);
}
- /** Returns a new {@link ProvisionListenerStackCallback} for the key.
+ /**
+ * Returns a new {@link ProvisionListenerStackCallback} for the key or {@code null} if there are
+ * no listeners
*/
- @SuppressWarnings("unchecked") // the ProvisionListenerStackCallback type always agrees with the passed type
+ @SuppressWarnings(
+ "unchecked") // the ProvisionListenerStackCallback type always agrees with the passed type
public <T> ProvisionListenerStackCallback<T> get(Binding<T> binding) {
// Never notify any listeners for internal bindings.
if (!INTERNAL_BINDINGS.contains(binding.getKey())) {
- return (ProvisionListenerStackCallback<T>) cache.getUnchecked(
- new KeyBinding(binding.getKey(), binding));
+ ProvisionListenerStackCallback<T> callback =
+ (ProvisionListenerStackCallback<T>)
+ cache.getUnchecked(new KeyBinding(binding.getKey(), binding));
+ return callback.hasListeners() ? callback : null;
}
- return ProvisionListenerStackCallback.emptyListener();
+ return null;
}
/**
- * Purges a key from the cache. Use this only if the type is not actually valid for
- * binding and needs to be purged. (See issue 319 and
+ * Purges a key from the cache. Use this only if the type is not actually valid for binding and
+ * needs to be purged. (See issue 319 and
* ImplicitBindingTest#testCircularJitBindingsLeaveNoResidue and
* #testInstancesRequestingProvidersForThemselvesWithChildInjectors for examples of when this is
* necessary.)
- *
- * Returns true if the type was stored in the cache, false otherwise.
+ *
+ * <p>Returns true if the type was stored in the cache, false otherwise.
*/
boolean remove(Binding<?> type) {
return cache.asMap().remove(type) != null;
}
/**
- * Creates a new {@link ProvisionListenerStackCallback} with the correct listeners
- * for the key.
+ * Creates a new {@link ProvisionListenerStackCallback} with the correct listeners for the key.
*/
private <T> ProvisionListenerStackCallback<T> create(Binding<T> binding) {
List<ProvisionListener> listeners = null;
@@ -105,21 +109,22 @@ final class ProvisionListenerCallbackStore {
}
return new ProvisionListenerStackCallback<T>(binding, listeners);
}
-
+
/** A struct that holds key & binding but uses just key for equality/hashcode. */
private static class KeyBinding {
final Key<?> key;
final Binding<?> binding;
-
+
KeyBinding(Key<?> key, Binding<?> binding) {
this.key = key;
this.binding = binding;
}
-
+
@Override
public boolean equals(Object obj) {
- return obj instanceof KeyBinding && key.equals(((KeyBinding)obj).key);
+ return obj instanceof KeyBinding && key.equals(((KeyBinding) obj).key);
}
+
@Override
public int hashCode() {
return key.hashCode();
diff --git a/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java b/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java
index f72da256..01a3d2d2 100644
--- a/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java
+++ b/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,10 +19,7 @@ package com.google.inject.internal;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.google.inject.Binding;
-import com.google.inject.ProvisionException;
-import com.google.inject.spi.DependencyAndSource;
import com.google.inject.spi.ProvisionListener;
-
import java.util.List;
import java.util.Set;
@@ -32,15 +29,16 @@ import java.util.Set;
* @author sameb@google.com (Sam Berlin)
*/
final class ProvisionListenerStackCallback<T> {
-
- private static final ProvisionListener EMPTY_LISTENER[] = new ProvisionListener[0];
- @SuppressWarnings("rawtypes")
+
+ private static final ProvisionListener[] EMPTY_LISTENER = new ProvisionListener[0];
+
+ @SuppressWarnings({"rawtypes", "unchecked"})
private static final ProvisionListenerStackCallback<?> EMPTY_CALLBACK =
new ProvisionListenerStackCallback(null /* unused, so ok */, ImmutableList.of());
private final ProvisionListener[] listeners;
private final Binding<T> binding;
-
+
@SuppressWarnings("unchecked")
public static <T> ProvisionListenerStackCallback<T> emptyListener() {
return (ProvisionListenerStackCallback<T>) EMPTY_CALLBACK;
@@ -55,30 +53,32 @@ final class ProvisionListenerStackCallback<T> {
this.listeners = deDuplicated.toArray(new ProvisionListener[deDuplicated.size()]);
}
}
-
+
public boolean hasListeners() {
return listeners.length > 0;
}
- public T provision(Errors errors, InternalContext context, ProvisionCallback<T> callable)
- throws ErrorsException {
- Provision provision = new Provision(errors, context, callable);
+ public T provision(InternalContext context, ProvisionCallback<T> callable)
+ throws InternalProvisionException {
+ Provision provision = new Provision(context, callable);
RuntimeException caught = null;
try {
provision.provision();
- } catch(RuntimeException t) {
+ } catch (RuntimeException t) {
caught = t;
}
-
+
if (provision.exceptionDuringProvision != null) {
throw provision.exceptionDuringProvision;
} else if (caught != null) {
- Object listener = provision.erredListener != null ?
- provision.erredListener.getClass() : "(unknown)";
- throw errors
- .errorInUserCode(caught, "Error notifying ProvisionListener %s of %s.%n"
- + " Reason: %s", listener, binding.getKey(), caught)
- .toException();
+ Object listener =
+ provision.erredListener != null ? provision.erredListener.getClass() : "(unknown)";
+ throw InternalProvisionException.errorInUserCode(
+ caught,
+ "Error notifying ProvisionListener %s of %s.%n Reason: %s",
+ listener,
+ binding.getKey(),
+ caught);
} else {
return provision.result;
}
@@ -86,25 +86,22 @@ final class ProvisionListenerStackCallback<T> {
// TODO(sameb): Can this be more InternalFactory-like?
public interface ProvisionCallback<T> {
- public T call() throws ErrorsException;
+ public T call() throws InternalProvisionException;
}
private class Provision extends ProvisionListener.ProvisionInvocation<T> {
- final Errors errors;
- final int numErrorsBefore;
final InternalContext context;
+
final ProvisionCallback<T> callable;
int index = -1;
T result;
- ErrorsException exceptionDuringProvision;
+ InternalProvisionException exceptionDuringProvision;
ProvisionListener erredListener;
- public Provision(Errors errors, InternalContext context, ProvisionCallback<T> callable) {
+ public Provision(InternalContext context, ProvisionCallback<T> callable) {
this.callable = callable;
this.context = context;
- this.errors = errors;
- this.numErrorsBefore = errors.size();
}
@Override
@@ -113,18 +110,15 @@ final class ProvisionListenerStackCallback<T> {
if (index == listeners.length) {
try {
result = callable.call();
- // Make sure we don't return the provisioned object if there were any errors
- // injecting its field/method dependencies.
- errors.throwIfNewErrors(numErrorsBefore);
- } catch(ErrorsException ee) {
- exceptionDuringProvision = ee;
- throw new ProvisionException(errors.merge(ee.getErrors()).getMessages());
+ } catch (InternalProvisionException ipe) {
+ exceptionDuringProvision = ipe;
+ throw ipe.toProvisionException();
}
} else if (index < listeners.length) {
int currentIdx = index;
try {
listeners[index].onProvision(this);
- } catch(RuntimeException re) {
+ } catch (RuntimeException re) {
erredListener = listeners[currentIdx];
throw re;
}
@@ -137,7 +131,7 @@ final class ProvisionListenerStackCallback<T> {
}
return result;
}
-
+
@Override
public Binding<T> getBinding() {
// TODO(sameb): Because so many places cast directly to BindingImpl & subclasses,
@@ -145,10 +139,12 @@ final class ProvisionListenerStackCallback<T> {
// if someone calls that they'll get strange errors.
return binding;
}
-
+
+ @Deprecated
@Override
- public List<DependencyAndSource> getDependencyChain() {
+ public List<com.google.inject.spi.DependencyAndSource> getDependencyChain() {
return context.getDependencyChain();
}
+
}
}
diff --git a/core/src/com/google/inject/internal/ProxyFactory.java b/core/src/com/google/inject/internal/ProxyFactory.java
index 13aff810..156a5c82 100644
--- a/core/src/com/google/inject/internal/ProxyFactory.java
+++ b/core/src/com/google/inject/internal/ProxyFactory.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +16,7 @@
package com.google.inject.internal;
-import static com.google.inject.internal.BytecodeGen.newFastClass;
+import static com.google.inject.internal.BytecodeGen.newFastClassForMember;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -24,16 +24,6 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.spi.InjectionPoint;
-
-import net.sf.cglib.core.MethodWrapper;
-import net.sf.cglib.proxy.Callback;
-import net.sf.cglib.proxy.CallbackFilter;
-import net.sf.cglib.proxy.Enhancer;
-import net.sf.cglib.reflect.FastClass;
-import net.sf.cglib.reflect.FastConstructor;
-
-import org.aopalliance.intercept.MethodInterceptor;
-
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -41,6 +31,12 @@ import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
+import net.sf.cglib.core.MethodWrapper;
+import net.sf.cglib.proxy.Callback;
+import net.sf.cglib.proxy.CallbackFilter;
+import net.sf.cglib.proxy.Enhancer;
+import net.sf.cglib.reflect.FastClass;
+import org.aopalliance.intercept.MethodInterceptor;
/**
* Builds a construction proxy that can participate in AOP. This class manages applying type and
@@ -49,7 +45,7 @@ import java.util.logging.Logger;
* @author jessewilson@google.com (Jesse Wilson)
*/
final class ProxyFactory<T> implements ConstructionProxyFactory<T> {
-
+
private static final Logger logger = Logger.getLogger(ProxyFactory.class.getName());
private final InjectionPoint injectionPoint;
@@ -68,7 +64,7 @@ final class ProxyFactory<T> implements ConstructionProxyFactory<T> {
this.injectionPoint = injectionPoint;
@SuppressWarnings("unchecked") // the member of injectionPoint is always a Constructor<T>
- Constructor<T> constructor = (Constructor<T>) injectionPoint.getMember();
+ Constructor<T> constructor = (Constructor<T>) injectionPoint.getMember();
declaringClass = constructor.getDeclaringClass();
// Find applicable aspects. Bow out if none are applicable to this class.
@@ -101,12 +97,13 @@ final class ProxyFactory<T> implements ConstructionProxyFactory<T> {
for (MethodAspect methodAspect : applicableAspects) {
for (MethodInterceptorsPair pair : methodInterceptorsPairs) {
if (methodAspect.matches(pair.method)) {
- if(pair.method.isSynthetic()) {
- logger.log(Level.WARNING,
+ if (pair.method.isSynthetic()) {
+ logger.log(
+ Level.WARNING,
"Method [{0}] is synthetic and is being intercepted by {1}."
- + " This could indicate a bug. The method may be intercepted twice,"
- + " or may not be intercepted at all.",
- new Object[] { pair.method, methodAspect.interceptors() });
+ + " This could indicate a bug. The method may be intercepted twice,"
+ + " or may not be intercepted at all.",
+ new Object[] {pair.method, methodAspect.interceptors()});
}
visibility = visibility.and(BytecodeGen.Visibility.forMember(pair.method));
pair.addAll(methodAspect.interceptors());
@@ -142,18 +139,18 @@ final class ProxyFactory<T> implements ConstructionProxyFactory<T> {
callbacks[i] = new InterceptorStackCallback(pair.method, deDuplicated);
}
- interceptors = interceptorsMapBuilder != null
- ? interceptorsMapBuilder.build()
- : ImmutableMap.<Method, List<MethodInterceptor>>of();
+ interceptors =
+ interceptorsMapBuilder != null
+ ? interceptorsMapBuilder.build()
+ : ImmutableMap.<Method, List<MethodInterceptor>>of();
}
- /**
- * Returns the interceptors that apply to the constructed type.
- */
+ /** Returns the interceptors that apply to the constructed type. */
public ImmutableMap<Method, List<MethodInterceptor>> getInterceptors() {
return interceptors;
}
+ @Override
public ConstructionProxy<T> create() throws ErrorsException {
if (interceptors.isEmpty()) {
return new DefaultConstructionProxyFactory<T>(injectionPoint).create();
@@ -172,10 +169,10 @@ final class ProxyFactory<T> implements ConstructionProxyFactory<T> {
// Create the proxied class. We're careful to ensure that all enhancer state is not-specific
// to this injector. Otherwise, the proxies for each injector will waste PermGen memory
try {
- Enhancer enhancer = BytecodeGen.newEnhancer(declaringClass, visibility);
- enhancer.setCallbackFilter(new IndicesCallbackFilter(methods));
- enhancer.setCallbackTypes(callbackTypes);
- return new ProxyConstructor<T>(enhancer, injectionPoint, callbacks, interceptors);
+ Enhancer enhancer = BytecodeGen.newEnhancer(declaringClass, visibility);
+ enhancer.setCallbackFilter(new IndicesCallbackFilter(methods));
+ enhancer.setCallbackTypes(callbackTypes);
+ return new ProxyConstructor<T>(enhancer, injectionPoint, callbacks, interceptors);
} catch (Throwable e) {
throw new Errors().errorEnhancingClass(declaringClass, e).toException();
}
@@ -202,10 +199,9 @@ final class ProxyFactory<T> implements ConstructionProxyFactory<T> {
}
/**
- * A callback filter that maps methods to unique IDs. We define equals and
- * hashCode without using any state related to the injector so that enhanced
- * classes intercepting the same methods can be shared between injectors (and
- * child injectors, etc).
+ * A callback filter that maps methods to unique IDs. We define equals and hashCode without using
+ * any state related to the injector so that enhanced classes intercepting the same methods can be
+ * shared between injectors (and child injectors, etc).
*/
private static class IndicesCallbackFilter implements CallbackFilter {
final Map<Object, Integer> indices;
@@ -220,63 +216,71 @@ final class ProxyFactory<T> implements ConstructionProxyFactory<T> {
this.hashCode = indices.hashCode();
}
+ @Override
public int accept(Method method) {
return indices.get(MethodWrapper.create(method));
}
- @Override public boolean equals(Object o) {
- return o instanceof IndicesCallbackFilter &&
- ((IndicesCallbackFilter) o).indices.equals(indices);
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof IndicesCallbackFilter
+ && ((IndicesCallbackFilter) o).indices.equals(indices);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return hashCode;
}
}
- /**
- * Constructs instances that participate in AOP.
- */
+ /** Constructs instances that participate in AOP. */
private static class ProxyConstructor<T> implements ConstructionProxy<T> {
final Class<?> enhanced;
final InjectionPoint injectionPoint;
final Constructor<T> constructor;
final Callback[] callbacks;
- final FastConstructor fastConstructor;
+ final int constructorIndex;
final ImmutableMap<Method, List<MethodInterceptor>> methodInterceptors;
+ final FastClass fastClass;
@SuppressWarnings("unchecked") // the constructor promises to construct 'T's
- ProxyConstructor(Enhancer enhancer, InjectionPoint injectionPoint, Callback[] callbacks,
+ ProxyConstructor(
+ Enhancer enhancer,
+ InjectionPoint injectionPoint,
+ Callback[] callbacks,
ImmutableMap<Method, List<MethodInterceptor>> methodInterceptors) {
this.enhanced = enhancer.createClass(); // this returns a cached class if possible
this.injectionPoint = injectionPoint;
this.constructor = (Constructor<T>) injectionPoint.getMember();
this.callbacks = callbacks;
this.methodInterceptors = methodInterceptors;
-
- FastClass fastClass = newFastClass(enhanced, BytecodeGen.Visibility.forMember(constructor));
- this.fastConstructor = fastClass.getConstructor(constructor.getParameterTypes());
+ this.fastClass = newFastClassForMember(enhanced, constructor);
+ this.constructorIndex = fastClass.getIndex(constructor.getParameterTypes());
}
+ @Override
@SuppressWarnings("unchecked") // the constructor promises to produce 'T's
public T newInstance(Object... arguments) throws InvocationTargetException {
Enhancer.registerCallbacks(enhanced, callbacks);
try {
- return (T) fastConstructor.newInstance(arguments);
+ return (T) fastClass.newInstance(constructorIndex, arguments);
} finally {
Enhancer.registerCallbacks(enhanced, null);
}
}
+ @Override
public InjectionPoint getInjectionPoint() {
return injectionPoint;
}
+ @Override
public Constructor<T> getConstructor() {
return constructor;
}
+ @Override
public ImmutableMap<Method, List<MethodInterceptor>> getMethodInterceptors() {
return methodInterceptors;
}
diff --git a/core/src/com/google/inject/internal/RealElement.java b/core/src/com/google/inject/internal/RealElement.java
new file mode 100644
index 00000000..8f984a6c
--- /dev/null
+++ b/core/src/com/google/inject/internal/RealElement.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2008 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.internal;
+
+import com.google.inject.internal.Element.Type;
+import java.lang.annotation.Annotation;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/** An implementation of Element. */
+// TODO(cgruber): Use AutoAnnotation when available, here & wherever else is makes sense.
+class RealElement implements Element {
+ private static final AtomicInteger nextUniqueId = new AtomicInteger(1);
+
+ private final int uniqueId;
+ private final String setName;
+ private final Element.Type type;
+ private final String keyType;
+
+ RealElement(String setName, Element.Type type, String keyType) {
+ this(setName, type, keyType, nextUniqueId.incrementAndGet());
+ }
+
+ RealElement(String setName, Element.Type type, String keyType, int uniqueId) {
+ this.uniqueId = uniqueId;
+ this.setName = setName;
+ this.type = type;
+ this.keyType = keyType;
+ }
+
+ @Override
+ public String setName() {
+ return setName;
+ }
+
+ @Override
+ public int uniqueId() {
+ return uniqueId;
+ }
+
+ @Override
+ public Element.Type type() {
+ return type;
+ }
+
+ @Override
+ public String keyType() {
+ return keyType;
+ }
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return Element.class;
+ }
+
+ @Override
+ public String toString() {
+ return "@"
+ + Element.class.getName()
+ + "(setName="
+ + setName
+ + ",uniqueId="
+ + uniqueId
+ + ", type="
+ + type
+ + ", keyType="
+ + keyType
+ + ")";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof Element
+ && ((Element) o).setName().equals(setName())
+ && ((Element) o).uniqueId() == uniqueId()
+ && ((Element) o).type() == type()
+ && ((Element) o).keyType().equals(keyType());
+ }
+
+ @Override
+ public int hashCode() {
+ return ((127 * "setName".hashCode()) ^ setName.hashCode())
+ + ((127 * "uniqueId".hashCode()) ^ uniqueId)
+ + ((127 * "type".hashCode()) ^ type.hashCode())
+ + ((127 * "keyType".hashCode()) ^ keyType.hashCode());
+ }
+}
diff --git a/core/src/com/google/inject/internal/RealMapBinder.java b/core/src/com/google/inject/internal/RealMapBinder.java
new file mode 100644
index 00000000..1e28fb24
--- /dev/null
+++ b/core/src/com/google/inject/internal/RealMapBinder.java
@@ -0,0 +1,1344 @@
+
+package com.google.inject.internal;
+
+import static com.google.inject.internal.Element.Type.MAPBINDER;
+import static com.google.inject.internal.Errors.checkConfiguration;
+import static com.google.inject.internal.Errors.checkNotNull;
+import static com.google.inject.internal.RealMultibinder.setOf;
+import static com.google.inject.util.Types.newParameterizedType;
+import static com.google.inject.util.Types.newParameterizedTypeWithOwner;
+
+import com.google.common.base.Objects;
+import com.google.common.base.Preconditions;
+import com.google.common.collect.HashMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableMultimap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Multimap;
+import com.google.common.collect.Sets;
+import com.google.inject.Binder;
+import com.google.inject.Binding;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.Provider;
+import com.google.inject.TypeLiteral;
+import com.google.inject.binder.LinkedBindingBuilder;
+import com.google.inject.internal.InternalProviderInstanceBindingImpl.InitializationTiming;
+import com.google.inject.multibindings.MapBinderBinding;
+import com.google.inject.multibindings.Multibinder;
+import com.google.inject.multibindings.MultibindingsTargetVisitor;
+import com.google.inject.spi.BindingTargetVisitor;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.Element;
+import com.google.inject.spi.ProviderInstanceBinding;
+import com.google.inject.spi.ProviderWithExtensionVisitor;
+import com.google.inject.util.Types;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * The actual mapbinder plays several roles:
+ *
+ * <p>As a MapBinder, it acts as a factory for LinkedBindingBuilders for each of the map's values.
+ * It delegates to a {@link Multibinder} of entries (keys to value providers).
+ *
+ * <p>As a Module, it installs the binding to the map itself, as well as to a corresponding map
+ * whose values are providers.
+ *
+ * <p>As a module, this implements equals() and hashcode() in order to trick Guice into executing
+ * its configure() method only once. That makes it so that multiple mapbinders can be created for
+ * the same target map, but only one is bound. Since the list of bindings is retrieved from the
+ * injector itself (and not the mapbinder), each mapbinder has access to all contributions from all
+ * equivalent mapbinders.
+ *
+ * <p>Rather than binding a single Map.Entry&lt;K, V&gt;, the map binder binds keys and values
+ * independently. This allows the values to be properly scoped.
+ */
+public final class RealMapBinder<K, V> implements Module {
+
+ /**
+ * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link
+ * Map} that is itself bound with no binding annotation.
+ */
+ public static <K, V> RealMapBinder<K, V> newMapRealBinder(
+ Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
+ binder = binder.skipSources(RealMapBinder.class);
+ return newRealMapBinder(
+ binder,
+ keyType,
+ valueType,
+ Key.get(mapOf(keyType, valueType)),
+ RealMultibinder.newRealSetBinder(binder, Key.get(entryOfProviderOf(keyType, valueType))));
+ }
+
+ /**
+ * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link
+ * Map} that is itself bound with {@code annotation}.
+ */
+ public static <K, V> RealMapBinder<K, V> newRealMapBinder(
+ Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType, Annotation annotation) {
+ binder = binder.skipSources(RealMapBinder.class);
+ return newRealMapBinder(
+ binder,
+ keyType,
+ valueType,
+ Key.get(mapOf(keyType, valueType), annotation),
+ RealMultibinder.newRealSetBinder(
+ binder, Key.get(entryOfProviderOf(keyType, valueType), annotation)));
+ }
+
+ /**
+ * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link
+ * Map} that is itself bound with {@code annotationType}.
+ */
+ public static <K, V> RealMapBinder<K, V> newRealMapBinder(
+ Binder binder,
+ TypeLiteral<K> keyType,
+ TypeLiteral<V> valueType,
+ Class<? extends Annotation> annotationType) {
+ binder = binder.skipSources(RealMapBinder.class);
+ return newRealMapBinder(
+ binder,
+ keyType,
+ valueType,
+ Key.get(mapOf(keyType, valueType), annotationType),
+ RealMultibinder.newRealSetBinder(
+ binder, Key.get(entryOfProviderOf(keyType, valueType), annotationType)));
+ }
+
+ @SuppressWarnings("unchecked") // a map of <K, V> is safely a Map<K, V>
+ static <K, V> TypeLiteral<Map<K, V>> mapOf(TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
+ return (TypeLiteral<Map<K, V>>)
+ TypeLiteral.get(Types.mapOf(keyType.getType(), valueType.getType()));
+ }
+
+ @SuppressWarnings("unchecked") // a provider map <K, V> is safely a Map<K, Provider<V>>
+ static <K, V> TypeLiteral<Map<K, Provider<V>>> mapOfProviderOf(
+ TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
+ return (TypeLiteral<Map<K, Provider<V>>>)
+ TypeLiteral.get(Types.mapOf(keyType.getType(), Types.providerOf(valueType.getType())));
+ }
+
+ // provider map <K, V> is safely a Map<K, javax.inject.Provider<V>>>
+ @SuppressWarnings("unchecked")
+ static <K, V> TypeLiteral<Map<K, javax.inject.Provider<V>>> mapOfJavaxProviderOf(
+ TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
+ return (TypeLiteral<Map<K, javax.inject.Provider<V>>>)
+ TypeLiteral.get(
+ Types.mapOf(
+ keyType.getType(),
+ newParameterizedType(javax.inject.Provider.class, valueType.getType())));
+ }
+
+ @SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>>
+ static <K, V> TypeLiteral<Map<K, Set<Provider<V>>>> mapOfSetOfProviderOf(
+ TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
+ return (TypeLiteral<Map<K, Set<Provider<V>>>>)
+ TypeLiteral.get(
+ Types.mapOf(keyType.getType(), Types.setOf(Types.providerOf(valueType.getType()))));
+ }
+
+ @SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>>
+ static <K, V> TypeLiteral<Map<K, Set<javax.inject.Provider<V>>>> mapOfSetOfJavaxProviderOf(
+ TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
+ return (TypeLiteral<Map<K, Set<javax.inject.Provider<V>>>>)
+ TypeLiteral.get(
+ Types.mapOf(
+ keyType.getType(), Types.setOf(Types.javaxProviderOf(valueType.getType()))));
+ }
+
+ @SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>>
+ static <K, V> TypeLiteral<Map<K, Collection<Provider<V>>>> mapOfCollectionOfProviderOf(
+ TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
+ return (TypeLiteral<Map<K, Collection<Provider<V>>>>)
+ TypeLiteral.get(
+ Types.mapOf(
+ keyType.getType(), Types.collectionOf(Types.providerOf(valueType.getType()))));
+ }
+
+ @SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>>
+ static <K, V>
+ TypeLiteral<Map<K, Collection<javax.inject.Provider<V>>>> mapOfCollectionOfJavaxProviderOf(
+ TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
+ return (TypeLiteral<Map<K, Collection<javax.inject.Provider<V>>>>)
+ TypeLiteral.get(
+ Types.mapOf(
+ keyType.getType(), Types.collectionOf(Types.javaxProviderOf(valueType.getType()))));
+ }
+
+ @SuppressWarnings("unchecked") // a provider entry <K, V> is safely a Map.Entry<K, Provider<V>>
+ static <K, V> TypeLiteral<Map.Entry<K, Provider<V>>> entryOfProviderOf(
+ TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
+ return (TypeLiteral<Map.Entry<K, Provider<V>>>)
+ TypeLiteral.get(
+ newParameterizedTypeWithOwner(
+ Map.class,
+ Map.Entry.class,
+ keyType.getType(),
+ Types.providerOf(valueType.getType())));
+ }
+
+ @SuppressWarnings("unchecked") // a provider entry <K, V> is safely a Map.Entry<K, Provider<V>>
+ static <K, V> TypeLiteral<Map.Entry<K, Provider<V>>> entryOfJavaxProviderOf(
+ TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
+ return (TypeLiteral<Map.Entry<K, Provider<V>>>)
+ TypeLiteral.get(
+ newParameterizedTypeWithOwner(
+ Map.class,
+ Map.Entry.class,
+ keyType.getType(),
+ Types.javaxProviderOf(valueType.getType())));
+ }
+
+ @SuppressWarnings("unchecked") // a provider entry <K, V> is safely a Map.Entry<K, Provider<V>>
+ static <K, V>
+ TypeLiteral<Set<Map.Entry<K, javax.inject.Provider<V>>>> setOfEntryOfJavaxProviderOf(
+ TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
+ return (TypeLiteral<Set<Map.Entry<K, javax.inject.Provider<V>>>>)
+ TypeLiteral.get(Types.setOf(entryOfJavaxProviderOf(keyType, valueType).getType()));
+ }
+
+ /** Given a Key<T> will return a Key<Provider<T>> */
+ @SuppressWarnings("unchecked")
+ private static <T> Key<Provider<T>> getKeyOfProvider(Key<T> valueKey) {
+ return (Key<Provider<T>>)
+ valueKey.ofType(Types.providerOf(valueKey.getTypeLiteral().getType()));
+ }
+
+ // Note: We use valueTypeAndAnnotation effectively as a Pair<TypeLiteral, Annotation|Class>
+ // since it's an easy way to group a type and an optional annotation type or instance.
+ static <K, V> RealMapBinder<K, V> newRealMapBinder(
+ Binder binder, TypeLiteral<K> keyType, Key<V> valueTypeAndAnnotation) {
+ binder = binder.skipSources(RealMapBinder.class);
+ TypeLiteral<V> valueType = valueTypeAndAnnotation.getTypeLiteral();
+ return newRealMapBinder(
+ binder,
+ keyType,
+ valueType,
+ valueTypeAndAnnotation.ofType(mapOf(keyType, valueType)),
+ RealMultibinder.newRealSetBinder(
+ binder, valueTypeAndAnnotation.ofType(entryOfProviderOf(keyType, valueType))));
+ }
+
+ private static <K, V> RealMapBinder<K, V> newRealMapBinder(
+ Binder binder,
+ TypeLiteral<K> keyType,
+ TypeLiteral<V> valueType,
+ Key<Map<K, V>> mapKey,
+ RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder) {
+ RealMapBinder<K, V> mapBinder =
+ new RealMapBinder<K, V>(binder, keyType, valueType, mapKey, entrySetBinder);
+ binder.install(mapBinder);
+ return mapBinder;
+ }
+
+ // Until the injector initializes us, we don't know what our dependencies are,
+ // so initialize to the whole Injector.
+ private static final ImmutableSet<Dependency<?>> MODULE_DEPENDENCIES =
+ ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class)));
+
+ private final BindingSelection<K, V> bindingSelection;
+ private final Binder binder;
+
+ private final RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder;
+
+ private RealMapBinder(
+ Binder binder,
+ TypeLiteral<K> keyType,
+ TypeLiteral<V> valueType,
+ Key<Map<K, V>> mapKey,
+ RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder) {
+ this.bindingSelection = new BindingSelection<>(keyType, valueType, mapKey, entrySetBinder);
+ this.binder = binder;
+ this.entrySetBinder = entrySetBinder;
+ }
+
+ public void permitDuplicates() {
+ checkConfiguration(!bindingSelection.isInitialized(), "MapBinder was already initialized");
+ entrySetBinder.permitDuplicates();
+ binder.install(new MultimapBinder<K, V>(bindingSelection));
+ }
+
+ /** Adds a binding to the map for the given key. */
+ Key<V> getKeyForNewValue(K key) {
+ checkNotNull(key, "key");
+ checkConfiguration(!bindingSelection.isInitialized(), "MapBinder was already initialized");
+ RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder =
+ bindingSelection.getEntrySetBinder();
+
+ Key<V> valueKey =
+ Key.get(
+ bindingSelection.getValueType(),
+ new RealElement(
+ entrySetBinder.getSetName(), MAPBINDER, bindingSelection.getKeyType().toString()));
+ entrySetBinder.addBinding().toProvider(new ProviderMapEntry<K, V>(key, valueKey));
+ return valueKey;
+ }
+
+ /**
+ * This creates two bindings. One for the {@code Map.Entry<K, Provider<V>>} and another for {@code
+ * V}.
+ */
+ public LinkedBindingBuilder<V> addBinding(K key) {
+ return binder.bind(getKeyForNewValue(key));
+ }
+
+ @Override
+ public void configure(Binder binder) {
+ checkConfiguration(!bindingSelection.isInitialized(), "MapBinder was already initialized");
+
+ // Binds a Map<K, Provider<V>>
+ RealProviderMapProvider<K, V> providerMapProvider =
+ new RealProviderMapProvider<K, V>(bindingSelection);
+ binder.bind(bindingSelection.getProviderMapKey()).toProvider(providerMapProvider);
+
+ // The map this exposes is internally an ImmutableMap, so it's OK to massage
+ // the guice Provider to javax Provider in the value (since Guice provider
+ // implements javax Provider).
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ Provider<Map<K, javax.inject.Provider<V>>> javaxProviderMapProvider =
+ (Provider) providerMapProvider;
+ binder.bind(bindingSelection.getJavaxProviderMapKey()).toProvider(javaxProviderMapProvider);
+
+ RealMapProvider<K, V> mapProvider = new RealMapProvider<>(bindingSelection);
+ binder.bind(bindingSelection.getMapKey()).toProvider(mapProvider);
+
+ // The Map.Entries are all ProviderMapEntry instances which do not allow setValue, so it is
+ // safe to massage the return type like this
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ Key<Set<Map.Entry<K, javax.inject.Provider<V>>>> massagedEntrySetProviderKey =
+ (Key) bindingSelection.getEntrySetBinder().getSetKey();
+ binder.bind(bindingSelection.getEntrySetJavaxProviderKey()).to(massagedEntrySetProviderKey);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof RealMapBinder
+ && ((RealMapBinder<?, ?>) o).bindingSelection.equals(bindingSelection);
+ }
+
+ @Override
+ public int hashCode() {
+ return bindingSelection.hashCode();
+ }
+
+ /**
+ * The BindingSelection contains some of the core state and logic for the MapBinder.
+ *
+ * <p>It lazily computes the value for keys for various permutations of Maps that are provided by
+ * this module. It also builds up maps from {@code K} to {@code Binding<V>}, which is used by all
+ * of the internal factories to actually provide the desired maps.
+ *
+ * <p>During initialization time there is only one BindingSelection. It is possible that multiple
+ * different BindingSelections are constructed. Specifically, in the case of two different modules
+ * each adding bindings to the same MapBinder. If that happens, we define the BindingSelection
+ * held by the {@link RealMapProvider} to be the authoritative one. The logic for this exists in
+ * {@link RealMultimapBinderProviderWithDependencies}. This is done to avoid confusion because the
+ * BindingSelection contains mutable state.
+ */
+ private static final class BindingSelection<K, V> {
+ private enum InitializationState {
+ UNINITIALIZED,
+ INITIALIZED,
+ HAS_ERRORS;
+ }
+
+ private final TypeLiteral<K> keyType;
+ private final TypeLiteral<V> valueType;
+ private final Key<Map<K, V>> mapKey;
+
+ // Lazily computed
+ private Key<Map<K, javax.inject.Provider<V>>> javaxProviderMapKey;
+ private Key<Map<K, Provider<V>>> providerMapKey;
+ private Key<Map<K, Set<V>>> multimapKey;
+ private Key<Map<K, Set<Provider<V>>>> providerSetMultimapKey;
+ private Key<Map<K, Set<javax.inject.Provider<V>>>> javaxProviderSetMultimapKey;
+ private Key<Map<K, Collection<Provider<V>>>> providerCollectionMultimapKey;
+ private Key<Map<K, Collection<javax.inject.Provider<V>>>> javaxProviderCollectionMultimapKey;
+ private Key<Set<Map.Entry<K, javax.inject.Provider<V>>>> entrySetJavaxProviderKey;
+
+ private final RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder;
+
+ private InitializationState initializationState;
+
+ /**
+ * These are built during initialization and used by all factories to actually provide the
+ * relevant maps. These contain all of the necessary information about the map binder.
+ */
+ private ImmutableMap<K, Binding<V>> mapBindings;
+
+ private ImmutableMap<K, Set<Binding<V>>> multimapBindings;
+ private ImmutableList<Map.Entry<K, Binding<V>>> entries;
+
+ /**
+ * Indicates if this Map permits duplicates. It is initialized during initialization by querying
+ * the injector. This is done because multiple different modules can contribute to a MapBinder,
+ * and any one could set permitDuplicates.
+ */
+ private boolean permitsDuplicates;
+
+ private BindingSelection(
+ TypeLiteral<K> keyType,
+ TypeLiteral<V> valueType,
+ Key<Map<K, V>> mapKey,
+ RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder) {
+ this.keyType = keyType;
+ this.valueType = valueType;
+ this.mapKey = mapKey;
+ this.entrySetBinder = entrySetBinder;
+ this.initializationState = InitializationState.UNINITIALIZED;
+ }
+
+ /**
+ * Will initialize internal data structures.
+ *
+ * @return {@code true} if initialization was successful, {@code false} if there were errors
+ */
+ private boolean tryInitialize(InjectorImpl injector, Errors errors) {
+ // Every one of our providers will call this method, so only execute the logic once.
+ if (initializationState != InitializationState.UNINITIALIZED) {
+ return initializationState != InitializationState.HAS_ERRORS;
+ }
+
+ // Multiple different modules can all contribute to the same MapBinder, and if any
+ // one of them permits duplicates, then the map binder as a whole will permit duplicates.
+ // Since permitDuplicates() may not have been called on this instance, we need to go
+ // to the injector to see if permitDuplicates was set.
+ permitsDuplicates = entrySetBinder.permitsDuplicates(injector);
+
+ // We now build the Map<K, Set<Binding<V>>> from the entrySetBinder.
+ // The entrySetBinder contains all of the ProviderMapEntrys, and once
+ // we have those, it's easy to iterate through them to organize them by K.
+ Map<K, ImmutableSet.Builder<Binding<V>>> bindingMultimapMutable =
+ new LinkedHashMap<K, ImmutableSet.Builder<Binding<V>>>();
+ Map<K, Binding<V>> bindingMapMutable = new LinkedHashMap<>();
+ Multimap<K, Indexer.IndexedBinding> index = HashMultimap.create();
+ Indexer indexer = new Indexer(injector);
+ Multimap<K, Binding<V>> duplicates = null;
+
+ ImmutableList.Builder<Map.Entry<K, Binding<V>>> entriesBuilder = ImmutableList.builder();
+
+ // We get all of the Bindings that were put into the entrySetBinder
+ for (Binding<Map.Entry<K, Provider<V>>> binding :
+ injector.findBindingsByType(entrySetBinder.getElementTypeLiteral())) {
+ if (entrySetBinder.containsElement(binding)) {
+
+ // Protected by findBindingByType() and the fact that all providers are added by us
+ // in addBinding(). It would theoretically be possible for someone to directly
+ // add their own binding to the entrySetBinder, but they shouldn't do that.
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ ProviderInstanceBinding<ProviderMapEntry<K, V>> entryBinding =
+ (ProviderInstanceBinding) binding;
+
+ // We added all these bindings initially, so we know they are ProviderMapEntrys
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ ProviderMapEntry<K, V> entry = (ProviderMapEntry) entryBinding.getUserSuppliedProvider();
+ K key = entry.getKey();
+
+ Key<V> valueKey = entry.getValueKey();
+ Binding<V> valueBinding = injector.getExistingBinding(valueKey);
+
+ // Use the indexer to de-dupe user bindings. This is needed because of the
+ // uniqueId in RealElement. The uniqueId intentionally circumvents the regular
+ // Guice deduplication, so we need to re-implement our own here, ignoring
+ // uniqueId.
+ if (index.put(key, valueBinding.acceptTargetVisitor(indexer))) {
+
+ entriesBuilder.add(Maps.immutableEntry(key, valueBinding));
+
+ Binding<V> previous = bindingMapMutable.put(key, valueBinding);
+ // Check if this is a duplicate binding
+ if (previous != null && !permitsDuplicates) {
+ if (duplicates == null) {
+ // This is linked for both keys and values to maintain order
+ duplicates = LinkedHashMultimap.create();
+ }
+
+ // We add both the previous and the current value to the duplicates map.
+ // This is because if there are three duplicates, we will only execute this code
+ // for the second and third, but we want all three values to display a helpful
+ // error message. We rely on the multimap to dedupe repeated values.
+ duplicates.put(key, previous);
+ duplicates.put(key, valueBinding);
+ }
+
+ // Don't do extra work unless we need to
+ if (permitsDuplicates) {
+ // Create a set builder for this key if it's the first time we've seen it
+ if (!bindingMultimapMutable.containsKey(key)) {
+ bindingMultimapMutable.put(key, ImmutableSet.<Binding<V>>builder());
+ }
+
+ // Add the Binding<V>
+ bindingMultimapMutable.get(key).add(valueBinding);
+ }
+ }
+ }
+ }
+
+ // It is safe to check if duplicates is non-null because if duplicates are allowed,
+ // we don't build up this data structure
+ if (duplicates != null) {
+ initializationState = InitializationState.HAS_ERRORS;
+ reportDuplicateKeysError(duplicates, errors);
+
+ return false;
+ }
+
+ // Build all of the ImmutableSet.Builders,
+ // transforming from Map<K, ImmutableSet.Builder<Binding<V>>> to
+ // ImmutableMap<K, Set<Binding<V>>>
+ ImmutableMap.Builder<K, Set<Binding<V>>> bindingsMultimapBuilder = ImmutableMap.builder();
+ for (Map.Entry<K, ImmutableSet.Builder<Binding<V>>> entry :
+ bindingMultimapMutable.entrySet()) {
+ bindingsMultimapBuilder.put(entry.getKey(), entry.getValue().build());
+ }
+ mapBindings = ImmutableMap.copyOf(bindingMapMutable);
+ multimapBindings = bindingsMultimapBuilder.build();
+
+ entries = entriesBuilder.build();
+
+ initializationState = InitializationState.INITIALIZED;
+
+ return true;
+ }
+
+ private static <K, V> void reportDuplicateKeysError(
+ Multimap<K, Binding<V>> duplicates, Errors errors) {
+ StringBuilder sb = new StringBuilder("Map injection failed due to duplicated key ");
+ boolean first = true;
+ for (Map.Entry<K, Collection<Binding<V>>> entry : duplicates.asMap().entrySet()) {
+ K dupKey = entry.getKey();
+
+ if (first) {
+ first = false;
+ sb.append("\"" + dupKey + "\", from bindings:\n");
+ } else {
+ sb.append("\n and key: \"" + dupKey + "\", from bindings:\n");
+ }
+
+ for (Binding<V> dup : entry.getValue()) {
+ sb.append("\t at " + Errors.convert(dup.getSource()) + "\n");
+ }
+ }
+
+ // TODO(user): Add a different error for every duplicated key
+ errors.addMessage(sb.toString());
+ }
+
+ private boolean containsElement(Element element) {
+ if (entrySetBinder.containsElement(element)) {
+ return true;
+ }
+
+ Key<?> key;
+ if (element instanceof Binding) {
+ key = ((Binding<?>) element).getKey();
+ } else {
+ return false; // cannot match;
+ }
+
+ return key.equals(getMapKey())
+ || key.equals(getProviderMapKey())
+ || key.equals(getJavaxProviderMapKey())
+ || key.equals(getMultimapKey())
+ || key.equals(getProviderSetMultimapKey())
+ || key.equals(getJavaxProviderSetMultimapKey())
+ || key.equals(getProviderCollectionMultimapKey())
+ || key.equals(getJavaxProviderCollectionMultimapKey())
+ || key.equals(entrySetBinder.getSetKey())
+ || key.equals(getEntrySetJavaxProviderKey())
+ || matchesValueKey(key);
+ }
+
+ /** Returns true if the key indicates this is a value in the map. */
+ private boolean matchesValueKey(Key<?> key) {
+ return key.getAnnotation() instanceof RealElement
+ && ((RealElement) key.getAnnotation()).setName().equals(entrySetBinder.getSetName())
+ && ((RealElement) key.getAnnotation()).type() == MAPBINDER
+ && ((RealElement) key.getAnnotation()).keyType().equals(keyType.toString())
+ && key.getTypeLiteral().equals(valueType);
+ }
+
+ private Key<Map<K, Provider<V>>> getProviderMapKey() {
+ Key<Map<K, Provider<V>>> local = providerMapKey;
+ if (local == null) {
+ local = providerMapKey = mapKey.ofType(mapOfProviderOf(keyType, valueType));
+ }
+ return local;
+ }
+
+ private Key<Map<K, javax.inject.Provider<V>>> getJavaxProviderMapKey() {
+ Key<Map<K, javax.inject.Provider<V>>> local = javaxProviderMapKey;
+ if (local == null) {
+ local = javaxProviderMapKey = mapKey.ofType(mapOfJavaxProviderOf(keyType, valueType));
+ }
+ return local;
+ }
+
+ private Key<Map<K, Set<V>>> getMultimapKey() {
+ Key<Map<K, Set<V>>> local = multimapKey;
+ if (local == null) {
+ local = multimapKey = mapKey.ofType(mapOf(keyType, setOf(valueType)));
+ }
+ return local;
+ }
+
+ private Key<Map<K, Set<Provider<V>>>> getProviderSetMultimapKey() {
+ Key<Map<K, Set<Provider<V>>>> local = providerSetMultimapKey;
+ if (local == null) {
+ local = providerSetMultimapKey = mapKey.ofType(mapOfSetOfProviderOf(keyType, valueType));
+ }
+ return local;
+ }
+
+ private Key<Map<K, Set<javax.inject.Provider<V>>>> getJavaxProviderSetMultimapKey() {
+ Key<Map<K, Set<javax.inject.Provider<V>>>> local = javaxProviderSetMultimapKey;
+ if (local == null) {
+ local =
+ javaxProviderSetMultimapKey =
+ mapKey.ofType(mapOfSetOfJavaxProviderOf(keyType, valueType));
+ }
+ return local;
+ }
+
+ private Key<Map<K, Collection<Provider<V>>>> getProviderCollectionMultimapKey() {
+ Key<Map<K, Collection<Provider<V>>>> local = providerCollectionMultimapKey;
+ if (local == null) {
+ local =
+ providerCollectionMultimapKey =
+ mapKey.ofType(mapOfCollectionOfProviderOf(keyType, valueType));
+ }
+ return local;
+ }
+
+ private Key<Map<K, Collection<javax.inject.Provider<V>>>>
+ getJavaxProviderCollectionMultimapKey() {
+ Key<Map<K, Collection<javax.inject.Provider<V>>>> local = javaxProviderCollectionMultimapKey;
+ if (local == null) {
+ local =
+ javaxProviderCollectionMultimapKey =
+ mapKey.ofType(mapOfCollectionOfJavaxProviderOf(keyType, valueType));
+ }
+ return local;
+ }
+
+ private Key<Set<Map.Entry<K, javax.inject.Provider<V>>>> getEntrySetJavaxProviderKey() {
+ Key<Set<Map.Entry<K, javax.inject.Provider<V>>>> local = entrySetJavaxProviderKey;
+ if (local == null) {
+ local =
+ entrySetJavaxProviderKey =
+ mapKey.ofType(setOfEntryOfJavaxProviderOf(keyType, valueType));
+ }
+ return local;
+ }
+
+ private ImmutableMap<K, Binding<V>> getMapBindings() {
+ checkConfiguration(isInitialized(), "MapBinder has not yet been initialized");
+ return mapBindings;
+ }
+
+ private ImmutableMap<K, Set<Binding<V>>> getMultimapBindings() {
+ checkConfiguration(isInitialized(), "MapBinder has not yet been initialized");
+ return multimapBindings;
+ }
+
+ private ImmutableList<Map.Entry<K, Binding<V>>> getEntries() {
+ checkConfiguration(isInitialized(), "MapBinder has not yet been initialized");
+ return entries;
+ }
+
+ private boolean isInitialized() {
+ return initializationState == InitializationState.INITIALIZED;
+ }
+
+ private TypeLiteral<K> getKeyType() {
+ return keyType;
+ }
+
+ private TypeLiteral<V> getValueType() {
+ return valueType;
+ }
+
+ private Key<Map<K, V>> getMapKey() {
+ return mapKey;
+ }
+
+ private RealMultibinder<Map.Entry<K, Provider<V>>> getEntrySetBinder() {
+ return entrySetBinder;
+ }
+
+ private boolean permitsDuplicates() {
+ if (isInitialized()) {
+ return permitsDuplicates;
+ } else {
+ throw new UnsupportedOperationException(
+ "permitsDuplicates() not supported for module bindings");
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof BindingSelection && ((BindingSelection<?, ?>) o).mapKey.equals(mapKey);
+ }
+
+ @Override
+ public int hashCode() {
+ return mapKey.hashCode();
+ }
+ }
+
+ private static final class RealProviderMapProvider<K, V>
+ extends RealMapBinderProviderWithDependencies<K, V, Map<K, Provider<V>>> {
+ private Map<K, Provider<V>> mapOfProviders;
+ private Set<Dependency<?>> dependencies = RealMapBinder.MODULE_DEPENDENCIES;
+
+ private RealProviderMapProvider(BindingSelection<K, V> bindingSelection) {
+ super(bindingSelection);
+ }
+
+ @Override
+ public Set<Dependency<?>> getDependencies() {
+ return dependencies;
+ }
+
+ @Override
+ protected void doInitialize(InjectorImpl injector, Errors errors) {
+ ImmutableMap.Builder<K, Provider<V>> mapOfProvidersBuilder = ImmutableMap.builder();
+ ImmutableSet.Builder<Dependency<?>> dependenciesBuilder = ImmutableSet.builder();
+ for (Map.Entry<K, Binding<V>> entry : bindingSelection.getMapBindings().entrySet()) {
+ mapOfProvidersBuilder.put(entry.getKey(), entry.getValue().getProvider());
+ dependenciesBuilder.add(Dependency.get(getKeyOfProvider(entry.getValue().getKey())));
+ }
+
+ mapOfProviders = mapOfProvidersBuilder.build();
+ dependencies = dependenciesBuilder.build();
+ }
+
+ @Override
+ protected Map<K, Provider<V>> doProvision(InternalContext context, Dependency<?> dependency) {
+ return mapOfProviders;
+ }
+ }
+
+ private static final class RealMapProvider<K, V>
+ extends RealMapBinderProviderWithDependencies<K, V, Map<K, V>>
+ implements ProviderWithExtensionVisitor<Map<K, V>>, MapBinderBinding<Map<K, V>> {
+ private Set<Dependency<?>> dependencies = RealMapBinder.MODULE_DEPENDENCIES;
+
+ /**
+ * An array of all the injectors.
+ *
+ * <p>This is parallel to array of keys below
+ */
+ private SingleParameterInjector<V>[] injectors;
+
+ private K[] keys;
+
+ private RealMapProvider(BindingSelection<K, V> bindingSelection) {
+ super(bindingSelection);
+ }
+
+ private BindingSelection<K, V> getBindingSelection() {
+ return bindingSelection;
+ }
+
+ @Override
+ protected void doInitialize(InjectorImpl injector, Errors errors) throws ErrorsException {
+ @SuppressWarnings("unchecked")
+ K[] keysArray = (K[]) new Object[bindingSelection.getMapBindings().size()];
+ keys = keysArray;
+ ImmutableSet.Builder<Dependency<?>> dependenciesBuilder = ImmutableSet.builder();
+ int i = 0;
+ for (Map.Entry<K, Binding<V>> entry : bindingSelection.getMapBindings().entrySet()) {
+ dependenciesBuilder.add(Dependency.get(entry.getValue().getKey()));
+ keys[i] = entry.getKey();
+ i++;
+ }
+
+ ImmutableSet<Dependency<?>> localDependencies = dependenciesBuilder.build();
+ dependencies = localDependencies;
+
+ List<Dependency<?>> dependenciesList = localDependencies.asList();
+
+ // We know the type because we built up our own sets of dependencies, it's just
+ // that the interface uses a "?" generic
+ @SuppressWarnings("unchecked")
+ SingleParameterInjector<V>[] typedInjectors =
+ (SingleParameterInjector<V>[]) injector.getParametersInjectors(dependenciesList, errors);
+ injectors = typedInjectors;
+ }
+
+ @Override
+ protected Map<K, V> doProvision(InternalContext context, Dependency<?> dependency)
+ throws InternalProvisionException {
+ SingleParameterInjector<V>[] localInjectors = injectors;
+ if (localInjectors == null) {
+ // if injectors == null, then we have no bindings so return the empty map.
+ return ImmutableMap.of();
+ }
+
+ ImmutableMap.Builder<K, V> resultBuilder = ImmutableMap.builder();
+ K[] localKeys = keys;
+ for (int i = 0; i < localInjectors.length; i++) {
+ SingleParameterInjector<V> injector = localInjectors[i];
+ K key = localKeys[i];
+
+ V value = injector.inject(context);
+
+ if (value == null) {
+ throw createNullValueException(key, bindingSelection.getMapBindings().get(key));
+ }
+
+ resultBuilder.put(key, value);
+ }
+
+ return resultBuilder.build();
+ }
+
+ @Override
+ public Set<Dependency<?>> getDependencies() {
+ return dependencies;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public <B, W> W acceptExtensionVisitor(
+ BindingTargetVisitor<B, W> visitor, ProviderInstanceBinding<? extends B> binding) {
+ if (visitor instanceof MultibindingsTargetVisitor) {
+ return ((MultibindingsTargetVisitor<Map<K, V>, W>) visitor).visit(this);
+ } else {
+ return visitor.visit(binding);
+ }
+ }
+
+ @Override
+ public Key<Map<K, V>> getMapKey() {
+ return bindingSelection.getMapKey();
+ }
+
+ @Override
+ public TypeLiteral<K> getKeyTypeLiteral() {
+ return bindingSelection.getKeyType();
+ }
+
+ @Override
+ public TypeLiteral<V> getValueTypeLiteral() {
+ return bindingSelection.getValueType();
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public List<Map.Entry<?, Binding<?>>> getEntries() {
+ if (bindingSelection.isInitialized()) {
+ return (List<Map.Entry<?, Binding<?>>>) (List<?>) bindingSelection.getEntries();
+ } else {
+ throw new UnsupportedOperationException("getEntries() not supported for module bindings");
+ }
+ }
+
+ @Override
+ public List<Map.Entry<?, Binding<?>>> getEntries(Iterable<? extends Element> elements) {
+ // Iterate over the elements, building up the below maps
+ // This is a preprocessing step allowing us to only iterate over elements
+ // once and have O(n) runtime
+ ImmutableMultimap.Builder<K, Key<V>> keyToValueKeyBuilder = ImmutableMultimap.builder();
+ ImmutableMap.Builder<Key<V>, Binding<V>> valueKeyToBindingBuilder = ImmutableMap.builder();
+ ImmutableMap.Builder<Key<V>, K> valueKeyToKeyBuilder = ImmutableMap.builder();
+ ImmutableMap.Builder<Key<V>, Binding<Map.Entry<K, Provider<V>>>>
+ valueKeyToEntryBindingBuilder = ImmutableMap.builder();
+ for (Element element : elements) {
+ if (element instanceof Binding) {
+ Binding<?> binding = (Binding<?>) element;
+ if (bindingSelection.matchesValueKey(binding.getKey())
+ && binding.getKey().getTypeLiteral().equals(bindingSelection.valueType)) {
+ // Safe because of the check on the type literal above
+ @SuppressWarnings("unchecked")
+ Binding<V> typedBinding = (Binding<V>) binding;
+ Key<V> typedKey = typedBinding.getKey();
+ valueKeyToBindingBuilder.put(typedKey, typedBinding);
+ }
+ }
+
+ if (element instanceof ProviderInstanceBinding
+ && bindingSelection.getEntrySetBinder().containsElement(element)) {
+ // Safe because of the instanceof check, and containsElement() check
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ ProviderInstanceBinding<Map.Entry<K, Provider<V>>> entryBinding =
+ (ProviderInstanceBinding) element;
+
+ // Safe because of the check for containsElement() above
+ @SuppressWarnings("unchecked")
+ Provider<Map.Entry<K, Provider<V>>> typedProvider =
+ (Provider<Map.Entry<K, Provider<V>>>) entryBinding.getUserSuppliedProvider();
+ Provider<Map.Entry<K, Provider<V>>> userSuppliedProvider = typedProvider;
+
+ if (userSuppliedProvider instanceof ProviderMapEntry) {
+ // Safe because of the instanceof check
+ @SuppressWarnings("unchecked")
+ ProviderMapEntry<K, V> typedUserSuppliedProvider =
+ (ProviderMapEntry<K, V>) userSuppliedProvider;
+ ProviderMapEntry<K, V> entry = typedUserSuppliedProvider;
+
+ keyToValueKeyBuilder.put(entry.getKey(), entry.getValueKey());
+ valueKeyToEntryBindingBuilder.put(entry.getValueKey(), entryBinding);
+ valueKeyToKeyBuilder.put(entry.getValueKey(), entry.getKey());
+ }
+ }
+ }
+
+ ImmutableMultimap<K, Key<V>> keyToValueKey = keyToValueKeyBuilder.build();
+ ImmutableMap<Key<V>, K> valueKeyToKey = valueKeyToKeyBuilder.build();
+ ImmutableMap<Key<V>, Binding<V>> valueKeyToBinding = valueKeyToBindingBuilder.build();
+ ImmutableMap<Key<V>, Binding<Map.Entry<K, Provider<V>>>> valueKeyToEntryBinding =
+ valueKeyToEntryBindingBuilder.build();
+
+ // Check that there is a 1:1 mapping from keys from the ProviderMapEntrys to the
+ // keys from the Bindings.
+ Set<Key<V>> keysFromProviderMapEntrys = Sets.newHashSet(keyToValueKey.values());
+ Set<Key<V>> keysFromBindings = valueKeyToBinding.keySet();
+
+ if (!keysFromProviderMapEntrys.equals(keysFromBindings)) {
+ Set<Key<V>> keysOnlyFromProviderMapEntrys =
+ Sets.difference(keysFromProviderMapEntrys, keysFromBindings);
+ Set<Key<V>> keysOnlyFromBindings =
+ Sets.difference(keysFromBindings, keysFromProviderMapEntrys);
+
+ StringBuilder sb = new StringBuilder("Expected a 1:1 mapping from map keys to values.");
+
+ if (!keysOnlyFromBindings.isEmpty()) {
+ sb.append(
+ Errors.format("%nFound these Bindings that were missing an associated entry:%n"));
+ for (Key<V> key : keysOnlyFromBindings) {
+ sb.append(
+ Errors.format(" %s bound at: %s%n", key, valueKeyToBinding.get(key).getSource()));
+ }
+ }
+
+ if (!keysOnlyFromProviderMapEntrys.isEmpty()) {
+ sb.append(Errors.format("%nFound these map keys without a corresponding value:%n"));
+ for (Key<V> key : keysOnlyFromProviderMapEntrys) {
+ sb.append(
+ Errors.format(
+ " '%s' bound at: %s%n",
+ valueKeyToKey.get(key), valueKeyToEntryBinding.get(key).getSource()));
+ }
+ }
+
+ throw new IllegalArgumentException(sb.toString());
+ }
+
+ // Now that we have the two maps, generate the result map
+ ImmutableList.Builder<Map.Entry<?, Binding<?>>> resultBuilder = ImmutableList.builder();
+ for (Map.Entry<K, Key<V>> entry : keyToValueKey.entries()) {
+ Binding<?> binding = valueKeyToBinding.get(entry.getValue());
+ // No null check for binding needed because of the above check to make sure all the
+ // values in keyToValueKey are present as keys in valueKeyToBinding
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ Map.Entry<?, Binding<?>> newEntry =
+ (Map.Entry) Maps.immutableEntry(entry.getKey(), binding);
+ resultBuilder.add(newEntry);
+ }
+ return resultBuilder.build();
+ }
+
+ @Override
+ public boolean permitsDuplicates() {
+ if (bindingSelection.isInitialized()) {
+ return bindingSelection.permitsDuplicates();
+ } else {
+ throw new UnsupportedOperationException(
+ "permitsDuplicates() not supported for module bindings");
+ }
+ }
+
+ @Override
+ public boolean containsElement(Element element) {
+ return bindingSelection.containsElement(element);
+ }
+ }
+
+ /**
+ * Binds {@code Map<K, Set<V>>} and {{@code Map<K, Set<Provider<V>>>}.
+ *
+ * <p>This will only exist if permitDuplicates() is called.
+ */
+ private static final class MultimapBinder<K, V> implements Module {
+ private final BindingSelection<K, V> bindingSelection;
+
+ private MultimapBinder(BindingSelection<K, V> bindingSelection) {
+ this.bindingSelection = bindingSelection;
+ }
+
+ @Override
+ public void configure(Binder binder) {
+ // Binds a Map<K, Set<Provider<V>>>
+ Provider<Map<K, Set<Provider<V>>>> multimapProvider =
+ new RealProviderMultimapProvider<K, V>(bindingSelection.getMapKey());
+ binder.bind(bindingSelection.getProviderSetMultimapKey()).toProvider(multimapProvider);
+
+ // Provide links from a few different public keys to the providerMultimapKey.
+ // The collection this exposes is internally an ImmutableMap, so it's OK to massage
+ // the guice Provider to javax Provider in the value (since the guice Provider implements
+ // javax Provider).
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ Provider<Map<K, Set<javax.inject.Provider<V>>>> javaxProvider = (Provider) multimapProvider;
+ binder.bind(bindingSelection.getJavaxProviderSetMultimapKey()).toProvider(javaxProvider);
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ Provider<Map<K, Collection<Provider<V>>>> collectionProvider = (Provider) multimapProvider;
+ binder
+ .bind(bindingSelection.getProviderCollectionMultimapKey())
+ .toProvider(collectionProvider);
+
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ Provider<Map<K, Collection<javax.inject.Provider<V>>>> collectionJavaxProvider =
+ (Provider) multimapProvider;
+ binder
+ .bind(bindingSelection.getJavaxProviderCollectionMultimapKey())
+ .toProvider(collectionJavaxProvider);
+
+ // Binds a Map<K, Set<V>>
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ Provider<Map<K, Set<V>>> realMultimapProvider =
+ new RealMultimapProvider(bindingSelection.getMapKey());
+ binder.bind(bindingSelection.getMultimapKey()).toProvider(realMultimapProvider);
+ }
+
+ @Override
+ public int hashCode() {
+ return bindingSelection.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof MultimapBinder
+ && ((MultimapBinder<?, ?>) o).bindingSelection.equals(bindingSelection);
+ }
+
+ private static final class RealProviderMultimapProvider<K, V>
+ extends RealMultimapBinderProviderWithDependencies<K, V, Map<K, Set<Provider<V>>>> {
+ private Map<K, Set<Provider<V>>> multimapOfProviders;
+ private Set<Dependency<?>> dependencies = RealMapBinder.MODULE_DEPENDENCIES;
+
+ private RealProviderMultimapProvider(Key<Map<K, V>> mapKey) {
+ super(mapKey);
+ }
+
+ @Override
+ public Set<Dependency<?>> getDependencies() {
+ return dependencies;
+ }
+
+ @Override
+ protected void doInitialize(InjectorImpl injector, Errors errors) {
+ ImmutableMap.Builder<K, Set<Provider<V>>> multimapOfProvidersBuilder =
+ ImmutableMap.builder();
+ ImmutableSet.Builder<Dependency<?>> dependenciesBuilder = ImmutableSet.builder();
+ for (Map.Entry<K, Set<Binding<V>>> entry :
+ bindingSelection.getMultimapBindings().entrySet()) {
+ ImmutableSet.Builder<Provider<V>> providersBuilder = ImmutableSet.builder();
+ for (Binding<V> binding : entry.getValue()) {
+ providersBuilder.add(binding.getProvider());
+ dependenciesBuilder.add(Dependency.get(getKeyOfProvider(binding.getKey())));
+ }
+
+ multimapOfProvidersBuilder.put(entry.getKey(), providersBuilder.build());
+ }
+ multimapOfProviders = multimapOfProvidersBuilder.build();
+ dependencies = dependenciesBuilder.build();
+ }
+
+ @Override
+ protected Map<K, Set<Provider<V>>> doProvision(
+ InternalContext context, Dependency<?> dependency) {
+ return multimapOfProviders;
+ }
+ }
+
+ private static final class RealMultimapProvider<K, V>
+ extends RealMultimapBinderProviderWithDependencies<K, V, Map<K, Set<V>>> {
+
+ /**
+ * A simple class to hold a key and the associated bindings as an array.
+ *
+ * <p>Arrays are used for performance.
+ */
+ private static final class PerKeyData<K, V> {
+ private final K key;
+ private final Binding<V>[] bindings;
+ private final SingleParameterInjector<V>[] injectors;
+
+ private PerKeyData(K key, Binding<V>[] bindings, SingleParameterInjector<V>[] injectors) {
+ Preconditions.checkArgument(bindings.length == injectors.length);
+
+ this.key = key;
+ this.bindings = bindings;
+ this.injectors = injectors;
+ }
+ }
+
+ private Set<Dependency<?>> dependencies = RealMapBinder.MODULE_DEPENDENCIES;
+
+ private PerKeyData<K, V>[] perKeyDatas;
+
+ private RealMultimapProvider(Key<Map<K, V>> mapKey) {
+ super(mapKey);
+ }
+
+ @Override
+ public Set<Dependency<?>> getDependencies() {
+ return dependencies;
+ }
+
+ @Override
+ protected void doInitialize(InjectorImpl injector, Errors errors) throws ErrorsException {
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ PerKeyData<K, V>[] typedPerKeyData =
+ new PerKeyData[bindingSelection.getMapBindings().size()];
+ perKeyDatas = typedPerKeyData;
+ ImmutableSet.Builder<Dependency<?>> dependenciesBuilder = ImmutableSet.builder();
+ List<Dependency<?>> dependenciesForKey = Lists.newArrayList();
+ int i = 0;
+ for (Map.Entry<K, Set<Binding<V>>> entry :
+ bindingSelection.getMultimapBindings().entrySet()) {
+ // Clear the list of dependencies because we're reusing it for each different key
+ dependenciesForKey.clear();
+
+ Set<Binding<V>> bindings = entry.getValue();
+ @SuppressWarnings({"unchecked", "rawtypes"})
+ Binding<V>[] typedBindings = new Binding[bindings.size()];
+ Binding<V>[] bindingsArray = typedBindings;
+ int j = 0;
+ for (Binding<V> binding : bindings) {
+ Dependency<V> dependency = Dependency.get(binding.getKey());
+ dependenciesBuilder.add(dependency);
+ dependenciesForKey.add(dependency);
+ bindingsArray[j] = binding;
+ j++;
+ }
+
+ @SuppressWarnings("unchecked")
+ SingleParameterInjector<V>[] injectors =
+ (SingleParameterInjector<V>[])
+ injector.getParametersInjectors(dependenciesForKey, errors);
+
+ perKeyDatas[i] = new PerKeyData<>(entry.getKey(), bindingsArray, injectors);
+ i++;
+ }
+
+ dependencies = dependenciesBuilder.build();
+ }
+
+ @Override
+ protected Map<K, Set<V>> doProvision(InternalContext context, Dependency<?> dependency)
+ throws InternalProvisionException {
+ ImmutableMap.Builder<K, Set<V>> resultBuilder = ImmutableMap.builder();
+
+ for (PerKeyData<K, V> perKeyData : perKeyDatas) {
+ ImmutableSet.Builder<V> bindingsBuilder = ImmutableSet.builder();
+ SingleParameterInjector<V>[] injectors = perKeyData.injectors;
+ for (int i = 0; i < injectors.length; i++) {
+ SingleParameterInjector<V> injector = injectors[i];
+ V value = injector.inject(context);
+
+ if (value == null) {
+ throw createNullValueException(perKeyData.key, perKeyData.bindings[i]);
+ }
+
+ bindingsBuilder.add(value);
+ }
+
+ resultBuilder.put(perKeyData.key, bindingsBuilder.build());
+ }
+
+ return resultBuilder.build();
+ }
+ }
+ }
+
+ /** A factory for a {@code Map.Entry<K, Provider<V>>}. */
+ //VisibleForTesting
+ static final class ProviderMapEntry<K, V>
+ extends InternalProviderInstanceBindingImpl.Factory<Map.Entry<K, Provider<V>>> {
+ private final K key;
+ private final Key<V> valueKey;
+ private Map.Entry<K, Provider<V>> entry;
+
+ ProviderMapEntry(K key, Key<V> valueKey) {
+ super(InitializationTiming.EAGER);
+ this.key = key;
+ this.valueKey = valueKey;
+ }
+
+ @Override
+ public Set<Dependency<?>> getDependencies() {
+ // The dependencies are Key<Provider<V>>
+ return ImmutableSet.<Dependency<?>>of(Dependency.get(getKeyOfProvider(valueKey)));
+ }
+
+ @Override
+ void initialize(InjectorImpl injector, Errors errors) {
+ Binding<V> valueBinding = injector.getExistingBinding(valueKey);
+ entry = Maps.immutableEntry(key, valueBinding.getProvider());
+ }
+
+ @Override
+ protected Map.Entry<K, Provider<V>> doProvision(
+ InternalContext context, Dependency<?> dependency) {
+ return entry;
+ }
+
+ K getKey() {
+ return key;
+ }
+
+ Key<V> getValueKey() {
+ return valueKey;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof ProviderMapEntry) {
+ ProviderMapEntry<?, ?> o = (ProviderMapEntry<?, ?>) obj;
+ return key.equals(o.key) && valueKey.equals(o.valueKey);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(key, valueKey);
+ }
+
+ @Override
+ public String toString() {
+ return "ProviderMapEntry(" + key + ", " + valueKey + ")";
+ }
+ }
+
+ /** A base class for ProviderWithDependencies that need equality based on a specific object. */
+ private abstract static class RealMapBinderProviderWithDependencies<K, V, P>
+ extends InternalProviderInstanceBindingImpl.Factory<P> {
+ final BindingSelection<K, V> bindingSelection;
+
+ private RealMapBinderProviderWithDependencies(BindingSelection<K, V> bindingSelection) {
+ // While MapBinders only depend on bindings created in modules so we could theoretically
+ // initialize eagerly, they also depend on
+ // 1. findBindingsByType returning results
+ // 2. being able to call BindingImpl.acceptTargetVisitor
+ // neither of those is available during eager initialization, so we use DELAYED
+ super(InitializationTiming.DELAYED);
+
+ this.bindingSelection = bindingSelection;
+ }
+
+ @Override
+ final void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
+ if (bindingSelection.tryInitialize(injector, errors)) {
+ doInitialize(injector, errors);
+ }
+ }
+
+ /**
+ * Initialize the factory. BindingSelection is guaranteed to be initialized at this point and
+ * this will be called prior to any provisioning.
+ */
+ protected abstract void doInitialize(InjectorImpl injector, Errors errors)
+ throws ErrorsException;
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null
+ && this.getClass() == obj.getClass()
+ && bindingSelection.equals(
+ ((RealMapBinderProviderWithDependencies<?, ?, ?>) obj).bindingSelection);
+ }
+
+ @Override
+ public int hashCode() {
+ return bindingSelection.hashCode();
+ }
+ }
+
+ /**
+ * A base class for ProviderWithDependencies that need equality based on a specific object.
+ *
+ * <p>This differs from {@link RealMapBinderProviderWithDependencies} in that it gets the {@code
+ * bindingSelection} from the injector at initialization time, rather than in the constructor.
+ * This is done to allow all the providers to operate on the same instance of the {@link
+ * BindingSelection}.
+ */
+ private abstract static class RealMultimapBinderProviderWithDependencies<K, V, P>
+ extends InternalProviderInstanceBindingImpl.Factory<P> {
+ final Key<Map<K, V>> mapKey;
+ BindingSelection<K, V> bindingSelection;
+
+ private RealMultimapBinderProviderWithDependencies(Key<Map<K, V>> mapKey) {
+ // While MapBinders only depend on bindings created in modules so we could theoretically
+ // initialize eagerly, they also depend on
+ // 1. findBindingsByType returning results
+ // 2. being able to call BindingImpl.acceptTargetVisitor
+ // neither of those is available during eager initialization, so we use DELAYED
+ super(InitializationTiming.DELAYED);
+
+ this.mapKey = mapKey;
+ }
+
+ /**
+ * This will get the authoritative {@link BindingSelection} from the map provider. This
+ * guarantees that everyone has the same instance of the bindingSelection and sees consistent
+ * state.
+ */
+ @Override
+ final void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
+ Binding<Map<K, V>> mapBinding = injector.getExistingBinding(mapKey);
+ ProviderInstanceBinding<Map<K, V>> providerInstanceBinding =
+ (ProviderInstanceBinding<Map<K, V>>) mapBinding;
+ @SuppressWarnings("unchecked")
+ RealMapProvider<K, V> mapProvider =
+ (RealMapProvider<K, V>) providerInstanceBinding.getUserSuppliedProvider();
+
+ this.bindingSelection = mapProvider.getBindingSelection();
+
+ if (bindingSelection.tryInitialize(injector, errors)) {
+ doInitialize(injector, errors);
+ }
+ }
+
+ /**
+ * Initialize the factory. BindingSelection is guaranteed to be initialized at this point and
+ * this will be called prior to any provisioning.
+ */
+ abstract void doInitialize(InjectorImpl injector, Errors errors) throws ErrorsException;
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null
+ && this.getClass() == obj.getClass()
+ && mapKey.equals(((RealMultimapBinderProviderWithDependencies<?, ?, ?>) obj).mapKey);
+ }
+
+ @Override
+ public int hashCode() {
+ return mapKey.hashCode();
+ }
+ }
+
+ private static <K, V> InternalProvisionException createNullValueException(
+ K key, Binding<V> binding) {
+ return InternalProvisionException.create(
+ "Map injection failed due to null value for key \"%s\", bound at: %s",
+ key, binding.getSource());
+ }
+}
diff --git a/core/src/com/google/inject/internal/RealMultibinder.java b/core/src/com/google/inject/internal/RealMultibinder.java
new file mode 100644
index 00000000..aa887f4e
--- /dev/null
+++ b/core/src/com/google/inject/internal/RealMultibinder.java
@@ -0,0 +1,604 @@
+package com.google.inject.internal;
+
+import static com.google.inject.internal.Element.Type.MULTIBINDER;
+import static com.google.inject.internal.Errors.checkConfiguration;
+import static com.google.inject.internal.Errors.checkNotNull;
+import static com.google.inject.name.Names.named;
+
+import com.google.common.base.Objects;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
+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;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.Provider;
+import com.google.inject.TypeLiteral;
+import com.google.inject.binder.LinkedBindingBuilder;
+import com.google.inject.internal.InternalProviderInstanceBindingImpl.InitializationTiming;
+import com.google.inject.multibindings.MultibinderBinding;
+import com.google.inject.multibindings.MultibindingsTargetVisitor;
+import com.google.inject.spi.BindingTargetVisitor;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.ProviderInstanceBinding;
+import com.google.inject.spi.ProviderWithExtensionVisitor;
+import com.google.inject.util.Types;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * The actual multibinder plays several roles:
+ *
+ * <p>As a Multibinder, it acts as a factory for LinkedBindingBuilders for each of the set's
+ * elements. Each binding is given an annotation that identifies it as a part of this set.
+ *
+ * <p>As a Module, it installs the binding to the set itself. As a module, this implements equals()
+ * and hashcode() in order to trick Guice into executing its configure() method only once. That
+ * makes it so that multiple multibinders can be created for the same target collection, but only
+ * one is bound. Since the list of bindings is retrieved from the injector itself (and not the
+ * multibinder), each multibinder has access to all contributions from all multibinders.
+ *
+ * <p>As a Provider, this constructs the set instances.
+ *
+ * <p>We use a subclass to hide 'implements Module, Provider' from the public API.
+ */
+public final class RealMultibinder<T> implements Module {
+
+ /** Implementation of newSetBinder. */
+ public static <T> RealMultibinder<T> newRealSetBinder(Binder binder, Key<T> key) {
+ binder = binder.skipSources(RealMultibinder.class);
+ RealMultibinder<T> result = new RealMultibinder<>(binder, key);
+ binder.install(result);
+ return result;
+ }
+
+ @SuppressWarnings("unchecked") // wrapping a T in a Set safely returns a Set<T>
+ static <T> TypeLiteral<Set<T>> setOf(TypeLiteral<T> elementType) {
+ Type type = Types.setOf(elementType.getType());
+ return (TypeLiteral<Set<T>>) TypeLiteral.get(type);
+ }
+
+ @SuppressWarnings("unchecked")
+ static <T> TypeLiteral<Collection<Provider<T>>> collectionOfProvidersOf(
+ TypeLiteral<T> elementType) {
+ Type providerType = Types.providerOf(elementType.getType());
+ Type type = Types.collectionOf(providerType);
+ return (TypeLiteral<Collection<Provider<T>>>) TypeLiteral.get(type);
+ }
+
+ @SuppressWarnings("unchecked")
+ static <T> TypeLiteral<Collection<javax.inject.Provider<T>>> collectionOfJavaxProvidersOf(
+ TypeLiteral<T> elementType) {
+ Type providerType =
+ Types.newParameterizedType(javax.inject.Provider.class, elementType.getType());
+ Type type = Types.collectionOf(providerType);
+ return (TypeLiteral<Collection<javax.inject.Provider<T>>>) TypeLiteral.get(type);
+ }
+
+ private final BindingSelection<T> bindingSelection;
+ private final Binder binder;
+
+ RealMultibinder(Binder binder, Key<T> key) {
+ this.binder = checkNotNull(binder, "binder");
+ this.bindingSelection = new BindingSelection<>(key);
+ }
+
+ @Override
+ public void configure(Binder binder) {
+ checkConfiguration(!bindingSelection.isInitialized(), "Multibinder was already initialized");
+ binder
+ .bind(bindingSelection.getSetKey())
+ .toProvider(new RealMultibinderProvider<T>(bindingSelection));
+ Provider<Collection<Provider<T>>> collectionOfProvidersProvider =
+ new RealMultibinderCollectionOfProvidersProvider<T>(bindingSelection);
+ binder
+ .bind(bindingSelection.getCollectionOfProvidersKey())
+ .toProvider(collectionOfProvidersProvider);
+
+ // The collection this exposes is internally an ImmutableList, so it's OK to massage
+ // the guice Provider to javax Provider in the value (since the guice Provider implements
+ // javax Provider).
+ @SuppressWarnings("unchecked")
+ Provider<Collection<javax.inject.Provider<T>>> javaxProvider =
+ (Provider) collectionOfProvidersProvider;
+ binder.bind(bindingSelection.getCollectionOfJavaxProvidersKey()).toProvider(javaxProvider);
+ }
+
+ public void permitDuplicates() {
+ binder.install(new PermitDuplicatesModule(bindingSelection.getPermitDuplicatesKey()));
+ }
+
+ /** Adds a new entry to the set and returns the key for it. */
+ Key<T> getKeyForNewItem() {
+ checkConfiguration(!bindingSelection.isInitialized(), "Multibinder was already initialized");
+ return Key.get(
+ bindingSelection.getElementTypeLiteral(),
+ new RealElement(bindingSelection.getSetName(), MULTIBINDER, ""));
+ }
+
+ public LinkedBindingBuilder<T> addBinding() {
+ return binder.bind(getKeyForNewItem());
+ }
+
+ // These methods are used by RealMapBinder
+
+ Key<Set<T>> getSetKey() {
+ return bindingSelection.getSetKey();
+ }
+
+ TypeLiteral<T> getElementTypeLiteral() {
+ return bindingSelection.getElementTypeLiteral();
+ }
+
+ String getSetName() {
+ return bindingSelection.getSetName();
+ }
+
+ boolean permitsDuplicates(Injector injector) {
+ return bindingSelection.permitsDuplicates(injector);
+ }
+
+ boolean containsElement(com.google.inject.spi.Element element) {
+ return bindingSelection.containsElement(element);
+ }
+
+ private static final class RealMultibinderProvider<T>
+ extends InternalProviderInstanceBindingImpl.Factory<Set<T>>
+ implements ProviderWithExtensionVisitor<Set<T>>, MultibinderBinding<Set<T>> {
+ private final BindingSelection<T> bindingSelection;
+ private List<Binding<T>> bindings;
+ private SingleParameterInjector<T>[] injectors;
+ private boolean permitDuplicates;
+
+ RealMultibinderProvider(BindingSelection<T> bindingSelection) {
+ // While Multibinders only depend on bindings created in modules so we could theoretically
+ // initialize eagerly, they also depend on
+ // 1. findBindingsByType returning results
+ // 2. being able to call BindingImpl.acceptTargetVisitor
+ // neither of those is available during eager initialization, so we use DELAYED
+ super(InitializationTiming.DELAYED);
+ this.bindingSelection = bindingSelection;
+ }
+
+ @Override
+ public Set<Dependency<?>> getDependencies() {
+ return bindingSelection.getDependencies();
+ }
+
+ @Override
+ void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
+ bindingSelection.initialize(injector, errors);
+ this.bindings = bindingSelection.getBindings();
+ this.injectors = bindingSelection.getParameterInjectors();
+ this.permitDuplicates = bindingSelection.permitsDuplicates();
+ }
+
+ @Override
+ protected Set<T> doProvision(InternalContext context, Dependency<?> dependency)
+ throws InternalProvisionException {
+ SingleParameterInjector<T>[] localInjectors = injectors;
+ if (localInjectors == null) {
+ // if localInjectors == null, then we have no bindings so return the empty set.
+ return ImmutableSet.of();
+ }
+ // Ideally we would just add to an ImmutableSet.Builder, but if we did that and there were
+ // duplicates we wouldn't be able to tell which one was the duplicate. So to manage this we
+ // first put everything into an array and then construct the set. This way if something gets
+ // dropped we can figure out what it is.
+ @SuppressWarnings("unchecked")
+ T[] values = (T[]) new Object[localInjectors.length];
+ for (int i = 0; i < localInjectors.length; i++) {
+ SingleParameterInjector<T> parameterInjector = localInjectors[i];
+ T newValue = parameterInjector.inject(context);
+ if (newValue == null) {
+ throw newNullEntryException(i);
+ }
+ values[i] = newValue;
+ }
+ ImmutableSet<T> set = ImmutableSet.copyOf(values);
+ // There are fewer items in the set than the array. Figure out which one got dropped.
+ if (!permitDuplicates && set.size() < values.length) {
+ throw newDuplicateValuesException(set, values);
+ }
+ return set;
+ }
+
+ private InternalProvisionException newNullEntryException(int i) {
+ return InternalProvisionException.create(
+ "Set injection failed due to null element bound at: %s", bindings.get(i).getSource());
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <B, V> V acceptExtensionVisitor(
+ BindingTargetVisitor<B, V> visitor, ProviderInstanceBinding<? extends B> binding) {
+ if (visitor instanceof MultibindingsTargetVisitor) {
+ return ((MultibindingsTargetVisitor<Set<T>, V>) visitor).visit(this);
+ } else {
+ return visitor.visit(binding);
+ }
+ }
+
+ private InternalProvisionException newDuplicateValuesException(
+ ImmutableSet<T> set, T[] values) {
+ // TODO(lukes): consider reporting all duplicate values, the easiest way would be to rebuild
+ // a new set and detect dupes as we go
+ // Find the duplicate binding
+ // To do this we take advantage of the fact that set, values and bindings all have the same
+ // ordering for a non-empty prefix of the set.
+ // First we scan for the first item dropped from the set.
+ int newBindingIndex = 0;
+ for (T item : set) {
+ if (item != values[newBindingIndex]) {
+ break;
+ }
+ newBindingIndex++;
+ }
+ // once we exit the loop newBindingIndex will point at the first item in values that was
+ // dropped.
+
+ Binding<T> newBinding = bindings.get(newBindingIndex);
+ T newValue = values[newBindingIndex];
+ // Now we scan again to find the index of the value, we are guaranteed to find it.
+ int oldBindingIndex = set.asList().indexOf(newValue);
+ T oldValue = values[oldBindingIndex];
+ Binding<T> duplicateBinding = bindings.get(oldBindingIndex);
+ String oldString = oldValue.toString();
+ String newString = newValue.toString();
+ if (Objects.equal(oldString, newString)) {
+ // When the value strings match, just show the source of the bindings
+ return InternalProvisionException.create(
+ "Set injection failed due to duplicated element \"%s\""
+ + "\n Bound at %s\n Bound at %s",
+ newValue, duplicateBinding.getSource(), newBinding.getSource());
+ } else {
+ // When the value strings don't match, include them both as they may be useful for debugging
+ return InternalProvisionException.create(
+ "Set injection failed due to multiple elements comparing equal:"
+ + "\n \"%s\"\n bound at %s"
+ + "\n \"%s\"\n bound at %s",
+ oldValue, duplicateBinding.getSource(), newValue, newBinding.getSource());
+ }
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof RealMultibinderProvider
+ && bindingSelection.equals(((RealMultibinderProvider<?>) obj).bindingSelection);
+ }
+
+ @Override
+ public int hashCode() {
+ return bindingSelection.hashCode();
+ }
+
+ @Override
+ public Key<Set<T>> getSetKey() {
+ return bindingSelection.getSetKey();
+ }
+
+ @Override
+ public TypeLiteral<?> getElementTypeLiteral() {
+ return bindingSelection.getElementTypeLiteral();
+ }
+
+ @Override
+ public List<Binding<?>> getElements() {
+ return bindingSelection.getElements();
+ }
+
+ @Override
+ public boolean permitsDuplicates() {
+ return bindingSelection.permitsDuplicates();
+ }
+
+ @Override
+ public boolean containsElement(com.google.inject.spi.Element element) {
+ return bindingSelection.containsElement(element);
+ }
+ }
+
+ private static final class BindingSelection<T> {
+ // prior to initialization we declare just a dependency on the injector, but as soon as we are
+ // initialized we swap to dependencies on the elements.
+ private static final ImmutableSet<Dependency<?>> MODULE_DEPENDENCIES =
+ ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class)));
+ private final TypeLiteral<T> elementType;
+ private final Key<Set<T>> setKey;
+
+ // these are all lazily allocated
+ private String setName;
+ private Key<Collection<Provider<T>>> collectionOfProvidersKey;
+ private Key<Collection<javax.inject.Provider<T>>> collectionOfJavaxProvidersKey;
+ private Key<Boolean> permitDuplicatesKey;
+
+ private boolean isInitialized;
+ /* a binding for each element in the set. null until initialization, non-null afterwards */
+ private ImmutableList<Binding<T>> bindings;
+
+ // Starts out as Injector and gets set up properly after initialization
+ private ImmutableSet<Dependency<?>> dependencies = MODULE_DEPENDENCIES;
+ private ImmutableSet<Dependency<?>> providerDependencies = MODULE_DEPENDENCIES;
+
+ /** whether duplicates are allowed. Possibly configured by a different instance */
+ private boolean permitDuplicates;
+
+ private SingleParameterInjector<T>[] parameterinjectors;
+
+ BindingSelection(Key<T> key) {
+ this.setKey = key.ofType(setOf(key.getTypeLiteral()));
+ this.elementType = key.getTypeLiteral();
+ }
+
+ void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
+ // This will be called multiple times, once by each Factory. We only want
+ // to do the work to initialize everything once, so guard this code with
+ // isInitialized.
+ if (isInitialized) {
+ return;
+ }
+ List<Binding<T>> bindings = Lists.newArrayList();
+ Set<Indexer.IndexedBinding> index = Sets.newHashSet();
+ Indexer indexer = new Indexer(injector);
+ List<Dependency<?>> dependencies = Lists.newArrayList();
+ List<Dependency<?>> providerDependencies = Lists.newArrayList();
+ for (Binding<?> entry : injector.findBindingsByType(elementType)) {
+ if (keyMatches(entry.getKey())) {
+ @SuppressWarnings("unchecked") // protected by findBindingsByType()
+ Binding<T> binding = (Binding<T>) entry;
+ if (index.add(binding.acceptTargetVisitor(indexer))) {
+ // TODO(lukes): most of these are linked bindings since user bindings are linked to
+ // a user binding through the @Element annotation. Since this is an implementation
+ // detail we could 'dereference' the @Element if it is a LinkedBinding and avoid
+ // provisioning through the FactoryProxy at runtime.
+ // Ditto for OptionalBinder/MapBinder
+ bindings.add(binding);
+ Key<T> key = binding.getKey();
+ // TODO(lukes): we should mark this as a non-nullable dependency since we don't accept
+ // null.
+ // Add a dependency on Key<T>
+ dependencies.add(Dependency.get(key));
+ // and add a dependency on Key<Provider<T>>
+ providerDependencies.add(
+ Dependency.get(key.ofType(Types.providerOf(key.getTypeLiteral().getType()))));
+ }
+ }
+ }
+
+ this.bindings = ImmutableList.copyOf(bindings);
+ this.dependencies = ImmutableSet.copyOf(dependencies);
+ this.providerDependencies = ImmutableSet.copyOf(providerDependencies);
+ this.permitDuplicates = permitsDuplicates(injector);
+ // This is safe because all our dependencies are assignable to T and we never assign to
+ // elements of this array.
+ @SuppressWarnings("unchecked")
+ SingleParameterInjector<T>[] typed =
+ (SingleParameterInjector<T>[]) injector.getParametersInjectors(dependencies, errors);
+ this.parameterinjectors = typed;
+ isInitialized = true;
+ }
+
+ boolean permitsDuplicates(Injector injector) {
+ return injector.getBindings().containsKey(getPermitDuplicatesKey());
+ }
+
+ ImmutableList<Binding<T>> getBindings() {
+ checkConfiguration(isInitialized, "not initialized");
+ return bindings;
+ }
+
+ SingleParameterInjector<T>[] getParameterInjectors() {
+ checkConfiguration(isInitialized, "not initialized");
+ return parameterinjectors;
+ }
+
+ ImmutableSet<Dependency<?>> getDependencies() {
+ return dependencies;
+ }
+
+ ImmutableSet<Dependency<?>> getProviderDependencies() {
+ return providerDependencies;
+ }
+
+ String getSetName() {
+ // lazily initialized since most selectors don't survive module installation.
+ if (setName == null) {
+ setName = Annotations.nameOf(setKey);
+ }
+ return setName;
+ }
+
+ Key<Boolean> getPermitDuplicatesKey() {
+ Key<Boolean> local = permitDuplicatesKey;
+ if (local == null) {
+ local =
+ permitDuplicatesKey = Key.get(Boolean.class, named(toString() + " permits duplicates"));
+ }
+ return local;
+ }
+
+ Key<Collection<Provider<T>>> getCollectionOfProvidersKey() {
+ Key<Collection<Provider<T>>> local = collectionOfProvidersKey;
+ if (local == null) {
+ local = collectionOfProvidersKey = setKey.ofType(collectionOfProvidersOf(elementType));
+ }
+ return local;
+ }
+
+ Key<Collection<javax.inject.Provider<T>>> getCollectionOfJavaxProvidersKey() {
+ Key<Collection<javax.inject.Provider<T>>> local = collectionOfJavaxProvidersKey;
+ if (local == null) {
+ local =
+ collectionOfJavaxProvidersKey =
+ setKey.ofType(collectionOfJavaxProvidersOf(elementType));
+ }
+ return local;
+ }
+
+ boolean isInitialized() {
+ return isInitialized;
+ }
+
+ // MultibinderBinding API methods
+
+ TypeLiteral<T> getElementTypeLiteral() {
+ return elementType;
+ }
+
+ Key<Set<T>> getSetKey() {
+ return setKey;
+ }
+
+ @SuppressWarnings("unchecked")
+ List<Binding<?>> getElements() {
+ if (isInitialized()) {
+ return (List<Binding<?>>) (List<?>) bindings; // safe because bindings is immutable.
+ } else {
+ throw new UnsupportedOperationException("getElements() not supported for module bindings");
+ }
+ }
+
+ boolean permitsDuplicates() {
+ if (isInitialized()) {
+ return permitDuplicates;
+ } else {
+ throw new UnsupportedOperationException(
+ "permitsDuplicates() not supported for module bindings");
+ }
+ }
+
+ boolean containsElement(com.google.inject.spi.Element element) {
+ if (element instanceof Binding) {
+ Binding<?> binding = (Binding<?>) element;
+ return keyMatches(binding.getKey())
+ || binding.getKey().equals(getPermitDuplicatesKey())
+ || binding.getKey().equals(setKey)
+ || binding.getKey().equals(collectionOfProvidersKey)
+ || binding.getKey().equals(collectionOfJavaxProvidersKey);
+ } else {
+ return false;
+ }
+ }
+
+ private boolean keyMatches(Key<?> key) {
+ return key.getTypeLiteral().equals(elementType)
+ && key.getAnnotation() instanceof Element
+ && ((Element) key.getAnnotation()).setName().equals(getSetName())
+ && ((Element) key.getAnnotation()).type() == MULTIBINDER;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof BindingSelection) {
+ return setKey.equals(((BindingSelection<?>) obj).setKey);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return setKey.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return (getSetName().isEmpty() ? "" : getSetName() + " ")
+ + "Multibinder<"
+ + elementType
+ + ">";
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof RealMultibinder
+ && ((RealMultibinder<?>) o).bindingSelection.equals(bindingSelection);
+ }
+
+ @Override
+ public int hashCode() {
+ return bindingSelection.hashCode();
+ }
+
+ private static final class RealMultibinderCollectionOfProvidersProvider<T>
+ extends InternalProviderInstanceBindingImpl.Factory<Collection<Provider<T>>> {
+
+ private final BindingSelection<T> bindingSelection;
+ private ImmutableList<Provider<T>> collectionOfProviders;
+
+ RealMultibinderCollectionOfProvidersProvider(BindingSelection<T> bindingSelection) {
+ super(InitializationTiming.DELAYED); // See comment in RealMultibinderProvider
+ this.bindingSelection = bindingSelection;
+ }
+
+ @Override
+ void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
+ bindingSelection.initialize(injector, errors);
+ ImmutableList.Builder<Provider<T>> providers = ImmutableList.builder();
+ for (Binding<T> binding : bindingSelection.getBindings()) {
+ providers.add(binding.getProvider());
+ }
+ this.collectionOfProviders = providers.build();
+ }
+
+ @Override
+ protected Collection<Provider<T>> doProvision(
+ InternalContext context, Dependency<?> dependency) {
+ return collectionOfProviders;
+ }
+
+ @Override
+ public Set<Dependency<?>> getDependencies() {
+ return bindingSelection.getProviderDependencies();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof RealMultibinderCollectionOfProvidersProvider
+ && bindingSelection.equals(
+ ((RealMultibinderCollectionOfProvidersProvider<?>) obj).bindingSelection);
+ }
+
+ @Override
+ public int hashCode() {
+ return bindingSelection.hashCode();
+ }
+ }
+
+ /**
+ * We install the permit duplicates configuration as its own binding, all by itself. This way, if
+ * only one of a multibinder's users remember to call permitDuplicates(), they're still permitted.
+ *
+ * <p>This is like setting a global variable in the injector so that each instance of the
+ * multibinder will have the same value for permitDuplicates, even if it is only set on one of
+ * them.
+ */
+ private static class PermitDuplicatesModule extends AbstractModule {
+ private final Key<Boolean> key;
+
+ PermitDuplicatesModule(Key<Boolean> key) {
+ this.key = key;
+ }
+
+ @Override
+ protected void configure() {
+ bind(key).toInstance(true);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof PermitDuplicatesModule && ((PermitDuplicatesModule) o).key.equals(key);
+ }
+
+ @Override
+ public int hashCode() {
+ return getClass().hashCode() ^ key.hashCode();
+ }
+ }
+}
diff --git a/core/src/com/google/inject/internal/RealOptionalBinder.java b/core/src/com/google/inject/internal/RealOptionalBinder.java
new file mode 100644
index 00000000..7072d2e8
--- /dev/null
+++ b/core/src/com/google/inject/internal/RealOptionalBinder.java
@@ -0,0 +1,844 @@
+/*
+ * Copyright (C) 2016 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.internal;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static com.google.common.base.Preconditions.checkState;
+import static com.google.inject.internal.Errors.checkConfiguration;
+import static com.google.inject.util.Types.newParameterizedType;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Throwables;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.inject.Binder;
+import com.google.inject.Binding;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.Provider;
+import com.google.inject.TypeLiteral;
+import com.google.inject.binder.LinkedBindingBuilder;
+import com.google.inject.internal.InternalProviderInstanceBindingImpl.InitializationTiming;
+import com.google.inject.multibindings.MultibindingsTargetVisitor;
+import com.google.inject.multibindings.OptionalBinderBinding;
+import com.google.inject.spi.BindingTargetVisitor;
+import com.google.inject.spi.Dependency;
+import com.google.inject.spi.Element;
+import com.google.inject.spi.ProviderInstanceBinding;
+import com.google.inject.spi.ProviderWithExtensionVisitor;
+import com.google.inject.util.Types;
+import java.io.Serializable;
+import java.lang.annotation.Annotation;
+import java.lang.annotation.Retention;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.Set;
+import javax.inject.Qualifier;
+
+/**
+ * The actual OptionalBinder plays several roles. It implements Module to hide that fact from the
+ * public API, and installs the various bindings that are exposed to the user.
+ */
+public final class RealOptionalBinder<T> implements Module {
+ public static <T> RealOptionalBinder<T> newRealOptionalBinder(Binder binder, Key<T> type) {
+ binder = binder.skipSources(RealOptionalBinder.class);
+ RealOptionalBinder<T> optionalBinder = new RealOptionalBinder<>(binder, type);
+ binder.install(optionalBinder);
+ return optionalBinder;
+ }
+
+ /* Reflectively capture java 8's Optional types so we can bind them if we're running in java8. */
+ private static final Class<?> JAVA_OPTIONAL_CLASS;
+ private static final Object JAVA_OPTIONAL_EMPTY;
+ private static final Method JAVA_OPTIONAL_OF_METHOD;
+
+ static {
+ Class<?> optional = null;
+ Object emptyObject = null;
+ Method of = null;
+ boolean useJavaOptional = false;
+ try {
+ optional = Class.forName("java.util.Optional");
+ emptyObject = optional.getDeclaredMethod("empty").invoke(null);
+ of = optional.getDeclaredMethod("of", Object.class);
+ // only use optional support if all our reflection succeeded
+ useJavaOptional = true;
+ } catch (ClassNotFoundException ignored) {
+ } catch (NoSuchMethodException ignored) {
+ } catch (SecurityException ignored) {
+ } catch (IllegalAccessException ignored) {
+ } catch (InvocationTargetException ignored) {
+ }
+ JAVA_OPTIONAL_CLASS = useJavaOptional ? optional : null;
+ JAVA_OPTIONAL_EMPTY = useJavaOptional ? emptyObject : null;
+ JAVA_OPTIONAL_OF_METHOD = useJavaOptional ? of : null;
+ }
+
+ /**
+ * Returns java.util.Optional.empty() if the parameter is null, calls {@link
+ * #invokeJavaOptionalOf} otherwise.
+ */
+ private static Object invokeJavaOptionalOfNullable(Object o) {
+ if (o == null) {
+ return JAVA_OPTIONAL_EMPTY;
+ }
+ return invokeJavaOptionalOf(o);
+ }
+
+ /** Invokes java.util.Optional.of. */
+ private static Object invokeJavaOptionalOf(Object o) {
+ try {
+ return JAVA_OPTIONAL_OF_METHOD.invoke(null, o);
+ } catch (IllegalAccessException e) {
+ throw new SecurityException(e);
+ } catch (IllegalArgumentException e) {
+ throw new IllegalStateException(e);
+ } catch (InvocationTargetException e) {
+ throw Throwables.propagate(e.getCause());
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ static <T> TypeLiteral<Optional<T>> optionalOf(TypeLiteral<T> type) {
+ return (TypeLiteral<Optional<T>>)
+ TypeLiteral.get(Types.newParameterizedType(Optional.class, type.getType()));
+ }
+
+ static <T> TypeLiteral<?> javaOptionalOf(TypeLiteral<T> type) {
+ checkState(JAVA_OPTIONAL_CLASS != null, "java.util.Optional not found");
+ return TypeLiteral.get(Types.newParameterizedType(JAVA_OPTIONAL_CLASS, type.getType()));
+ }
+
+ @SuppressWarnings("unchecked")
+ static <T> TypeLiteral<Optional<javax.inject.Provider<T>>> optionalOfJavaxProvider(
+ TypeLiteral<T> type) {
+ return (TypeLiteral<Optional<javax.inject.Provider<T>>>)
+ TypeLiteral.get(
+ Types.newParameterizedType(
+ Optional.class, newParameterizedType(javax.inject.Provider.class, type.getType())));
+ }
+
+ static <T> TypeLiteral<?> javaOptionalOfJavaxProvider(TypeLiteral<T> type) {
+ checkState(JAVA_OPTIONAL_CLASS != null, "java.util.Optional not found");
+ return TypeLiteral.get(
+ Types.newParameterizedType(
+ JAVA_OPTIONAL_CLASS,
+ newParameterizedType(javax.inject.Provider.class, type.getType())));
+ }
+
+ @SuppressWarnings("unchecked")
+ static <T> TypeLiteral<Optional<Provider<T>>> optionalOfProvider(TypeLiteral<T> type) {
+ return (TypeLiteral<Optional<Provider<T>>>)
+ TypeLiteral.get(
+ Types.newParameterizedType(
+ Optional.class, newParameterizedType(Provider.class, type.getType())));
+ }
+
+ static <T> TypeLiteral<?> javaOptionalOfProvider(TypeLiteral<T> type) {
+ checkState(JAVA_OPTIONAL_CLASS != null, "java.util.Optional not found");
+ return TypeLiteral.get(
+ Types.newParameterizedType(
+ JAVA_OPTIONAL_CLASS, newParameterizedType(Provider.class, type.getType())));
+ }
+
+ @SuppressWarnings("unchecked")
+ static <T> Key<Provider<T>> providerOf(Key<T> key) {
+ Type providerT = Types.providerOf(key.getTypeLiteral().getType());
+ return (Key<Provider<T>>) key.ofType(providerT);
+ }
+
+ enum Source {
+ DEFAULT,
+ ACTUAL
+ }
+
+ @Retention(RUNTIME)
+ @Qualifier
+ @interface Default {
+ String value();
+ }
+
+ @Retention(RUNTIME)
+ @Qualifier
+ @interface Actual {
+ String value();
+ }
+
+ private final BindingSelection<T> bindingSelection;
+ private final Binder binder;
+
+ private RealOptionalBinder(Binder binder, Key<T> typeKey) {
+ this.bindingSelection = new BindingSelection<>(typeKey);
+ this.binder = binder;
+ }
+
+ /**
+ * Adds a binding for T. Multiple calls to this are safe, and will be collapsed as duplicate
+ * bindings.
+ */
+ private void addDirectTypeBinding(Binder binder) {
+ binder
+ .bind(bindingSelection.getDirectKey())
+ .toProvider(new RealDirectTypeProvider<T>(bindingSelection));
+ }
+
+ /**
+ * Returns the key to use for the default binding.
+ *
+ * <p>As a side effect this installs support for the 'direct type', so a binding for {@code T}
+ * will be made available.
+ */
+ Key<T> getKeyForDefaultBinding() {
+ bindingSelection.checkNotInitialized();
+ addDirectTypeBinding(binder);
+ return bindingSelection.getKeyForDefaultBinding();
+ }
+
+ public LinkedBindingBuilder<T> setDefault() {
+ return binder.bind(getKeyForDefaultBinding());
+ }
+
+ /**
+ * Returns the key to use for the actual binding, overrides the default if set.
+ *
+ * <p>As a side effect this installs support for the 'direct type', so a binding for {@code T}
+ * will be made available.
+ */
+ Key<T> getKeyForActualBinding() {
+ bindingSelection.checkNotInitialized();
+ addDirectTypeBinding(binder);
+ return bindingSelection.getKeyForActualBinding();
+ }
+
+ public LinkedBindingBuilder<T> setBinding() {
+ return binder.bind(getKeyForActualBinding());
+ }
+
+ @Override
+ public void configure(Binder binder) {
+ bindingSelection.checkNotInitialized();
+ Key<T> key = bindingSelection.getDirectKey();
+ // Every OptionalBinder get's the following types bound
+ // * Optional<Provider<T>>
+ // * Optional<javax.inject.Provider<T>>
+ // * Optional<T>
+ // If setDefault() or setBinding() is called then also
+ // * T is bound
+ // If java.util.Optional is on the classpath (because this is a jdk8+ vm), then you also get
+ // * java.util.Optional<Provider<T>>
+ // * java.util.Optional<javax.inject.Provider<T>>
+ // * java.util.Optional<T>
+ InternalProviderInstanceBindingImpl.Factory<Optional<Provider<T>>> optionalProviderFactory =
+ new RealOptionalProviderProvider<T>(bindingSelection);
+ binder
+ .bind(key.ofType(optionalOfProvider(key.getTypeLiteral())))
+ .toProvider(optionalProviderFactory);
+
+ // Provider is assignable to javax.inject.Provider and the provider that the factory contains
+ // cannot be modified so we can use some rawtypes hackery to share the same implementation.
+ @SuppressWarnings("unchecked")
+ InternalProviderInstanceBindingImpl.Factory<Optional<javax.inject.Provider<T>>>
+ optionalJavaxProviderFactory =
+ (InternalProviderInstanceBindingImpl.Factory) optionalProviderFactory;
+ binder
+ .bind(key.ofType(optionalOfJavaxProvider(key.getTypeLiteral())))
+ .toProvider(optionalJavaxProviderFactory);
+
+ Key<Optional<T>> optionalKey = key.ofType(optionalOf(key.getTypeLiteral()));
+ binder
+ .bind(optionalKey)
+ .toProvider(new RealOptionalKeyProvider<T>(bindingSelection, optionalKey));
+
+ // Bind the java-8 types if we know them.
+ bindJava8Optional(binder);
+ }
+
+ @SuppressWarnings("unchecked")
+ private void bindJava8Optional(Binder binder) {
+ if (JAVA_OPTIONAL_CLASS != null) {
+ Key<?> key = bindingSelection.getDirectKey();
+ TypeLiteral<?> typeLiteral = key.getTypeLiteral();
+ InternalProviderInstanceBindingImpl.Factory<Object> javaOptionalProviderFactory =
+ new JavaOptionalProviderProvider(bindingSelection);
+ binder
+ .bind(key.ofType(javaOptionalOfProvider(typeLiteral)))
+ .toProvider((Provider) javaOptionalProviderFactory);
+ // Provider is assignable to javax.inject.Provider and the provider that the factory contains
+ // cannot be modified so we can use some rawtypes hackery to share the same implementation.
+ binder
+ .bind(key.ofType(javaOptionalOfJavaxProvider(typeLiteral)))
+ .toProvider((Provider) javaOptionalProviderFactory);
+ Key<?> javaOptionalKey = key.ofType(javaOptionalOf(typeLiteral));
+ binder
+ .bind(javaOptionalKey)
+ .toProvider(new JavaOptionalProvider(bindingSelection, javaOptionalKey));
+ }
+ }
+
+ /** Provides the binding for java.util.Optional<T>. */
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ private static final class JavaOptionalProvider extends RealOptionalBinderProviderWithDependencies
+ implements ProviderWithExtensionVisitor, OptionalBinderBinding {
+
+ private final Key<?> optionalKey;
+
+ private Dependency<?> targetDependency;
+ private InternalFactory<?> target;
+
+ JavaOptionalProvider(BindingSelection<?> bindingSelection, Key<?> optionalKey) {
+ super(bindingSelection);
+ this.optionalKey = optionalKey;
+ }
+
+ @Override
+ void doInitialize() {
+ if (bindingSelection.getBinding() != null) {
+ target = bindingSelection.getBinding().getInternalFactory();
+ targetDependency = bindingSelection.getDependency();
+ }
+ }
+
+ @Override
+ protected Object doProvision(InternalContext context, Dependency dependency)
+ throws InternalProvisionException {
+ InternalFactory<?> local = target;
+ if (local == null) {
+ return JAVA_OPTIONAL_EMPTY;
+ }
+ Dependency<?> localDependency = targetDependency;
+ Object result;
+ Dependency previous = context.pushDependency(localDependency, getSource());
+
+ try {
+ // See comments in RealOptionalKeyProvider, about how localDependency may be more specific
+ // than what we actually need.
+ result = local.get(context, localDependency, false);
+ } catch (InternalProvisionException ipe) {
+ throw ipe.addSource(localDependency);
+ } finally {
+ context.popStateAndSetDependency(previous);
+
+ }
+ return invokeJavaOptionalOfNullable(result);
+ }
+
+ @Override
+ public Set<Dependency<?>> getDependencies() {
+ return bindingSelection.dependencies;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Object acceptExtensionVisitor(
+ BindingTargetVisitor visitor, ProviderInstanceBinding binding) {
+ if (visitor instanceof MultibindingsTargetVisitor) {
+ return ((MultibindingsTargetVisitor) visitor).visit(this);
+ } else {
+ return visitor.visit(binding);
+ }
+ }
+
+ @Override
+ public boolean containsElement(Element element) {
+ return bindingSelection.containsElement(element);
+ }
+
+ @Override
+ public Binding<?> getActualBinding() {
+ return bindingSelection.getActualBinding();
+ }
+
+ @Override
+ public Binding<?> getDefaultBinding() {
+ return bindingSelection.getDefaultBinding();
+ }
+
+ @Override
+ public Key getKey() {
+ return optionalKey;
+ }
+ }
+
+ /** Provides the binding for java.util.Optional<Provider<T>>. */
+ @SuppressWarnings({"rawtypes", "unchecked"})
+ private static final class JavaOptionalProviderProvider
+ extends RealOptionalBinderProviderWithDependencies {
+ private Object value;
+
+ JavaOptionalProviderProvider(BindingSelection<?> bindingSelection) {
+ super(bindingSelection);
+ }
+
+ @Override
+ void doInitialize() {
+ if (bindingSelection.getBinding() == null) {
+ value = JAVA_OPTIONAL_EMPTY;
+ } else {
+ value = invokeJavaOptionalOf(bindingSelection.getBinding().getProvider());
+ }
+ }
+
+ @Override
+ protected Object doProvision(InternalContext context, Dependency dependency) {
+ return value;
+ }
+
+ @Override
+ public Set<Dependency<?>> getDependencies() {
+ return bindingSelection.providerDependencies();
+ }
+ }
+
+ /** Provides the binding for T, conditionally installed by calling setBinding/setDefault. */
+ private static final class RealDirectTypeProvider<T>
+ extends RealOptionalBinderProviderWithDependencies<T, T> {
+ private Key<? extends T> targetKey;
+
+ private Object targetSource;
+
+ private InternalFactory<? extends T> targetFactory;
+
+ RealDirectTypeProvider(BindingSelection<T> bindingSelection) {
+ super(bindingSelection);
+ }
+
+ @Override
+ void doInitialize() {
+ BindingImpl<T> targetBinding = bindingSelection.getBinding();
+ // we only install this factory if they call setBinding()/setDefault() so we know that
+ // targetBinding will be non-null.
+ this.targetKey = targetBinding.getKey();
+ this.targetSource = targetBinding.getSource();
+ this.targetFactory = targetBinding.getInternalFactory();
+ }
+
+ @Override
+ protected T doProvision(InternalContext context, Dependency<?> dependency)
+ throws InternalProvisionException {
+ // This is what linked bindings do (see FactoryProxy), and we are pretty similar.
+ context.pushState(targetKey, targetSource);
+
+ try {
+ return targetFactory.get(context, dependency, true);
+ } catch (InternalProvisionException ipe) {
+ throw ipe.addSource(targetKey);
+ } finally {
+ context.popState();
+
+ }
+ }
+
+ @Override
+ public Set<Dependency<?>> getDependencies() {
+ return bindingSelection.dependencies;
+ }
+ }
+
+ /** Provides the binding for Optional<Provider<T>>. */
+ private static final class RealOptionalProviderProvider<T>
+ extends RealOptionalBinderProviderWithDependencies<T, Optional<Provider<T>>> {
+ private Optional<Provider<T>> value;
+
+ RealOptionalProviderProvider(BindingSelection<T> bindingSelection) {
+ super(bindingSelection);
+ }
+
+ @Override
+ void doInitialize() {
+ if (bindingSelection.getBinding() == null) {
+ value = Optional.absent();
+ } else {
+ value = Optional.of(bindingSelection.getBinding().getProvider());
+ }
+ }
+
+ @Override
+ protected Optional<Provider<T>> doProvision(InternalContext context, Dependency<?> dependency) {
+ return value;
+ }
+
+ @Override
+ public Set<Dependency<?>> getDependencies() {
+ return bindingSelection.providerDependencies();
+ }
+ }
+
+ /** Provides the binding for Optional<T>. */
+ private static final class RealOptionalKeyProvider<T>
+ extends RealOptionalBinderProviderWithDependencies<T, Optional<T>>
+ implements ProviderWithExtensionVisitor<Optional<T>>, OptionalBinderBinding<Optional<T>> {
+
+ private final Key<Optional<T>> optionalKey;
+
+ // These are assigned to non-null values during initialization if and only if we have a binding
+ // to delegate to.
+ private Dependency<?> targetDependency;
+ private InternalFactory<? extends T> delegate;
+
+ RealOptionalKeyProvider(BindingSelection<T> bindingSelection, Key<Optional<T>> optionalKey) {
+ super(bindingSelection);
+ this.optionalKey = optionalKey;
+ }
+
+ @Override
+ void doInitialize() {
+ if (bindingSelection.getBinding() != null) {
+ delegate = bindingSelection.getBinding().getInternalFactory();
+ targetDependency = bindingSelection.getDependency();
+ }
+ }
+
+ @Override
+ protected Optional<T> doProvision(InternalContext context, Dependency<?> currentDependency)
+ throws InternalProvisionException {
+ InternalFactory<? extends T> local = delegate;
+ if (local == null) {
+ return Optional.absent();
+ }
+ Dependency<?> localDependency = targetDependency;
+ T result;
+ Dependency previous = context.pushDependency(localDependency, getSource());
+
+ try {
+ // currentDependency is Optional<? super T>, so we really just need to set the target
+ // dependency to ? super T, but we are currently setting it to T. We could hypothetically
+ // make it easier for our delegate to generate proxies by modifying the dependency, but that
+ // would also require us to rewrite the key on each call. So for now we don't do it.
+ result = local.get(context, localDependency, false);
+ } catch (InternalProvisionException ipe) {
+ throw ipe.addSource(localDependency);
+ } finally {
+ context.popStateAndSetDependency(previous);
+
+ }
+ return Optional.fromNullable(result);
+ }
+
+ @Override
+ public Set<Dependency<?>> getDependencies() {
+ return bindingSelection.dependencies();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <B, R> R acceptExtensionVisitor(
+ BindingTargetVisitor<B, R> visitor, ProviderInstanceBinding<? extends B> binding) {
+ if (visitor instanceof MultibindingsTargetVisitor) {
+ return ((MultibindingsTargetVisitor<Optional<T>, R>) visitor).visit(this);
+ } else {
+ return visitor.visit(binding);
+ }
+ }
+
+ @Override
+ public Key<Optional<T>> getKey() {
+ return optionalKey;
+ }
+
+ @Override
+ public Binding<?> getActualBinding() {
+ return bindingSelection.getActualBinding();
+ }
+
+ @Override
+ public Binding<?> getDefaultBinding() {
+ return bindingSelection.getDefaultBinding();
+ }
+
+ @Override
+ public boolean containsElement(Element element) {
+ return bindingSelection.containsElement(element);
+ }
+ }
+
+ /**
+ * A helper object that implements the core logic for deciding what the implementation of the
+ * binding will be.
+ *
+ * <p>This also implements the main OptionalBinderBinding logic.
+ */
+ private static final class BindingSelection<T> {
+ private static final ImmutableSet<Dependency<?>> MODULE_DEPENDENCIES =
+ ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class)));
+
+ /*@Nullable */ BindingImpl<T> actualBinding;
+ /*@Nullable */ BindingImpl<T> defaultBinding;
+ /*@Nullable */ BindingImpl<T> binding;
+ private boolean initialized;
+ private final Key<T> key;
+
+ // Until the injector initializes us, we don't know what our dependencies are,
+ // so initialize to the whole Injector (like Multibinder, and MapBinder indirectly).
+ private ImmutableSet<Dependency<?>> dependencies = MODULE_DEPENDENCIES;
+ private ImmutableSet<Dependency<?>> providerDependencies = MODULE_DEPENDENCIES;
+
+ /** lazily allocated, by {@link #getBindingName}. */
+ private String bindingName;
+
+ /** lazily allocated, by {@link #getKeyForDefaultBinding}. */
+ private Key<T> defaultBindingKey;
+
+ /** lazily allocated, by {@link #getKeyForActualBinding}. */
+ private Key<T> actualBindingKey;
+
+ BindingSelection(Key<T> key) {
+ this.key = key;
+ }
+
+ void checkNotInitialized() {
+ checkConfiguration(!initialized, "already initialized");
+ }
+
+ void initialize(InjectorImpl injector) {
+ // Every one of our providers will call this method, so only execute the logic once.
+ if (initialized) {
+ return;
+ }
+
+ actualBinding = injector.getExistingBinding(getKeyForActualBinding());
+ defaultBinding = injector.getExistingBinding(getKeyForDefaultBinding());
+ // We should never create Jit bindings, but we can use them if some other binding created it.
+ BindingImpl<T> userBinding = injector.getExistingBinding(key);
+ if (actualBinding != null) {
+ // TODO(sameb): Consider exposing an option that will allow
+ // ACTUAL to fallback to DEFAULT if ACTUAL's provider returns null.
+ // Right now, an ACTUAL binding can convert from present -> absent
+ // if it's bound to a provider that returns null.
+ binding = actualBinding;
+ } else if (defaultBinding != null) {
+ binding = defaultBinding;
+ } else if (userBinding != null) {
+ // If neither the actual or default is set, then we fallback
+ // to the value bound to the type itself and consider that the
+ // "actual binding" for the SPI.
+ binding = userBinding;
+ actualBinding = userBinding;
+ }
+ if (binding != null) {
+ dependencies = ImmutableSet.<Dependency<?>>of(Dependency.get(binding.getKey()));
+ providerDependencies =
+ ImmutableSet.<Dependency<?>>of(Dependency.get(providerOf(binding.getKey())));
+ } else {
+ dependencies = ImmutableSet.of();
+ providerDependencies = ImmutableSet.of();
+ }
+ initialized = true;
+ }
+
+ Key<T> getKeyForDefaultBinding() {
+ if (defaultBindingKey == null) {
+ defaultBindingKey = Key.get(key.getTypeLiteral(), new DefaultImpl(getBindingName()));
+ }
+ return defaultBindingKey;
+ }
+
+ Key<T> getKeyForActualBinding() {
+ if (actualBindingKey == null) {
+ actualBindingKey = Key.get(key.getTypeLiteral(), new ActualImpl(getBindingName()));
+ }
+ return actualBindingKey;
+ }
+
+ Key<T> getDirectKey() {
+ return key;
+ }
+
+ private String getBindingName() {
+ // Lazily allocated, most instantiations will never need this because they are deduped during
+ // module installation.
+ if (bindingName == null) {
+ bindingName = Annotations.nameOf(key);
+ }
+ return bindingName;
+ }
+
+ BindingImpl<T> getBinding() {
+ return binding;
+ }
+
+ // Provide default implementations for most of the OptionalBinderBinding interface
+ BindingImpl<T> getDefaultBinding() {
+ return defaultBinding;
+ }
+
+ BindingImpl<T> getActualBinding() {
+ return actualBinding;
+ }
+
+ ImmutableSet<Dependency<?>> providerDependencies() {
+ return providerDependencies;
+ }
+
+ ImmutableSet<Dependency<?>> dependencies() {
+ return dependencies;
+ }
+
+ /**
+ * Returns the Dependency for the target binding, throws NoSuchElementException if no target
+ * exists.
+ *
+ * <p>Calls to this method should typically be guarded by checking if {@link #getBinding()}
+ * returns {@code null}.
+ */
+ Dependency<?> getDependency() {
+ return Iterables.getOnlyElement(dependencies);
+ }
+
+ /** Implementation of {@link OptionalBinderBinding#containsElement}. */
+ boolean containsElement(Element element) {
+ // All of our bindings are ProviderInstanceBindings whose providers extend
+ // RealOptionalBinderProviderWithDependencies and have 'this' as its binding selection.
+ if (element instanceof ProviderInstanceBinding) {
+ javax.inject.Provider<?> providerInstance =
+ ((ProviderInstanceBinding<?>) element).getUserSuppliedProvider();
+ if (providerInstance instanceof RealOptionalBinderProviderWithDependencies) {
+ return ((RealOptionalBinderProviderWithDependencies<?, ?>) providerInstance)
+ .bindingSelection.equals(this);
+ }
+ }
+ if (element instanceof Binding) {
+ Key<?> elementKey = ((Binding) element).getKey();
+ // if it isn't one of the things we bound directly it might be an actual or default key
+ return elementKey.equals(getKeyForActualBinding())
+ || elementKey.equals(getKeyForDefaultBinding());
+ }
+ return false; // cannot match;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof BindingSelection && ((BindingSelection) o).key.equals(key);
+ }
+
+ @Override
+ public int hashCode() {
+ return key.hashCode();
+ }
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof RealOptionalBinder
+ && ((RealOptionalBinder<?>) o).bindingSelection.equals(bindingSelection);
+ }
+
+ @Override
+ public int hashCode() {
+ return bindingSelection.hashCode();
+ }
+
+ /** A base class for ProviderWithDependencies that need equality based on a specific object. */
+ private abstract static class RealOptionalBinderProviderWithDependencies<T, P>
+ extends InternalProviderInstanceBindingImpl.Factory<P> {
+ protected final BindingSelection<T> bindingSelection;
+
+ RealOptionalBinderProviderWithDependencies(BindingSelection<T> bindingSelection) {
+ // We need delayed initialization so we can detect jit bindings created by other bindings
+ // while not also creating jit bindings ourselves. This ensures we only pick up user bindings
+ // if the binding would have existed in the injector statically.
+ super(InitializationTiming.DELAYED);
+ this.bindingSelection = bindingSelection;
+ }
+
+ @Override
+ final void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
+ bindingSelection.initialize(injector);
+ doInitialize();
+ }
+
+ /**
+ * Initialize the factory. BindingSelection is guaranteed to be initialized at this point and
+ * this will be called prior to any provisioning.
+ */
+ abstract void doInitialize();
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj != null
+ && this.getClass() == obj.getClass()
+ && bindingSelection.equals(
+ ((RealOptionalBinderProviderWithDependencies<?, ?>) obj).bindingSelection);
+ }
+
+ @Override
+ public int hashCode() {
+ return bindingSelection.hashCode();
+ }
+ }
+
+ static class DefaultImpl extends BaseAnnotation implements Default {
+ public DefaultImpl(String value) {
+ super(Default.class, value);
+ }
+ }
+
+ static class ActualImpl extends BaseAnnotation implements Actual {
+ public ActualImpl(String value) {
+ super(Actual.class, value);
+ }
+ }
+
+ abstract static class BaseAnnotation implements Serializable, Annotation {
+
+ private final String value;
+ private final Class<? extends Annotation> clazz;
+
+ BaseAnnotation(Class<? extends Annotation> clazz, String value) {
+ this.clazz = checkNotNull(clazz, "clazz");
+ this.value = checkNotNull(value, "value");
+ }
+
+ public String value() {
+ return this.value;
+ }
+
+ @Override
+ public int hashCode() {
+ // This is specified in java.lang.Annotation.
+ return (127 * "value".hashCode()) ^ value.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ // We check against each annotation type instead of BaseAnnotation
+ // so that we can compare against generated annotation implementations.
+ if (o instanceof Actual && clazz == Actual.class) {
+ Actual other = (Actual) o;
+ return value.equals(other.value());
+ } else if (o instanceof Default && clazz == Default.class) {
+ Default other = (Default) o;
+ return value.equals(other.value());
+ }
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "@" + clazz.getName() + (value.isEmpty() ? "" : "(value=" + value + ")");
+ }
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ return clazz;
+ }
+
+ private static final long serialVersionUID = 0;
+ }
+}
diff --git a/core/src/com/google/inject/internal/ScopeBindingProcessor.java b/core/src/com/google/inject/internal/ScopeBindingProcessor.java
index 3e68b30a..83d7f8a0 100644
--- a/core/src/com/google/inject/internal/ScopeBindingProcessor.java
+++ b/core/src/com/google/inject/internal/ScopeBindingProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.inject.Scope;
import com.google.inject.spi.ScopeBinding;
-
import java.lang.annotation.Annotation;
/**
@@ -35,9 +34,11 @@ final class ScopeBindingProcessor extends AbstractProcessor {
super(errors);
}
- @Override public Boolean visit(ScopeBinding command) {
+ @Override
+ public Boolean visit(ScopeBinding command) {
Scope scope = checkNotNull(command.getScope(), "scope");
- Class<? extends Annotation> annotationType = checkNotNull(command.getAnnotationType(), "annotation type");
+ Class<? extends Annotation> annotationType =
+ checkNotNull(command.getAnnotationType(), "annotation type");
if (!Annotations.isScopeAnnotation(annotationType)) {
errors.missingScopeAnnotation(annotationType);
@@ -60,4 +61,4 @@ final class ScopeBindingProcessor extends AbstractProcessor {
return true;
}
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/internal/Scoping.java b/core/src/com/google/inject/internal/Scoping.java
index 334aaef4..53b72c0e 100644
--- a/core/src/com/google/inject/internal/Scoping.java
+++ b/core/src/com/google/inject/internal/Scoping.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,7 +26,6 @@ import com.google.inject.Stage;
import com.google.inject.binder.ScopedBindingBuilder;
import com.google.inject.spi.BindingScopingVisitor;
import com.google.inject.spi.ScopeBinding;
-
import java.lang.annotation.Annotation;
/**
@@ -41,98 +40,148 @@ public abstract class Scoping {
* No scoping annotation has been applied. Note that this is different from {@code
* in(Scopes.NO_SCOPE)}, where the 'NO_SCOPE' has been explicitly applied.
*/
- public static final Scoping UNSCOPED = new Scoping() {
- @Override public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
- return visitor.visitNoScoping();
- }
-
- @Override public Scope getScopeInstance() {
- return Scopes.NO_SCOPE;
- }
-
- @Override public String toString() {
- return Scopes.NO_SCOPE.toString();
- }
-
- @Override public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
- // do nothing
- }
- };
-
- public static final Scoping SINGLETON_ANNOTATION = new Scoping() {
- @Override public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
- return visitor.visitScopeAnnotation(Singleton.class);
- }
-
- @Override public Class<? extends Annotation> getScopeAnnotation() {
- return Singleton.class;
- }
-
- @Override public String toString() {
- return Singleton.class.getName();
- }
-
- @Override public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
- scopedBindingBuilder.in(Singleton.class);
- }
- };
-
- public static final Scoping SINGLETON_INSTANCE = new Scoping() {
- @Override public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
- return visitor.visitScope(Scopes.SINGLETON);
- }
-
- @Override public Scope getScopeInstance() {
- return Scopes.SINGLETON;
- }
+ public static final Scoping UNSCOPED =
+ new Scoping() {
+ @Override
+ public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
+ return visitor.visitNoScoping();
+ }
+
+ @Override
+ public Scope getScopeInstance() {
+ return Scopes.NO_SCOPE;
+ }
+
+ @Override
+ public String toString() {
+ return Scopes.NO_SCOPE.toString();
+ }
+
+ @Override
+ public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
+ // do nothing
+ }
+ };
- @Override public String toString() {
- return Scopes.SINGLETON.toString();
- }
-
- @Override public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
- scopedBindingBuilder.in(Scopes.SINGLETON);
- }
- };
-
- public static final Scoping EAGER_SINGLETON = new Scoping() {
- @Override public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
- return visitor.visitEagerSingleton();
- }
-
- @Override public Scope getScopeInstance() {
- return Scopes.SINGLETON;
- }
-
- @Override public String toString() {
- return "eager singleton";
- }
-
- @Override public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
- scopedBindingBuilder.asEagerSingleton();
- }
- };
+ /**
+ * No scoping annotation has been applied explicitly. Note that this is is the same as {@code
+ * in(Scopes.NO_SCOPE)}.
+ */
+ private static final Scoping EXPLICITLY_UNSCOPED =
+ new Scoping() {
+ @Override
+ public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
+ return visitor.visitNoScoping();
+ }
+
+ @Override
+ public Scope getScopeInstance() {
+ return Scopes.NO_SCOPE;
+ }
+
+ @Override
+ public String toString() {
+ return Scopes.NO_SCOPE.toString();
+ }
+
+ @Override
+ public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
+ scopedBindingBuilder.in(Scopes.NO_SCOPE);
+ }
+ };
+
+ public static final Scoping SINGLETON_ANNOTATION =
+ new Scoping() {
+ @Override
+ public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
+ return visitor.visitScopeAnnotation(Singleton.class);
+ }
+
+ @Override
+ public Class<? extends Annotation> getScopeAnnotation() {
+ return Singleton.class;
+ }
+
+ @Override
+ public String toString() {
+ return Singleton.class.getName();
+ }
+
+ @Override
+ public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
+ scopedBindingBuilder.in(Singleton.class);
+ }
+ };
+
+ public static final Scoping SINGLETON_INSTANCE =
+ new Scoping() {
+ @Override
+ public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
+ return visitor.visitScope(Scopes.SINGLETON);
+ }
+
+ @Override
+ public Scope getScopeInstance() {
+ return Scopes.SINGLETON;
+ }
+
+ @Override
+ public String toString() {
+ return Scopes.SINGLETON.toString();
+ }
+
+ @Override
+ public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
+ scopedBindingBuilder.in(Scopes.SINGLETON);
+ }
+ };
+
+ public static final Scoping EAGER_SINGLETON =
+ new Scoping() {
+ @Override
+ public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
+ return visitor.visitEagerSingleton();
+ }
+
+ @Override
+ public Scope getScopeInstance() {
+ return Scopes.SINGLETON;
+ }
+
+ @Override
+ public String toString() {
+ return "eager singleton";
+ }
+
+ @Override
+ public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
+ scopedBindingBuilder.asEagerSingleton();
+ }
+ };
public static Scoping forAnnotation(final Class<? extends Annotation> scopingAnnotation) {
- if (scopingAnnotation == Singleton.class
- || scopingAnnotation == javax.inject.Singleton.class) {
+ if (scopingAnnotation == Singleton.class || scopingAnnotation == javax.inject.Singleton.class) {
return SINGLETON_ANNOTATION;
}
return new Scoping() {
- @Override public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
+ @Override
+ public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
return visitor.visitScopeAnnotation(scopingAnnotation);
}
- @Override public Class<? extends Annotation> getScopeAnnotation() {
+ @Override
+ public Class<? extends Annotation> getScopeAnnotation() {
return scopingAnnotation;
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return scopingAnnotation.getName();
}
- @Override public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
+ @Override
+ public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
scopedBindingBuilder.in(scopingAnnotation);
}
};
@@ -141,22 +190,28 @@ public abstract class Scoping {
public static Scoping forInstance(final Scope scope) {
if (scope == Scopes.SINGLETON) {
return SINGLETON_INSTANCE;
+ } else if (scope == Scopes.NO_SCOPE) {
+ return EXPLICITLY_UNSCOPED;
}
return new Scoping() {
- @Override public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
+ @Override
+ public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) {
return visitor.visitScope(scope);
}
- @Override public Scope getScopeInstance() {
+ @Override
+ public Scope getScopeInstance() {
return scope;
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return scope.toString();
}
- @Override public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
+ @Override
+ public void applyTo(ScopedBindingBuilder scopedBindingBuilder) {
scopedBindingBuilder.in(scope);
}
};
@@ -178,9 +233,7 @@ public abstract class Scoping {
return getScopeInstance() == Scopes.NO_SCOPE;
}
- /**
- * Returns true if this scope is a singleton that should be loaded eagerly in {@code stage}.
- */
+ /** Returns true if this scope is a singleton that should be loaded eagerly in {@code stage}. */
public boolean isEagerSingleton(Stage stage) {
if (this == EAGER_SINGLETON) {
return true;
@@ -193,31 +246,27 @@ public abstract class Scoping {
return false;
}
- /**
- * Returns the scope instance, or {@code null} if that isn't known for this instance.
- */
+ /** Returns the scope instance, or {@code null} if that isn't known for this instance. */
public Scope getScopeInstance() {
return null;
}
- /**
- * Returns the scope annotation, or {@code null} if that isn't known for this instance.
- */
+ /** Returns the scope annotation, or {@code null} if that isn't known for this instance. */
public Class<? extends Annotation> getScopeAnnotation() {
return null;
}
-
+
@Override
public boolean equals(Object obj) {
- if(obj instanceof Scoping) {
- Scoping o = (Scoping)obj;
+ if (obj instanceof Scoping) {
+ Scoping o = (Scoping) obj;
return Objects.equal(getScopeAnnotation(), o.getScopeAnnotation())
- && Objects.equal(getScopeInstance(), o.getScopeInstance());
+ && Objects.equal(getScopeInstance(), o.getScopeInstance());
} else {
return false;
}
}
-
+
@Override
public int hashCode() {
return Objects.hashCode(getScopeAnnotation(), getScopeInstance());
@@ -230,8 +279,12 @@ public abstract class Scoping {
private Scoping() {}
/** Scopes an internal factory. */
- static <T> InternalFactory<? extends T> scope(Key<T> key, InjectorImpl injector,
- InternalFactory<? extends T> creator, Object source, Scoping scoping) {
+ static <T> InternalFactory<? extends T> scope(
+ Key<T> key,
+ InjectorImpl injector,
+ InternalFactory<? extends T> creator,
+ Object source,
+ Scoping scoping) {
if (scoping.isNoScope()) {
return creator;
@@ -239,8 +292,11 @@ public abstract class Scoping {
Scope scope = scoping.getScopeInstance();
- Provider<T> scoped
- = scope.scope(key, new ProviderToInternalFactoryAdapter<T>(injector, creator));
+ // NOTE: SingletonScope relies on the fact that we are passing a
+ // ProviderToInternalFactoryAdapter here. If you change the type make sure to update
+ // SingletonScope as well.
+ Provider<T> scoped =
+ scope.scope(key, new ProviderToInternalFactoryAdapter<T>(injector, creator));
return new InternalFactoryToProviderAdapter<T>(scoped, source);
}
diff --git a/core/src/com/google/inject/internal/SingleFieldInjector.java b/core/src/com/google/inject/internal/SingleFieldInjector.java
index 52be1f45..5319d450 100644
--- a/core/src/com/google/inject/internal/SingleFieldInjector.java
+++ b/core/src/com/google/inject/internal/SingleFieldInjector.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,12 +19,9 @@ package com.google.inject.internal;
import com.google.inject.internal.InjectorImpl.JitLimitation;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.InjectionPoint;
-
import java.lang.reflect.Field;
-/**
- * Sets an injectable field.
- */
+/** Sets an injectable field. */
final class SingleFieldInjector implements SingleMemberInjector {
final Field field;
final InjectionPoint injectionPoint;
@@ -42,23 +39,24 @@ final class SingleFieldInjector implements SingleMemberInjector {
binding = injector.getBindingOrThrow(dependency.getKey(), errors, JitLimitation.NO_JIT);
}
+ @Override
public InjectionPoint getInjectionPoint() {
return injectionPoint;
}
- public void inject(Errors errors, InternalContext context, Object o) {
- errors = errors.withSource(dependency);
-
+ @Override
+ public void inject(InternalContext context, Object o) throws InternalProvisionException {
Dependency previous = context.pushDependency(dependency, binding.getSource());
+
try {
- Object value = binding.getInternalFactory().get(errors, context, dependency, false);
+ Object value = binding.getInternalFactory().get(context, dependency, false);
field.set(o, value);
- } catch (ErrorsException e) {
- errors.withSource(injectionPoint).merge(e.getErrors());
+ } catch (InternalProvisionException e) {
+ throw e.addSource(dependency);
} catch (IllegalAccessException e) {
throw new AssertionError(e); // a security manager is blocking us, we're hosed
} finally {
- context.popStateAndSetDependency(previous);
- }
+ context.popStateAndSetDependency(previous);
+ }
}
}
diff --git a/core/src/com/google/inject/internal/SingleMemberInjector.java b/core/src/com/google/inject/internal/SingleMemberInjector.java
index fea5733f..f20a5e52 100644
--- a/core/src/com/google/inject/internal/SingleMemberInjector.java
+++ b/core/src/com/google/inject/internal/SingleMemberInjector.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,10 +18,9 @@ package com.google.inject.internal;
import com.google.inject.spi.InjectionPoint;
-/**
- * Injects a field or method of a given object.
- */
+/** Injects a field or method of a given object. */
interface SingleMemberInjector {
- void inject(Errors errors, InternalContext context, Object o);
+ void inject(InternalContext context, Object o) throws InternalProvisionException;
+
InjectionPoint getInjectionPoint();
}
diff --git a/core/src/com/google/inject/internal/SingleMethodInjector.java b/core/src/com/google/inject/internal/SingleMethodInjector.java
index 8bc8a34e..9cf7d934 100644
--- a/core/src/com/google/inject/internal/SingleMethodInjector.java
+++ b/core/src/com/google/inject/internal/SingleMethodInjector.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,17 +16,13 @@
package com.google.inject.internal;
-import com.google.inject.internal.BytecodeGen.Visibility;
import com.google.inject.internal.InjectorImpl.MethodInvoker;
import com.google.inject.spi.InjectionPoint;
-
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-/**
- * Invokes an injectable method.
- */
+/** Invokes an injectable method. */
final class SingleMethodInjector implements SingleMemberInjector {
private final MethodInvoker methodInvoker;
private final SingleParameterInjector<?>[] parameterInjectors;
@@ -42,31 +38,33 @@ final class SingleMethodInjector implements SingleMemberInjector {
private MethodInvoker createMethodInvoker(final Method method) {
- // We can't use FastMethod if the method is private.
- int modifiers = method.getModifiers();
- if (!Modifier.isPrivate(modifiers) && !Modifier.isProtected(modifiers)) {
- /*if[AOP]*/
- try {
- final net.sf.cglib.reflect.FastMethod fastMethod
- = BytecodeGen.newFastClass(method.getDeclaringClass(), Visibility.forMember(method))
- .getMethod(method);
+ /*if[AOP]*/
+ try {
+ final net.sf.cglib.reflect.FastClass fastClass = BytecodeGen.newFastClassForMember(method);
+ if (fastClass != null) {
+ final int index = fastClass.getMethod(method).getIndex();
- return new MethodInvoker() {
- public Object invoke(Object target, Object... parameters)
- throws IllegalAccessException, InvocationTargetException {
- return fastMethod.invoke(target, parameters);
- }
- };
- } catch (net.sf.cglib.core.CodeGenerationException e) {/* fall-through */}
- /*end[AOP]*/
+ return new MethodInvoker() {
+ @Override
+ public Object invoke(Object target, Object... parameters)
+ throws IllegalAccessException, InvocationTargetException {
+ return fastClass.invoke(index, target, parameters);
+ }
+ };
+ }
+ } catch (net.sf.cglib.core.CodeGenerationException e) {
+ /* fall-through */
}
+ /*end[AOP]*/
- if (!Modifier.isPublic(modifiers) ||
- !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
+ int modifiers = method.getModifiers();
+ if (!Modifier.isPublic(modifiers)
+ || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) {
method.setAccessible(true);
}
return new MethodInvoker() {
+ @Override
public Object invoke(Object target, Object... parameters)
throws IllegalAccessException, InvocationTargetException {
return method.invoke(target, parameters);
@@ -74,28 +72,22 @@ final class SingleMethodInjector implements SingleMemberInjector {
};
}
+ @Override
public InjectionPoint getInjectionPoint() {
return injectionPoint;
}
- public void inject(Errors errors, InternalContext context, Object o) {
- Object[] parameters;
- try {
- parameters = SingleParameterInjector.getAll(errors, context, parameterInjectors);
- } catch (ErrorsException e) {
- errors.merge(e.getErrors());
- return;
- }
+ @Override
+ public void inject(InternalContext context, Object o) throws InternalProvisionException {
+ Object[] parameters = SingleParameterInjector.getAll(context, parameterInjectors);
try {
methodInvoker.invoke(o, parameters);
} catch (IllegalAccessException e) {
throw new AssertionError(e); // a security manager is blocking us, we're hosed
} catch (InvocationTargetException userException) {
- Throwable cause = userException.getCause() != null
- ? userException.getCause()
- : userException;
- errors.withSource(injectionPoint).errorInjectingMethod(cause);
+ Throwable cause = userException.getCause() != null ? userException.getCause() : userException;
+ throw InternalProvisionException.errorInjectingMethod(cause).addSource(injectionPoint);
}
}
}
diff --git a/core/src/com/google/inject/internal/SingleParameterInjector.java b/core/src/com/google/inject/internal/SingleParameterInjector.java
index 708b8b09..3e36ed72 100644
--- a/core/src/com/google/inject/internal/SingleParameterInjector.java
+++ b/core/src/com/google/inject/internal/SingleParameterInjector.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,54 +18,52 @@ package com.google.inject.internal;
import com.google.inject.spi.Dependency;
-/**
- * Resolves a single parameter, to be used in a constructor or method invocation.
- */
+/** Resolves a single parameter, to be used in a constructor or method invocation. */
final class SingleParameterInjector<T> {
- private static final Object[] NO_ARGUMENTS = {};
+ private static final Object[] NO_ARGUMENTS = {};
private final Dependency<T> dependency;
- private final BindingImpl<? extends T> binding;
+
+ private final Object source;
+
+ private final InternalFactory<? extends T> factory;
SingleParameterInjector(Dependency<T> dependency, BindingImpl<? extends T> binding) {
this.dependency = dependency;
- this.binding = binding;
+ this.source = binding.getSource();
+ this.factory = binding.getInternalFactory();
}
- private T inject(Errors errors, InternalContext context) throws ErrorsException {
- Dependency previous = context.pushDependency(dependency, binding.getSource());
+ T inject(InternalContext context) throws InternalProvisionException {
+ Dependency<T> localDependency = dependency;
+ Dependency previous = context.pushDependency(localDependency, source);
+
try {
- return binding.getInternalFactory().get(errors.withSource(dependency), context, dependency, false);
- } finally {
- context.popStateAndSetDependency(previous);
+ return factory.get(context, localDependency, false);
+ } catch (InternalProvisionException ipe) {
+ throw ipe.addSource(localDependency);
+ } finally {
+ context.popStateAndSetDependency(previous);
+
}
}
- /**
- * Returns an array of parameter values.
- */
- static Object[] getAll(Errors errors, InternalContext context,
- SingleParameterInjector<?>[] parameterInjectors) throws ErrorsException {
+ // TODO(lukes): inline into callers to decrease stack depth
+
+ /** Returns an array of parameter values. */
+ static Object[] getAll(InternalContext context, SingleParameterInjector<?>[] parameterInjectors)
+ throws InternalProvisionException {
if (parameterInjectors == null) {
return NO_ARGUMENTS;
}
- int numErrorsBefore = errors.size();
-
int size = parameterInjectors.length;
Object[] parameters = new Object[size];
- // optimization: use manual for/each to save allocating an iterator here
+ // optimization: use manual for/each to save allocating an iterator here
for (int i = 0; i < size; i++) {
- SingleParameterInjector<?> parameterInjector = parameterInjectors[i];
- try {
- parameters[i] = parameterInjector.inject(errors, context);
- } catch (ErrorsException e) {
- errors.merge(e.getErrors());
- }
+ parameters[i] = parameterInjectors[i].inject(context);
}
-
- errors.throwIfNewErrors(numErrorsBefore);
return parameters;
}
}
diff --git a/core/src/com/google/inject/internal/SingletonScope.java b/core/src/com/google/inject/internal/SingletonScope.java
index fe6287aa..c07ccb7e 100644
--- a/core/src/com/google/inject/internal/SingletonScope.java
+++ b/core/src/com/google/inject/internal/SingletonScope.java
@@ -2,10 +2,8 @@ package com.google.inject.internal;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Iterables;
import com.google.common.collect.ListMultimap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Provider;
@@ -15,58 +13,43 @@ import com.google.inject.Scopes;
import com.google.inject.Singleton;
import com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory;
import com.google.inject.spi.Dependency;
-import com.google.inject.spi.DependencyAndSource;
import com.google.inject.spi.Message;
-
-import java.util.Collections;
+import java.util.Formatter;
import java.util.List;
-import java.util.Map;
/**
* One instance per {@link Injector}. Also see {@code @}{@link Singleton}.
*
- * Introduction from the author:
- * Implementation of this class seems unreasonably complicated at the first sight.
- * I fully agree with you, that the beast below is very complex
- * and it's hard to 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>Introduction from the author: Implementation of this class seems unreasonably complicated at
+ * the first sight. I fully agree with you, that the beast below is very complex and it's hard to
+ * 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.
*
- * 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. 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.
*
* @see #scope(Key, Provider)
* @see CycleDetectingLock
- *
* @author timofeyb (Timothy Basanov)
*/
public class SingletonScope implements Scope {
@@ -78,36 +61,34 @@ public class SingletonScope implements Scope {
* Allows us to detect when circular proxies are necessary. It's only used during singleton
* instance initialization, after initialization direct access through volatile field is used.
*
- * NB: Factory uses {@link Key}s as a user locks ids, different injectors can
- * share them. Cycles are detected properly as cycle detection does not rely on user locks ids,
- * but error message generated could be less than ideal.
- *
- * TODO(user): we may use one factory per injector tree for optimization reasons
+ * <p>NB: Factory uses {@link Key}s as a user locks ids, different injectors can share them.
+ * Cycles are detected properly as cycle detection does not rely on user locks ids, but error
+ * message generated could be less than ideal.
*/
+ // TODO(user): we may use one factory per injector tree for optimization reasons
private static final CycleDetectingLockFactory<Key<?>> cycleDetectingLockFactory =
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: - 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,
+ *
* @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: - 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
*/
return new Provider<T>() {
/**
@@ -120,21 +101,43 @@ public class SingletonScope implements Scope {
* Circular proxies are used when potential deadlocks are detected. Guarded by itself.
* ConstructionContext is not thread-safe, so each call should be synchronized.
*/
- final ConstructionContext<T> constructionContext = new ConstructionContext<T>();
+ final ConstructionContext<T> constructionContext = new ConstructionContext<>();
/** For each binding there is a separate lock that we hold during object creation. */
final CycleDetectingLock<Key<?>> creationLock = cycleDetectingLockFactory.create(key);
+ /**
+ * The singleton provider needs a reference back to the injector, in order to get ahold of
+ * InternalContext during instantiation.
+ */
+ final /* @Nullable */ InjectorImpl injector;
+
+ {
+ // If we are getting called by Scoping
+ if (creator instanceof ProviderToInternalFactoryAdapter) {
+ injector = ((ProviderToInternalFactoryAdapter) creator).getInjector();
+ } else {
+ injector = null;
+ }
+ }
+
@SuppressWarnings("DoubleCheckedLocking")
+ @Override
public T get() {
// cache volatile variable for the usual case of already initialized object
final Object initialInstance = instance;
if (initialInstance == null) {
// instance is not initialized yet
+ // first, store the current InternalContext in a map, so that if there is a circular
+ // dependency error, we can use the InternalContext objects to create a complete
+ // error message.
+ // Handle injector being null, which can happen when users call Scoping.scope themselves
+ final InternalContext context = injector == null ? null : injector.getLocalContext();
// acquire lock for current binding to initialize an instance
- final ListMultimap<Long, Key<?>> locksCycle =
+ final ListMultimap<Thread, Key<?>> locksCycle =
creationLock.lockOrDetectPotentialLocksCycle();
+
if (locksCycle.isEmpty()) {
// this thread now owns creation of an instance
try {
@@ -147,7 +150,7 @@ public class SingletonScope implements Scope {
// scope called recursively can initialize instance as a side effect
if (instance == null) {
- // instance is still not initialized, se we can proceed
+ // instance is still not initialized, so we can proceed
// don't remember proxies created by Guice on circular dependency
// detection within the same thread; they are not real instances to cache
@@ -162,7 +165,8 @@ public class SingletonScope implements Scope {
}
} else {
// safety assert in case instance was initialized
- Preconditions.checkState(instance == providedNotNull,
+ Preconditions.checkState(
+ instance == providedNotNull,
"Singleton is called recursively returning different results");
}
}
@@ -178,50 +182,45 @@ public class SingletonScope implements Scope {
creationLock.unlock();
}
} else {
+ if (context == null) {
+ throw new ProvisionException(
+ ImmutableList.of(createCycleDependenciesMessage(locksCycle, null)));
+ }
// potential deadlock detected, creation lock is not taken by this thread
synchronized (constructionContext) {
// guarantee thread-safety for instance and proxies initialization
if (instance == null) {
- // InjectorImpl.callInContext() sets this context when scope is called from Guice
- Map<Thread, InternalContext> globalInternalContext =
- InjectorImpl.getGlobalInternalContext();
- InternalContext internalContext = globalInternalContext.get(Thread.currentThread());
-
// creating a proxy to satisfy circular dependency across several threads
- Dependency<?> dependency = Preconditions.checkNotNull(
- internalContext.getDependency(),
- "globalInternalContext.get(currentThread()).getDependency()");
+ Dependency<?> dependency =
+ Preconditions.checkNotNull(
+ context.getDependency(), "internalContext.getDependency()");
Class<?> rawType = dependency.getKey().getTypeLiteral().getRawType();
try {
@SuppressWarnings("unchecked")
- T proxy = (T) constructionContext.createProxy(
- new Errors(), internalContext.getInjectorOptions(), rawType);
+ T proxy =
+ (T) constructionContext.createProxy(context.getInjectorOptions(), rawType);
return proxy;
- } catch (ErrorsException e) {
+ } catch (InternalProvisionException e) {
// best effort to create a rich error message
- List<Message> exceptionErrorMessages = e.getErrors().getMessages();
- // we expect an error thrown
- Preconditions.checkState(exceptionErrorMessages.size() == 1);
- // explicitly copy the map to guarantee iteration correctness
- // it's ok to have a data race with other threads that are locked
- Message cycleDependenciesMessage = createCycleDependenciesMessage(
- ImmutableMap.copyOf(globalInternalContext),
- locksCycle,
- exceptionErrorMessages.get(0));
+ Message proxyCreationError = Iterables.getOnlyElement(e.getErrors());
+ Message cycleDependenciesMessage =
+ createCycleDependenciesMessage(locksCycle, proxyCreationError);
// adding stack trace generated by us in addition to a standard one
- throw new ProvisionException(ImmutableList.of(
- cycleDependenciesMessage, exceptionErrorMessages.get(0)));
+ throw new ProvisionException(
+ ImmutableList.of(cycleDependenciesMessage, proxyCreationError));
}
}
}
}
+
// at this point we're sure that singleton was initialized,
// reread volatile variable to catch all corner cases
// caching volatile variable to minimize number of reads performed
final Object initializedInstance = instance;
- Preconditions.checkState(initializedInstance != null,
+ Preconditions.checkState(
+ initializedInstance != null,
"Internal error: Singleton is not initialized contrary to our expectations");
@SuppressWarnings("unchecked")
T initializedTypedInstance = (T) initializedInstance;
@@ -235,99 +234,45 @@ public class SingletonScope implements Scope {
}
/**
- * Helper method to create beautiful and rich error descriptions. Best effort and slow.
- * Tries its best to provide dependency information from injectors currently available
- * in a global internal context.
+ * Helper method to create beautiful and rich error descriptions. Best effort and slow. Tries
+ * its best to provide dependency information from injectors currently available in a global
+ * internal context.
+ *
+ * <p>The main thing being done is creating a list of Dependencies involved into lock cycle
+ * across all the threads involved. This is a structure we're creating:
*
- * <p>The main thing being done is creating a list of Dependencies involved into
- * lock cycle across all the threads involved. This is a structure we're creating:
* <pre>
* { Current Thread, C.class, B.class, Other Thread, B.class, C.class, Current Thread }
* To be inserted in the beginning by Guice: { A.class, B.class, C.class }
* </pre>
- * When we're calling Guice to create A and it fails in the deadlock while trying to
- * create C, which is being created by another thread, which waits for B. List would
- * be reversed before printing it to the end user.
+ *
+ * When we're calling Guice to create A and it fails in the deadlock while trying to create C,
+ * which is being created by another thread, which waits for B. List would be reversed before
+ * printing it to the end user.
*/
private Message createCycleDependenciesMessage(
- Map<Thread, InternalContext> globalInternalContext,
- ListMultimap<Long, Key<?>> locksCycle,
- Message proxyCreationError) {
+ ListMultimap<Thread, Key<?>> locksCycle, /* @Nullable */ Message proxyCreationError) {
// this is the main thing that we'll show in an error message,
// current thread is populate by Guice
- List<Object> sourcesCycle = Lists.newArrayList();
- sourcesCycle.add(Thread.currentThread());
- // temp map to speed up look ups
- Map<Long, Thread> threadById = Maps.newHashMap();
- for (Thread thread : globalInternalContext.keySet()) {
- threadById.put(thread.getId(), thread);
+ StringBuilder sb = new StringBuilder();
+ Formatter fmt = new Formatter(sb);
+ fmt.format("Encountered circular dependency spanning several threads.");
+ if (proxyCreationError != null) {
+ fmt.format(" %s", proxyCreationError.getMessage());
}
- for (long lockedThreadId : locksCycle.keySet()) {
- Thread lockedThread = threadById.get(lockedThreadId);
- List<Key<?>> lockedKeys = Collections.unmodifiableList(locksCycle.get(lockedThreadId));
- if (lockedThread == null) {
- // thread in a lock cycle is already terminated
- continue;
- }
- List<DependencyAndSource> dependencyChain = null;
- boolean allLockedKeysAreFoundInDependencies = false;
- // thread in a cycle is still present
- InternalContext lockedThreadInternalContext = globalInternalContext.get(lockedThread);
- if (lockedThreadInternalContext != null) {
- dependencyChain = lockedThreadInternalContext.getDependencyChain();
-
- // check that all of the keys are still present in dependency chain in order
- List<Key<?>> lockedKeysToFind = Lists.newLinkedList(lockedKeys);
- // check stack trace of the thread
- for (DependencyAndSource d : dependencyChain) {
- Dependency<?> dependency = d.getDependency();
- if (dependency == null) {
- continue;
- }
- if (dependency.getKey().equals(lockedKeysToFind.get(0))) {
- lockedKeysToFind.remove(0);
- if (lockedKeysToFind.isEmpty()) {
- // everything is found!
- allLockedKeysAreFoundInDependencies = true;
- break;
- }
- }
- }
+ fmt.format("%n");
+ for (Thread lockedThread : locksCycle.keySet()) {
+ List<Key<?>> lockedKeys = locksCycle.get(lockedThread);
+ fmt.format("%s is holding locks the following singletons in the cycle:%n", lockedThread);
+ for (Key<?> lockedKey : lockedKeys) {
+ fmt.format("%s%n", Errors.convert(lockedKey));
}
- if (allLockedKeysAreFoundInDependencies) {
- // all keys are present in a dependency chain of a thread's last injector,
- // highly likely that we just have discovered a dependency
- // chain that is part of a lock cycle starting with the first lock owned
- Key<?> firstLockedKey = lockedKeys.get(0);
- boolean firstLockedKeyFound = false;
- for (DependencyAndSource d : dependencyChain) {
- Dependency<?> dependency = d.getDependency();
- if (dependency == null) {
- continue;
- }
- if (firstLockedKeyFound) {
- sourcesCycle.add(dependency);
- sourcesCycle.add(d.getBindingSource());
- } else if (dependency.getKey().equals(firstLockedKey)) {
- firstLockedKeyFound = true;
- // for the very first one found we don't care why, so no dependency is added
- sourcesCycle.add(d.getBindingSource());
- }
- }
- } else {
- // something went wrong and not all keys are present in a state of an injector
- // that was used last for a current thread.
- // let's add all keys we're aware of, still better than nothing
- sourcesCycle.addAll(lockedKeys);
+ for (StackTraceElement traceElement : lockedThread.getStackTrace()) {
+ fmt.format("\tat %s%n", traceElement);
}
- // mentions that a tread is a part of a cycle
- sourcesCycle.add(lockedThread);
}
- return new Message(
- sourcesCycle,
- String.format("Encountered circular dependency spanning several threads. %s",
- proxyCreationError.getMessage()),
- null);
+ fmt.close();
+ return new Message(Thread.currentThread(), sb.toString());
}
@Override
@@ -337,7 +282,8 @@ public class SingletonScope implements Scope {
};
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "Scopes.SINGLETON";
}
}
diff --git a/core/src/com/google/inject/internal/State.java b/core/src/com/google/inject/internal/State.java
index 32c2da61..e49d2691 100644
--- a/core/src/com/google/inject/internal/State.java
+++ b/core/src/com/google/inject/internal/State.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,13 +23,11 @@ import com.google.inject.Binding;
import com.google.inject.Key;
import com.google.inject.Scope;
import com.google.inject.TypeLiteral;
-import com.google.inject.spi.ModuleAnnotatedMethodScanner;
import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding;
import com.google.inject.spi.ProvisionListenerBinding;
import com.google.inject.spi.ScopeBinding;
import com.google.inject.spi.TypeConverterBinding;
import com.google.inject.spi.TypeListenerBinding;
-
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
@@ -43,101 +41,124 @@ import java.util.Set;
*/
interface State {
- static final State NONE = new State() {
- public State parent() {
- throw new UnsupportedOperationException();
- }
-
- public <T> BindingImpl<T> getExplicitBinding(Key<T> key) {
- return null;
- }
-
- public Map<Key<?>, Binding<?>> getExplicitBindingsThisLevel() {
- throw new UnsupportedOperationException();
- }
-
- public void putBinding(Key<?> key, BindingImpl<?> binding) {
- throw new UnsupportedOperationException();
- }
-
- public ScopeBinding getScopeBinding(Class<? extends Annotation> scopingAnnotation) {
- return null;
- }
-
- public void putScopeBinding(Class<? extends Annotation> annotationType, ScopeBinding scope) {
- throw new UnsupportedOperationException();
- }
-
- public void addConverter(TypeConverterBinding typeConverterBinding) {
- throw new UnsupportedOperationException();
- }
-
- public TypeConverterBinding getConverter(String stringValue, TypeLiteral<?> type, Errors errors,
- Object source) {
- throw new UnsupportedOperationException();
- }
-
- public Iterable<TypeConverterBinding> getConvertersThisLevel() {
- return ImmutableSet.of();
- }
-
- /*if[AOP]*/
- public void addMethodAspect(MethodAspect methodAspect) {
- throw new UnsupportedOperationException();
- }
-
- public ImmutableList<MethodAspect> getMethodAspects() {
- return ImmutableList.of();
- }
- /*end[AOP]*/
-
- public void addTypeListener(TypeListenerBinding typeListenerBinding) {
- throw new UnsupportedOperationException();
- }
-
- public List<TypeListenerBinding> getTypeListenerBindings() {
- return ImmutableList.of();
- }
-
- public void addProvisionListener(ProvisionListenerBinding provisionListenerBinding) {
- throw new UnsupportedOperationException();
- }
-
- public List<ProvisionListenerBinding> getProvisionListenerBindings() {
- return ImmutableList.of();
- }
-
- public void addScanner(ModuleAnnotatedMethodScannerBinding scanner) {
- throw new UnsupportedOperationException();
- }
-
- public List<ModuleAnnotatedMethodScannerBinding> getScannerBindings() {
- return ImmutableList.of();
- }
-
- public void blacklist(Key<?> key, State state, Object source) {
- }
-
- public boolean isBlacklisted(Key<?> key) {
- return true;
- }
-
- public Set<Object> getSourcesForBlacklistedKey(Key<?> key) {
- throw new UnsupportedOperationException();
- }
-
- public Object lock() {
- throw new UnsupportedOperationException();
- }
-
- public Object singletonCreationLock() {
- throw new UnsupportedOperationException();
- }
-
- public Map<Class<? extends Annotation>, Scope> getScopes() {
- return ImmutableMap.of();
- }
- };
+ static final State NONE =
+ new State() {
+ @Override
+ public State parent() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public <T> BindingImpl<T> getExplicitBinding(Key<T> key) {
+ return null;
+ }
+
+ @Override
+ public Map<Key<?>, Binding<?>> getExplicitBindingsThisLevel() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void putBinding(Key<?> key, BindingImpl<?> binding) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ScopeBinding getScopeBinding(Class<? extends Annotation> scopingAnnotation) {
+ return null;
+ }
+
+ @Override
+ public void putScopeBinding(
+ Class<? extends Annotation> annotationType, ScopeBinding scope) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void addConverter(TypeConverterBinding typeConverterBinding) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public TypeConverterBinding getConverter(
+ String stringValue, TypeLiteral<?> type, Errors errors, Object source) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Iterable<TypeConverterBinding> getConvertersThisLevel() {
+ return ImmutableSet.of();
+ }
+
+ /*if[AOP]*/
+ @Override
+ public void addMethodAspect(MethodAspect methodAspect) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public ImmutableList<MethodAspect> getMethodAspects() {
+ return ImmutableList.of();
+ }
+ /*end[AOP]*/
+
+ @Override
+ public void addTypeListener(TypeListenerBinding typeListenerBinding) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<TypeListenerBinding> getTypeListenerBindings() {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public void addProvisionListener(ProvisionListenerBinding provisionListenerBinding) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<ProvisionListenerBinding> getProvisionListenerBindings() {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public void addScanner(ModuleAnnotatedMethodScannerBinding scanner) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public List<ModuleAnnotatedMethodScannerBinding> getScannerBindings() {
+ return ImmutableList.of();
+ }
+
+ @Override
+ public void blacklist(Key<?> key, State state, Object source) {}
+
+ @Override
+ public boolean isBlacklisted(Key<?> key) {
+ return true;
+ }
+
+ @Override
+ public Set<Object> getSourcesForBlacklistedKey(Key<?> key) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Object lock() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object singletonCreationLock() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public Map<Class<? extends Annotation>, Scope> getScopes() {
+ return ImmutableMap.of();
+ }
+ };
State parent();
@@ -148,7 +169,7 @@ interface State {
Map<Key<?>, Binding<?>> getExplicitBindingsThisLevel();
void putBinding(Key<?> key, BindingImpl<?> binding);
-
+
ScopeBinding getScopeBinding(Class<? extends Annotation> scopingAnnotation);
void putScopeBinding(Class<? extends Annotation> annotationType, ScopeBinding scope);
@@ -169,11 +190,11 @@ interface State {
/*end[AOP]*/
void addTypeListener(TypeListenerBinding typeListenerBinding);
-
+
List<TypeListenerBinding> getTypeListenerBindings();
-
+
void addProvisionListener(ProvisionListenerBinding provisionListenerBinding);
-
+
List<ProvisionListenerBinding> getProvisionListenerBindings();
void addScanner(ModuleAnnotatedMethodScannerBinding scanner);
@@ -192,7 +213,7 @@ interface State {
* one of this injector's descendent's has bound the key.
*/
boolean isBlacklisted(Key<?> key);
-
+
/** Returns the source of a blacklisted key. */
Set<Object> getSourcesForBlacklistedKey(Key<?> key);
@@ -202,8 +223,6 @@ interface State {
*/
Object lock();
- /**
- * Returns all the scope bindings at this level and parent levels.
- */
+ /** Returns all the scope bindings at this level and parent levels. */
Map<Class<? extends Annotation>, Scope> getScopes();
}
diff --git a/core/src/com/google/inject/internal/TypeConverterBindingProcessor.java b/core/src/com/google/inject/internal/TypeConverterBindingProcessor.java
index 7ab52ce5..34f2cd09 100644
--- a/core/src/com/google/inject/internal/TypeConverterBindingProcessor.java
+++ b/core/src/com/google/inject/internal/TypeConverterBindingProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@ import com.google.inject.matcher.Matcher;
import com.google.inject.matcher.Matchers;
import com.google.inject.spi.TypeConverter;
import com.google.inject.spi.TypeConverterBinding;
-
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
@@ -51,79 +50,97 @@ final class TypeConverterBindingProcessor extends AbstractProcessor {
convertToPrimitiveType(injector, float.class, Float.class);
convertToPrimitiveType(injector, double.class, Double.class);
- convertToClass(injector, Character.class, new TypeConverter() {
- public Object convert(String value, TypeLiteral<?> toType) {
- value = value.trim();
- if (value.length() != 1) {
- throw new RuntimeException("Length != 1.");
- }
- return value.charAt(0);
- }
-
- @Override public String toString() {
- return "TypeConverter<Character>";
- }
- });
-
- convertToClasses(injector, Matchers.subclassesOf(Enum.class), new TypeConverter() {
- @SuppressWarnings("unchecked")
- public Object convert(String value, TypeLiteral<?> toType) {
- return Enum.valueOf((Class) toType.getRawType(), value);
- }
-
- @Override public String toString() {
- return "TypeConverter<E extends Enum<E>>";
- }
- });
-
- internalConvertToTypes(injector, new AbstractMatcher<TypeLiteral<?>>() {
- public boolean matches(TypeLiteral<?> typeLiteral) {
- return typeLiteral.getRawType() == Class.class;
- }
-
- @Override public String toString() {
- return "Class<?>";
- }
- },
- new TypeConverter() {
- @SuppressWarnings("unchecked")
- public Object convert(String value, TypeLiteral<?> toType) {
- try {
- return Class.forName(value);
- } catch (ClassNotFoundException e) {
- throw new RuntimeException(e.getMessage());
+ convertToClass(
+ injector,
+ Character.class,
+ new TypeConverter() {
+ @Override
+ public Object convert(String value, TypeLiteral<?> toType) {
+ value = value.trim();
+ if (value.length() != 1) {
+ throw new RuntimeException("Length != 1.");
+ }
+ return value.charAt(0);
}
- }
- @Override public String toString() {
- return "TypeConverter<Class<?>>";
- }
- }
- );
- }
+ @Override
+ public String toString() {
+ return "TypeConverter<Character>";
+ }
+ });
+
+ convertToClasses(
+ injector,
+ Matchers.subclassesOf(Enum.class),
+ new TypeConverter() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object convert(String value, TypeLiteral<?> toType) {
+ return Enum.valueOf((Class) toType.getRawType(), value);
+ }
- private static <T> void convertToPrimitiveType(InjectorImpl injector, Class<T> primitiveType,
- final Class<T> wrapperType) {
- try {
- final Method parser = wrapperType.getMethod(
- "parse" + capitalize(primitiveType.getName()), String.class);
-
- TypeConverter typeConverter = new TypeConverter() {
- @SuppressWarnings("unchecked")
- public Object convert(String value, TypeLiteral<?> toType) {
- try {
- return parser.invoke(null, value);
- } catch (IllegalAccessException e) {
- throw new AssertionError(e);
- } catch (InvocationTargetException e) {
- throw new RuntimeException(e.getTargetException().getMessage());
+ @Override
+ public String toString() {
+ return "TypeConverter<E extends Enum<E>>";
+ }
+ });
+
+ internalConvertToTypes(
+ injector,
+ new AbstractMatcher<TypeLiteral<?>>() {
+ @Override
+ public boolean matches(TypeLiteral<?> typeLiteral) {
+ return typeLiteral.getRawType() == Class.class;
+ }
+
+ @Override
+ public String toString() {
+ return "Class<?>";
+ }
+ },
+ new TypeConverter() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object convert(String value, TypeLiteral<?> toType) {
+ try {
+ return Class.forName(value);
+ } catch (ClassNotFoundException e) {
+ throw new RuntimeException(e.getMessage());
+ }
}
- }
- @Override public String toString() {
- return "TypeConverter<" + wrapperType.getSimpleName() + ">";
- }
- };
+ @Override
+ public String toString() {
+ return "TypeConverter<Class<?>>";
+ }
+ });
+ }
+
+ private static <T> void convertToPrimitiveType(
+ InjectorImpl injector, Class<T> primitiveType, final Class<T> wrapperType) {
+ try {
+ final Method parser =
+ wrapperType.getMethod("parse" + capitalize(primitiveType.getName()), String.class);
+
+ TypeConverter typeConverter =
+ new TypeConverter() {
+ @Override
+ @SuppressWarnings("unchecked")
+ public Object convert(String value, TypeLiteral<?> toType) {
+ try {
+ return parser.invoke(null, value);
+ } catch (IllegalAccessException e) {
+ throw new AssertionError(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e.getTargetException().getMessage());
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "TypeConverter<" + wrapperType.getSimpleName() + ">";
+ }
+ };
convertToClass(injector, wrapperType, typeConverter);
} catch (NoSuchMethodException e) {
@@ -131,51 +148,54 @@ final class TypeConverterBindingProcessor extends AbstractProcessor {
}
}
- private static <T> void convertToClass(InjectorImpl injector, Class<T> type,
- TypeConverter converter) {
+ private static <T> void convertToClass(
+ InjectorImpl injector, Class<T> type, TypeConverter converter) {
convertToClasses(injector, Matchers.identicalTo(type), converter);
}
- private static void convertToClasses(InjectorImpl injector,
- final Matcher<? super Class<?>> typeMatcher, TypeConverter converter) {
- internalConvertToTypes(injector, new AbstractMatcher<TypeLiteral<?>>() {
- public boolean matches(TypeLiteral<?> typeLiteral) {
- Type type = typeLiteral.getType();
- if (!(type instanceof Class)) {
- return false;
- }
- Class<?> clazz = (Class<?>) type;
- return typeMatcher.matches(clazz);
- }
-
- @Override public String toString() {
- return typeMatcher.toString();
- }
- }, converter);
+ private static void convertToClasses(
+ InjectorImpl injector, final Matcher<? super Class<?>> typeMatcher, TypeConverter converter) {
+ internalConvertToTypes(
+ injector,
+ new AbstractMatcher<TypeLiteral<?>>() {
+ @Override
+ public boolean matches(TypeLiteral<?> typeLiteral) {
+ Type type = typeLiteral.getType();
+ if (!(type instanceof Class)) {
+ return false;
+ }
+ Class<?> clazz = (Class<?>) type;
+ return typeMatcher.matches(clazz);
+ }
+
+ @Override
+ public String toString() {
+ return typeMatcher.toString();
+ }
+ },
+ converter);
}
- private static void internalConvertToTypes(InjectorImpl injector,
- Matcher<? super TypeLiteral<?>> typeMatcher,
- TypeConverter converter) {
+ private static void internalConvertToTypes(
+ InjectorImpl injector, Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter) {
injector.state.addConverter(
new TypeConverterBinding(SourceProvider.UNKNOWN_SOURCE, typeMatcher, converter));
}
- @Override public Boolean visit(TypeConverterBinding command) {
- injector.state.addConverter(new TypeConverterBinding(
- command.getSource(), command.getTypeMatcher(), command.getTypeConverter()));
+ @Override
+ public Boolean visit(TypeConverterBinding command) {
+ injector.state.addConverter(
+ new TypeConverterBinding(
+ command.getSource(), command.getTypeMatcher(), command.getTypeConverter()));
return true;
}
-
+
private static String capitalize(String s) {
if (s.length() == 0) {
return s;
}
char first = s.charAt(0);
char capitalized = Character.toUpperCase(first);
- return (first == capitalized)
- ? s
- : capitalized + s.substring(1);
+ return (first == capitalized) ? s : capitalized + s.substring(1);
}
-
}
diff --git a/core/src/com/google/inject/internal/UniqueAnnotations.java b/core/src/com/google/inject/internal/UniqueAnnotations.java
index 924175e6..36b213d2 100644
--- a/core/src/com/google/inject/internal/UniqueAnnotations.java
+++ b/core/src/com/google/inject/internal/UniqueAnnotations.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,21 +19,19 @@ package com.google.inject.internal;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.inject.BindingAnnotation;
-
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.util.concurrent.atomic.AtomicInteger;
-/**
- * @author jessewilson@google.com (Jesse Wilson)
- */
+/** @author jessewilson@google.com (Jesse Wilson) */
public class UniqueAnnotations {
private UniqueAnnotations() {}
+
private static final AtomicInteger nextUniqueValue = new AtomicInteger(1);
/**
- * Returns an annotation instance that is not equal to any other annotation
- * instances, for use in creating distinct {@link com.google.inject.Key}s.
+ * Returns an annotation instance that is not equal to any other annotation instances, for use in
+ * creating distinct {@link com.google.inject.Key}s.
*/
public static Annotation create() {
return create(nextUniqueValue.getAndIncrement());
@@ -41,30 +39,35 @@ public class UniqueAnnotations {
static Annotation create(final int value) {
return new Internal() {
+ @Override
public int value() {
return value;
}
+ @Override
public Class<? extends Annotation> annotationType() {
return Internal.class;
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "@" + Internal.class.getName() + "(value=" + value + ")";
}
- @Override public boolean equals(Object o) {
- return o instanceof Internal
- && ((Internal) o).value() == value();
+ @Override
+ public boolean equals(Object o) {
+ return o instanceof Internal && ((Internal) o).value() == value();
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return (127 * "value".hashCode()) ^ value;
}
};
}
- @Retention(RUNTIME) @BindingAnnotation
+ @Retention(RUNTIME)
+ @BindingAnnotation
@interface Internal {
int value();
}
diff --git a/core/src/com/google/inject/internal/UntargettedBindingImpl.java b/core/src/com/google/inject/internal/UntargettedBindingImpl.java
index a2d3365d..18f0d947 100644
--- a/core/src/com/google/inject/internal/UntargettedBindingImpl.java
+++ b/core/src/com/google/inject/internal/UntargettedBindingImpl.java
@@ -16,6 +16,7 @@
package com.google.inject.internal;
+import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.inject.Binder;
import com.google.inject.Key;
@@ -26,35 +27,46 @@ import com.google.inject.spi.UntargettedBinding;
final class UntargettedBindingImpl<T> extends BindingImpl<T> implements UntargettedBinding<T> {
UntargettedBindingImpl(InjectorImpl injector, Key<T> key, Object source) {
- super(injector, key, source, new InternalFactory<T>() {
- public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) {
- throw new AssertionError();
- }
- }, Scoping.UNSCOPED);
+ super(
+ injector,
+ key,
+ source,
+ new InternalFactory<T>() {
+ @Override
+ public T get(InternalContext context, Dependency<?> dependency, boolean linked) {
+ throw new AssertionError();
+ }
+ },
+ Scoping.UNSCOPED);
}
public UntargettedBindingImpl(Object source, Key<T> key, Scoping scoping) {
super(source, key, scoping);
}
+ @Override
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
return visitor.visit(this);
}
+ @Override
public BindingImpl<T> withScoping(Scoping scoping) {
return new UntargettedBindingImpl<T>(getSource(), getKey(), scoping);
}
+ @Override
public BindingImpl<T> withKey(Key<T> key) {
return new UntargettedBindingImpl<T>(getSource(), key, getScoping());
}
+ @Override
public void applyTo(Binder binder) {
getScoping().applyTo(binder.withSource(getSource()).bind(getKey()));
}
- @Override public String toString() {
- return Objects.toStringHelper(UntargettedBinding.class)
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(UntargettedBinding.class)
.add("key", getKey())
.add("source", getSource())
.toString();
@@ -62,10 +74,9 @@ final class UntargettedBindingImpl<T> extends BindingImpl<T> implements Untarget
@Override
public boolean equals(Object obj) {
- if(obj instanceof UntargettedBindingImpl) {
- UntargettedBindingImpl<?> o = (UntargettedBindingImpl<?>)obj;
- return getKey().equals(o.getKey())
- && getScoping().equals(o.getScoping());
+ if (obj instanceof UntargettedBindingImpl) {
+ UntargettedBindingImpl<?> o = (UntargettedBindingImpl<?>) obj;
+ return getKey().equals(o.getKey()) && getScoping().equals(o.getScoping());
} else {
return false;
}
diff --git a/core/src/com/google/inject/internal/UntargettedBindingProcessor.java b/core/src/com/google/inject/internal/UntargettedBindingProcessor.java
index 8ca2ecc8..0e569957 100644
--- a/core/src/com/google/inject/internal/UntargettedBindingProcessor.java
+++ b/core/src/com/google/inject/internal/UntargettedBindingProcessor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,45 +25,47 @@ import com.google.inject.spi.UntargettedBinding;
* @author sameb@google.com (Sam Berlin)
*/
class UntargettedBindingProcessor extends AbstractBindingProcessor {
-
+
UntargettedBindingProcessor(Errors errors, ProcessedBindingData bindingData) {
super(errors, bindingData);
}
-
+
@Override
public <T> Boolean visit(Binding<T> binding) {
- return binding.acceptTargetVisitor(new Processor<T, Boolean>((BindingImpl<T>)binding) {
- public Boolean visit(UntargettedBinding<? extends T> untargetted) {
- prepareBinding();
+ return binding.acceptTargetVisitor(
+ new Processor<T, Boolean>((BindingImpl<T>) binding) {
+ @Override
+ public Boolean visit(UntargettedBinding<? extends T> untargetted) {
+ prepareBinding();
+
+ // Error: Missing implementation.
+ // Example: bind(Date.class).annotatedWith(Red.class);
+ // We can't assume abstract types aren't injectable. They may have an
+ // @ImplementedBy annotation or something.
+ if (key.getAnnotationType() != null) {
+ errors.missingImplementationWithHint(key, injector);
+ putBinding(invalidBinding(injector, key, source));
+ return true;
+ }
+
+ // This cast is safe after the preceeding check.
+ try {
+ BindingImpl<T> binding =
+ injector.createUninitializedBinding(key, scoping, source, errors, false);
+ scheduleInitialization(binding);
+ putBinding(binding);
+ } catch (ErrorsException e) {
+ errors.merge(e.getErrors());
+ putBinding(invalidBinding(injector, key, source));
+ }
+
+ return true;
+ }
- // Error: Missing implementation.
- // Example: bind(Date.class).annotatedWith(Red.class);
- // We can't assume abstract types aren't injectable. They may have an
- // @ImplementedBy annotation or something.
- if (key.getAnnotationType() != null) {
- errors.missingImplementation(key);
- putBinding(invalidBinding(injector, key, source));
- return true;
- }
-
- // This cast is safe after the preceeding check.
- try {
- BindingImpl<T> binding = injector.createUninitializedBinding(
- key, scoping, source, errors, false);
- scheduleInitialization(binding);
- putBinding(binding);
- } catch (ErrorsException e) {
- errors.merge(e.getErrors());
- putBinding(invalidBinding(injector, key, source));
- }
-
- return true;
- }
-
- @Override
- protected Boolean visitOther(Binding<? extends T> binding) {
- return false;
- }
- });
+ @Override
+ protected Boolean visitOther(Binding<? extends T> binding) {
+ return false;
+ }
+ });
}
}
diff --git a/core/src/com/google/inject/internal/WeakKeySet.java b/core/src/com/google/inject/internal/WeakKeySet.java
index ca137df6..c0cf668c 100644
--- a/core/src/com/google/inject/internal/WeakKeySet.java
+++ b/core/src/com/google/inject/internal/WeakKeySet.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,7 +29,6 @@ import com.google.common.collect.Multiset;
import com.google.common.collect.Sets;
import com.google.inject.Key;
import com.google.inject.internal.util.SourceProvider;
-
import java.util.Map;
import java.util.Set;
@@ -52,18 +51,19 @@ final class WeakKeySet {
* Tracks child injector lifetimes and evicts blacklisted keys/sources after the child injector is
* garbage collected.
*/
- private final Cache<State, Set<KeyAndSource>> evictionCache = CacheBuilder.newBuilder()
- .weakKeys()
- .removalListener(
- new RemovalListener<State, Set<KeyAndSource>>() {
- @Override
- public void onRemoval(RemovalNotification<State, Set<KeyAndSource>> notification) {
- Preconditions.checkState(RemovalCause.COLLECTED.equals(notification.getCause()));
-
- cleanUpForCollectedState(notification.getValue());
- }
- })
- .build();
+ private final Cache<State, Set<KeyAndSource>> evictionCache =
+ CacheBuilder.newBuilder()
+ .weakKeys()
+ .removalListener(
+ new RemovalListener<State, Set<KeyAndSource>>() {
+ @Override
+ public void onRemoval(RemovalNotification<State, Set<KeyAndSource>> notification) {
+ Preconditions.checkState(RemovalCause.COLLECTED.equals(notification.getCause()));
+
+ cleanUpForCollectedState(notification.getValue());
+ }
+ })
+ .build();
/**
* There may be multiple child injectors blacklisting a certain key so only remove the source
@@ -150,8 +150,7 @@ final class WeakKeySet {
}
KeyAndSource other = (KeyAndSource) obj;
- return Objects.equal(key, other.key)
- && Objects.equal(source, other.source);
+ return Objects.equal(key, other.key) && Objects.equal(source, other.source);
}
}
}
diff --git a/core/src/com/google/inject/internal/package-info.java b/core/src/com/google/inject/internal/package-info.java
index 4116f110..8e88e927 100644
--- a/core/src/com/google/inject/internal/package-info.java
+++ b/core/src/com/google/inject/internal/package-info.java
@@ -14,7 +14,5 @@
* limitations under the License.
*/
-/**
- * <i>Guice</i> (sounds like like "juice")
- */
+/** <i>Guice</i> (sounds like "juice") */
package com.google.inject.internal;
diff --git a/core/src/com/google/inject/internal/util/Classes.java b/core/src/com/google/inject/internal/util/Classes.java
index 0badab12..47174606 100644
--- a/core/src/com/google/inject/internal/util/Classes.java
+++ b/core/src/com/google/inject/internal/util/Classes.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2007 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,14 +24,11 @@ import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
-/**
- * Class utilities.
- */
+/** Class utilities. */
public final class Classes {
public static boolean isInnerClass(Class<?> clazz) {
- return !Modifier.isStatic(clazz.getModifiers())
- && clazz.getEnclosingClass() != null;
+ return !Modifier.isStatic(clazz.getModifiers()) && clazz.getEnclosingClass() != null;
}
public static boolean isConcrete(Class<?> clazz) {
@@ -40,12 +37,12 @@ public final class Classes {
}
/**
- * Formats a member as concise string, such as {@code java.util.ArrayList.size},
- * {@code java.util.ArrayList<init>()} or {@code java.util.List.remove()}.
+ * Formats a member as concise string, such as {@code java.util.ArrayList.size}, {@code
+ * java.util.ArrayList<init>()} or {@code java.util.List.remove()}.
*/
public static String toString(Member member) {
Class<? extends Member> memberType = Classes.memberType(member);
-
+
if (memberType == Method.class) {
return member.getDeclaringClass().getName() + "." + member.getName() + "()";
} else if (memberType == Field.class) {
@@ -57,21 +54,19 @@ public final class Classes {
}
}
- /**
- * Returns {@code Field.class}, {@code Method.class} or {@code Constructor.class}.
- */
+ /** Returns {@code Field.class}, {@code Method.class} or {@code Constructor.class}. */
public static Class<? extends Member> memberType(Member member) {
checkNotNull(member, "member");
-
+
if (member instanceof Field) {
return Field.class;
-
+
} else if (member instanceof Method) {
return Method.class;
-
+
} else if (member instanceof Constructor) {
return Constructor.class;
-
+
} else {
throw new IllegalArgumentException(
"Unsupported implementation class for Member, " + member.getClass());
diff --git a/core/src/com/google/inject/internal/util/LineNumbers.java b/core/src/com/google/inject/internal/util/LineNumbers.java
index 57c98b92..0179e8a0 100644
--- a/core/src/com/google/inject/internal/util/LineNumbers.java
+++ b/core/src/com/google/inject/internal/util/LineNumbers.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,15 +20,6 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
-
-import org.objectweb.asm.AnnotationVisitor;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.FieldVisitor;
-import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
@@ -36,6 +27,13 @@ import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.util.Map;
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
/**
* Looks up line numbers for classes and their members.
@@ -62,7 +60,14 @@ final class LineNumbers {
if (!type.isArray()) {
InputStream in = type.getResourceAsStream("/" + type.getName().replace('.', '/') + ".class");
if (in != null) {
- new ClassReader(in).accept(new LineNumberReader(), ClassReader.SKIP_FRAMES);
+ try {
+ new ClassReader(in).accept(new LineNumberReader(), ClassReader.SKIP_FRAMES);
+ } finally {
+ try {
+ in.close();
+ } catch (IOException ignored) {
+ }
+ }
}
}
}
@@ -82,11 +87,15 @@ final class LineNumbers {
* @param member a field, constructor, or method belonging to the class used during construction
* @return the wrapped line number, or null if not available
* @throws IllegalArgumentException if the member does not belong to the class used during
- * construction
+ * construction
*/
public Integer getLineNumber(Member member) {
- Preconditions.checkArgument(type == member.getDeclaringClass(),
- "Member %s belongs to %s, not %s", member, member.getDeclaringClass(), type);
+ Preconditions.checkArgument(
+ type == member.getDeclaringClass(),
+ "Member %s belongs to %s, not %s",
+ member,
+ member.getDeclaringClass(),
+ type);
return lines.get(memberKey(member));
}
@@ -108,7 +117,7 @@ final class LineNumbers {
} else if (member instanceof Constructor) {
StringBuilder sb = new StringBuilder().append("<init>(");
for (Class param : ((Constructor) member).getParameterTypes()) {
- sb.append(org.objectweb.asm.Type.getDescriptor(param));
+ sb.append(org.objectweb.asm.Type.getDescriptor(param));
}
return sb.append(")V").toString();
@@ -120,7 +129,7 @@ final class LineNumbers {
/*if[NO_AOP]
return "<NO_MEMBER_KEY>";
end[NO_AOP]*/
- }
+ }
private class LineNumberReader extends ClassVisitor {
@@ -129,16 +138,23 @@ final class LineNumbers {
private String name;
LineNumberReader() {
- super(Opcodes.ASM5);
+ super(Opcodes.ASM6);
}
- public void visit(int version, int access, String name, String signature,
- String superName, String[] interfaces) {
+ @Override
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
this.name = name;
}
- public MethodVisitor visitMethod(int access, String name, String desc,
- String signature, String[] exceptions) {
+ @Override
+ public MethodVisitor visitMethod(
+ int access, String name, String desc, String signature, String[] exceptions) {
if ((access & Opcodes.ACC_PRIVATE) != 0) {
return null;
}
@@ -147,6 +163,7 @@ final class LineNumbers {
return new LineNumberMethodVisitor();
}
+ @Override
public void visitSource(String source, String debug) {
LineNumbers.this.source = source;
}
@@ -163,41 +180,47 @@ final class LineNumbers {
}
}
- public FieldVisitor visitField(int access, String name, String desc,
- String signature, Object value) {
+ @Override
+ public FieldVisitor visitField(
+ int access, String name, String desc, String signature, Object value) {
return null;
}
+ @Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
return new LineNumberAnnotationVisitor();
}
- public AnnotationVisitor visitParameterAnnotation(int parameter,
- String desc, boolean visible) {
+ public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) {
return new LineNumberAnnotationVisitor();
}
class LineNumberMethodVisitor extends MethodVisitor {
LineNumberMethodVisitor() {
- super(Opcodes.ASM5);
+ super(Opcodes.ASM6);
}
+ @Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
return new LineNumberAnnotationVisitor();
}
+ @Override
public AnnotationVisitor visitAnnotationDefault() {
return new LineNumberAnnotationVisitor();
}
- public void visitFieldInsn(int opcode, String owner, String name,
- String desc) {
- if (opcode == Opcodes.PUTFIELD && LineNumberReader.this.name.equals(owner)
- && !lines.containsKey(name) && line != -1) {
+ @Override
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ if (opcode == Opcodes.PUTFIELD
+ && LineNumberReader.this.name.equals(owner)
+ && !lines.containsKey(name)
+ && line != -1) {
lines.put(name, line);
}
}
+ @Override
public void visitLineNumber(int line, Label start) {
LineNumberReader.this.visitLineNumber(line, start);
}
@@ -205,19 +228,21 @@ final class LineNumbers {
class LineNumberAnnotationVisitor extends AnnotationVisitor {
LineNumberAnnotationVisitor() {
- super(Opcodes.ASM5);
+ super(Opcodes.ASM6);
}
+
+ @Override
public AnnotationVisitor visitAnnotation(String name, String desc) {
return this;
}
+
+ @Override
public AnnotationVisitor visitArray(String name) {
return this;
}
- public void visitLocalVariable(String name, String desc, String signature,
- Label start, Label end, int index) {
- }
+ public void visitLocalVariable(
+ String name, String desc, String signature, Label start, Label end, int index) {}
}
-
}
}
diff --git a/core/src/com/google/inject/internal/util/SourceProvider.java b/core/src/com/google/inject/internal/util/SourceProvider.java
index 9d4b9f9a..bcb84de5 100644
--- a/core/src/com/google/inject/internal/util/SourceProvider.java
+++ b/core/src/com/google/inject/internal/util/SourceProvider.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,12 +19,11 @@ package com.google.inject.internal.util;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
-
import java.util.List;
/**
* Provides access to the calling line of code.
- *
+ *
* @author crazybob@google.com (Bob Lee)
*/
public final class SourceProvider {
@@ -34,9 +33,9 @@ public final class SourceProvider {
private final SourceProvider parent;
private final ImmutableSet<String> classNamesToSkip;
-
- public static final SourceProvider DEFAULT_INSTANCE
- = new SourceProvider(ImmutableSet.of(SourceProvider.class.getName()));
+
+ public static final SourceProvider DEFAULT_INSTANCE =
+ new SourceProvider(ImmutableSet.of(SourceProvider.class.getName()));
private SourceProvider(Iterable<String> classesToSkip) {
this(null, classesToSkip);
@@ -44,7 +43,7 @@ public final class SourceProvider {
private SourceProvider(SourceProvider parent, Iterable<String> classesToSkip) {
this.parent = parent;
-
+
ImmutableSet.Builder<String> classNamesToSkipBuilder = ImmutableSet.builder();
for (String classToSkip : classesToSkip) {
if (parent == null || !parent.shouldBeSkipped(classToSkip)) {
@@ -64,7 +63,7 @@ public final class SourceProvider {
return (parent != null && parent.shouldBeSkipped(className))
|| classNamesToSkip.contains(className);
}
-
+
/** Returns the class names as Strings */
private static List<String> asStrings(Class... classes) {
List<String> strings = Lists.newArrayList();
@@ -82,7 +81,7 @@ public final class SourceProvider {
Preconditions.checkNotNull(stackTraceElements, "The stack trace elements cannot be null.");
for (final StackTraceElement element : stackTraceElements) {
String className = element.getClassName();
-
+
if (!shouldBeSkipped(className)) {
return element;
}
@@ -90,9 +89,7 @@ public final class SourceProvider {
throw new AssertionError();
}
- /**
- * Returns the non-skipped module class name.
- */
+ /** Returns the non-skipped module class name. */
public Object getFromClassNames(List<String> moduleClassNames) {
Preconditions.checkNotNull(moduleClassNames, "The list of module class names cannot be null.");
for (final String moduleClassName : moduleClassNames) {
diff --git a/core/src/com/google/inject/internal/util/StackTraceElements.java b/core/src/com/google/inject/internal/util/StackTraceElements.java
index 69f930f1..486855b9 100644
--- a/core/src/com/google/inject/internal/util/StackTraceElements.java
+++ b/core/src/com/google/inject/internal/util/StackTraceElements.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,12 +19,11 @@ package com.google.inject.internal.util;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
-import com.google.common.collect.MapMaker;
-
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Member;
-import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
/**
* Creates stack trace elements for members.
@@ -34,25 +33,31 @@ import java.util.Map;
public class StackTraceElements {
private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
- private static final InMemoryStackTraceElement[] EMPTY_INMEMORY_STACK_TRACE =
+ private static final InMemoryStackTraceElement[] EMPTY_INMEMORY_STACK_TRACE =
new InMemoryStackTraceElement[0];
/*if[AOP]*/
static final LoadingCache<Class<?>, LineNumbers> lineNumbersCache =
- CacheBuilder.newBuilder().weakKeys().softValues().build(
- new CacheLoader<Class<?>, LineNumbers>() {
- public LineNumbers load(Class<?> key) {
- try {
- return new LineNumbers(key);
- }
- catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
- });
+ CacheBuilder.newBuilder()
+ .weakKeys()
+ .softValues()
+ .build(
+ new CacheLoader<Class<?>, LineNumbers>() {
+ @Override
+ public LineNumbers load(Class<?> key) {
+ try {
+ return new LineNumbers(key);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ });
/*end[AOP]*/
- private static Map<Object, Object> cache = new MapMaker().makeMap();
+ private static final ConcurrentMap<InMemoryStackTraceElement, InMemoryStackTraceElement>
+ elementCache = new ConcurrentHashMap<>();
+ private static final ConcurrentMap<String, String> stringCache = new ConcurrentHashMap<>();
+
private static final String UNKNOWN_SOURCE = "Unknown Source";
public static Object forMember(Member member) {
@@ -91,31 +96,28 @@ public class StackTraceElements {
return new StackTraceElement(implementation.getName(), "class", fileName, lineNumber);
}
-
- /**
- * Clears the internal cache for {@link StackTraceElement StackTraceElements}.
- */
+
+ /** Clears the internal cache for {@link StackTraceElement StackTraceElements}. */
public static void clearCache() {
- cache.clear();
+ elementCache.clear();
+ stringCache.clear();
}
-
- /**
- * Returns encoded in-memory version of {@link StackTraceElement StackTraceElements}.
- */
+
+ /** Returns encoded in-memory version of {@link StackTraceElement StackTraceElements}. */
public static InMemoryStackTraceElement[] convertToInMemoryStackTraceElement(
StackTraceElement[] stackTraceElements) {
if (stackTraceElements.length == 0) {
return EMPTY_INMEMORY_STACK_TRACE;
}
- InMemoryStackTraceElement[] inMemoryStackTraceElements =
+ InMemoryStackTraceElement[] inMemoryStackTraceElements =
new InMemoryStackTraceElement[stackTraceElements.length];
for (int i = 0; i < stackTraceElements.length; i++) {
- inMemoryStackTraceElements[i] =
+ inMemoryStackTraceElements[i] =
weakIntern(new InMemoryStackTraceElement(stackTraceElements[i]));
}
return inMemoryStackTraceElements;
}
-
+
/**
* Decodes in-memory stack trace elements to regular {@link StackTraceElement StackTraceElements}.
*/
@@ -124,45 +126,43 @@ public class StackTraceElements {
if (inMemoryStackTraceElements.length == 0) {
return EMPTY_STACK_TRACE;
}
- StackTraceElement[] stackTraceElements =
+ StackTraceElement[] stackTraceElements =
new StackTraceElement[inMemoryStackTraceElements.length];
for (int i = 0; i < inMemoryStackTraceElements.length; i++) {
String declaringClass = inMemoryStackTraceElements[i].getClassName();
String methodName = inMemoryStackTraceElements[i].getMethodName();
int lineNumber = inMemoryStackTraceElements[i].getLineNumber();
- stackTraceElements[i] =
+ stackTraceElements[i] =
new StackTraceElement(declaringClass, methodName, UNKNOWN_SOURCE, lineNumber);
}
return stackTraceElements;
}
-
+
private static InMemoryStackTraceElement weakIntern(
InMemoryStackTraceElement inMemoryStackTraceElement) {
- InMemoryStackTraceElement cached =
- (InMemoryStackTraceElement) cache.get(inMemoryStackTraceElement);
+ InMemoryStackTraceElement cached = elementCache.get(inMemoryStackTraceElement);
if (cached != null) {
return cached;
}
- inMemoryStackTraceElement = new InMemoryStackTraceElement(
- weakIntern(inMemoryStackTraceElement.getClassName()),
- weakIntern(inMemoryStackTraceElement.getMethodName()),
- inMemoryStackTraceElement.getLineNumber());
- cache.put(inMemoryStackTraceElement, inMemoryStackTraceElement);
+ inMemoryStackTraceElement =
+ new InMemoryStackTraceElement(
+ weakIntern(inMemoryStackTraceElement.getClassName()),
+ weakIntern(inMemoryStackTraceElement.getMethodName()),
+ inMemoryStackTraceElement.getLineNumber());
+ elementCache.put(inMemoryStackTraceElement, inMemoryStackTraceElement);
return inMemoryStackTraceElement;
}
-
+
private static String weakIntern(String s) {
- String cached = (String) cache.get(s);
+ String cached = stringCache.get(s);
if (cached != null) {
return cached;
}
- cache.put(s, s);
- return s;
+ stringCache.put(s, s);
+ return s;
}
-
- /**
- * In-Memory version of {@link StackTraceElement} that does not store the file name.
- */
+
+ /** In-Memory version of {@link StackTraceElement} that does not store the file name. */
public static class InMemoryStackTraceElement {
private String declaringClass;
private String methodName;
@@ -181,11 +181,11 @@ public class StackTraceElements {
String getClassName() {
return declaringClass;
}
-
+
String getMethodName() {
return methodName;
}
-
+
int getLineNumber() {
return lineNumber;
}
@@ -199,8 +199,9 @@ public class StackTraceElements {
return false;
}
InMemoryStackTraceElement e = (InMemoryStackTraceElement) obj;
- return e.declaringClass.equals(declaringClass) && e.lineNumber == lineNumber &&
- methodName.equals(e.methodName);
+ return e.declaringClass.equals(declaringClass)
+ && e.lineNumber == lineNumber
+ && methodName.equals(e.methodName);
}
@Override
@@ -209,7 +210,7 @@ public class StackTraceElements {
result = 31 * result + lineNumber;
return result;
}
-
+
@Override
public String toString() {
return declaringClass + "." + methodName + "(" + lineNumber + ")";
diff --git a/core/src/com/google/inject/internal/util/Stopwatch.java b/core/src/com/google/inject/internal/util/Stopwatch.java
index 92c73fba..04953d44 100644
--- a/core/src/com/google/inject/internal/util/Stopwatch.java
+++ b/core/src/com/google/inject/internal/util/Stopwatch.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -28,9 +28,7 @@ public final class Stopwatch {
private long start = System.currentTimeMillis();
- /**
- * Resets and returns elapsed time in milliseconds.
- */
+ /** Resets and returns elapsed time in milliseconds. */
public long reset() {
long now = System.currentTimeMillis();
try {
@@ -40,9 +38,7 @@ public final class Stopwatch {
}
}
- /**
- * Resets and logs elapsed time in milliseconds.
- */
+ /** Resets and logs elapsed time in milliseconds. */
public void resetAndLog(String label) {
logger.fine(label + ": " + reset() + "ms");
}
diff --git a/core/src/com/google/inject/matcher/AbstractMatcher.java b/core/src/com/google/inject/matcher/AbstractMatcher.java
index 91ea2e67..08209fc3 100644
--- a/core/src/com/google/inject/matcher/AbstractMatcher.java
+++ b/core/src/com/google/inject/matcher/AbstractMatcher.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,10 +25,12 @@ import java.io.Serializable;
*/
public abstract class AbstractMatcher<T> implements Matcher<T> {
+ @Override
public Matcher<T> and(final Matcher<? super T> other) {
return new AndMatcher<T>(this, other);
}
+ @Override
public Matcher<T> or(Matcher<? super T> other) {
return new OrMatcher<T>(this, other);
}
@@ -41,21 +43,25 @@ public abstract class AbstractMatcher<T> implements Matcher<T> {
this.b = b;
}
+ @Override
public boolean matches(T t) {
return a.matches(t) && b.matches(t);
}
- @Override public boolean equals(Object other) {
+ @Override
+ public boolean equals(Object other) {
return other instanceof AndMatcher
&& ((AndMatcher) other).a.equals(a)
&& ((AndMatcher) other).b.equals(b);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return 41 * (a.hashCode() ^ b.hashCode());
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "and(" + a + ", " + b + ")";
}
@@ -70,21 +76,25 @@ public abstract class AbstractMatcher<T> implements Matcher<T> {
this.b = b;
}
+ @Override
public boolean matches(T t) {
return a.matches(t) || b.matches(t);
}
- @Override public boolean equals(Object other) {
+ @Override
+ public boolean equals(Object other) {
return other instanceof OrMatcher
&& ((OrMatcher) other).a.equals(a)
&& ((OrMatcher) other).b.equals(b);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return 37 * (a.hashCode() ^ b.hashCode());
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "or(" + a + ", " + b + ")";
}
diff --git a/core/src/com/google/inject/matcher/Matcher.java b/core/src/com/google/inject/matcher/Matcher.java
index 681f1256..6eb81e88 100644
--- a/core/src/com/google/inject/matcher/Matcher.java
+++ b/core/src/com/google/inject/matcher/Matcher.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,20 +23,18 @@ package com.google.inject.matcher;
*/
public interface Matcher<T> {
- /**
- * Returns {@code true} if this matches {@code t}, {@code false} otherwise.
- */
+ /** Returns {@code true} if this matches {@code t}, {@code false} otherwise. */
boolean matches(T t);
/**
- * Returns a new matcher which returns {@code true} if both this and the
- * given matcher return {@code true}.
+ * Returns a new matcher which returns {@code true} if both this and the given matcher return
+ * {@code true}.
*/
Matcher<T> and(Matcher<? super T> other);
/**
- * Returns a new matcher which returns {@code true} if either this or the
- * given matcher return {@code true}.
+ * Returns a new matcher which returns {@code true} if either this or the given matcher return
+ * {@code true}.
*/
Matcher<T> or(Matcher<? super T> other);
}
diff --git a/core/src/com/google/inject/matcher/Matchers.java b/core/src/com/google/inject/matcher/Matchers.java
index 1bebcdb1..7aaf750e 100644
--- a/core/src/com/google/inject/matcher/Matchers.java
+++ b/core/src/com/google/inject/matcher/Matchers.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,9 +34,7 @@ import java.lang.reflect.Method;
public class Matchers {
private Matchers() {}
- /**
- * Returns a matcher which matches any input.
- */
+ /** Returns a matcher which matches any input. */
public static Matcher<Object> any() {
return ANY;
}
@@ -44,11 +42,13 @@ public class Matchers {
private static final Matcher<Object> ANY = new Any();
private static class Any extends AbstractMatcher<Object> implements Serializable {
+ @Override
public boolean matches(Object o) {
return true;
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "any()";
}
@@ -59,9 +59,7 @@ public class Matchers {
private static final long serialVersionUID = 0;
}
- /**
- * Inverts the given matcher.
- */
+ /** Inverts the given matcher. */
public static <T> Matcher<T> not(final Matcher<? super T> p) {
return new Not<T>(p);
}
@@ -73,37 +71,38 @@ public class Matchers {
this.delegate = checkNotNull(delegate, "delegate");
}
+ @Override
public boolean matches(T t) {
return !delegate.matches(t);
}
- @Override public boolean equals(Object other) {
- return other instanceof Not
- && ((Not) other).delegate.equals(delegate);
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof Not && ((Not) other).delegate.equals(delegate);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return -delegate.hashCode();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "not(" + delegate + ")";
}
private static final long serialVersionUID = 0;
}
- private static void checkForRuntimeRetention(
- Class<? extends Annotation> annotationType) {
+ private static void checkForRuntimeRetention(Class<? extends Annotation> annotationType) {
Retention retention = annotationType.getAnnotation(Retention.class);
- checkArgument(retention != null && retention.value() == RetentionPolicy.RUNTIME,
- "Annotation %s is missing RUNTIME retention", annotationType.getSimpleName());
+ checkArgument(
+ retention != null && retention.value() == RetentionPolicy.RUNTIME,
+ "Annotation %s is missing RUNTIME retention",
+ annotationType.getSimpleName());
}
- /**
- * Returns a matcher which matches elements (methods, classes, etc.)
- * with a given annotation.
- */
+ /** Returns a matcher which matches elements (methods, classes, etc.) with a given annotation. */
public static Matcher<AnnotatedElement> annotatedWith(
final Class<? extends Annotation> annotationType) {
return new AnnotatedWithType(annotationType);
@@ -118,32 +117,32 @@ public class Matchers {
checkForRuntimeRetention(annotationType);
}
+ @Override
public boolean matches(AnnotatedElement element) {
return element.isAnnotationPresent(annotationType);
}
- @Override public boolean equals(Object other) {
+ @Override
+ public boolean equals(Object other) {
return other instanceof AnnotatedWithType
&& ((AnnotatedWithType) other).annotationType.equals(annotationType);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return 37 * annotationType.hashCode();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "annotatedWith(" + annotationType.getSimpleName() + ".class)";
}
private static final long serialVersionUID = 0;
}
- /**
- * Returns a matcher which matches elements (methods, classes, etc.)
- * with a given annotation.
- */
- public static Matcher<AnnotatedElement> annotatedWith(
- final Annotation annotation) {
+ /** Returns a matcher which matches elements (methods, classes, etc.) with a given annotation. */
+ public static Matcher<AnnotatedElement> annotatedWith(final Annotation annotation) {
return new AnnotatedWith(annotation);
}
@@ -156,127 +155,130 @@ public class Matchers {
checkForRuntimeRetention(annotation.annotationType());
}
+ @Override
public boolean matches(AnnotatedElement element) {
Annotation fromElement = element.getAnnotation(annotation.annotationType());
return fromElement != null && annotation.equals(fromElement);
}
- @Override public boolean equals(Object other) {
+ @Override
+ public boolean equals(Object other) {
return other instanceof AnnotatedWith
&& ((AnnotatedWith) other).annotation.equals(annotation);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return 37 * annotation.hashCode();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "annotatedWith(" + annotation + ")";
}
private static final long serialVersionUID = 0;
}
- /**
- * Returns a matcher which matches subclasses of the given type (as well as
- * the given type).
- */
+ /** Returns a matcher which matches subclasses of the given type (as well as the given type). */
public static Matcher<Class> subclassesOf(final Class<?> superclass) {
return new SubclassesOf(superclass);
}
- private static class SubclassesOf extends AbstractMatcher<Class>
- implements Serializable {
+ private static class SubclassesOf extends AbstractMatcher<Class> implements Serializable {
private final Class<?> superclass;
public SubclassesOf(Class<?> superclass) {
this.superclass = checkNotNull(superclass, "superclass");
}
+ @Override
public boolean matches(Class subclass) {
return superclass.isAssignableFrom(subclass);
}
- @Override public boolean equals(Object other) {
- return other instanceof SubclassesOf
- && ((SubclassesOf) other).superclass.equals(superclass);
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof SubclassesOf && ((SubclassesOf) other).superclass.equals(superclass);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return 37 * superclass.hashCode();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "subclassesOf(" + superclass.getSimpleName() + ".class)";
}
private static final long serialVersionUID = 0;
}
- /**
- * Returns a matcher which matches objects equal to the given object.
- */
+ /** Returns a matcher which matches objects equal to the given object. */
public static Matcher<Object> only(Object value) {
return new Only(value);
}
- private static class Only extends AbstractMatcher<Object>
- implements Serializable {
+ private static class Only extends AbstractMatcher<Object> implements Serializable {
private final Object value;
public Only(Object value) {
this.value = checkNotNull(value, "value");
}
+ @Override
public boolean matches(Object other) {
return value.equals(other);
}
- @Override public boolean equals(Object other) {
- return other instanceof Only
- && ((Only) other).value.equals(value);
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof Only && ((Only) other).value.equals(value);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return 37 * value.hashCode();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "only(" + value + ")";
}
private static final long serialVersionUID = 0;
}
- /**
- * Returns a matcher which matches only the given object.
- */
+ /** Returns a matcher which matches only the given object. */
public static Matcher<Object> identicalTo(final Object value) {
return new IdenticalTo(value);
}
- private static class IdenticalTo extends AbstractMatcher<Object>
- implements Serializable {
+ private static class IdenticalTo extends AbstractMatcher<Object> implements Serializable {
private final Object value;
public IdenticalTo(Object value) {
this.value = checkNotNull(value, "value");
}
+ @Override
public boolean matches(Object other) {
return value == other;
}
- @Override public boolean equals(Object other) {
- return other instanceof IdenticalTo
- && ((IdenticalTo) other).value == value;
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof IdenticalTo && ((IdenticalTo) other).value == value;
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return 37 * System.identityHashCode(value);
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "identicalTo(" + value + ")";
}
@@ -300,20 +302,23 @@ public class Matchers {
this.packageName = targetPackage.getName();
}
+ @Override
public boolean matches(Class c) {
return c.getPackage().equals(targetPackage);
}
- @Override public boolean equals(Object other) {
- return other instanceof InPackage
- && ((InPackage) other).targetPackage.equals(targetPackage);
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof InPackage && ((InPackage) other).targetPackage.equals(targetPackage);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return 37 * targetPackage.hashCode();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "inPackage(" + targetPackage.getName() + ")";
}
@@ -325,9 +330,9 @@ public class Matchers {
}
/**
- * Returns a matcher which matches classes in the given package and its subpackages. Unlike
- * {@link #inPackage(Package) inPackage()}, this matches classes from any classloader.
- *
+ * Returns a matcher which matches classes in the given package and its subpackages. Unlike {@link
+ * #inPackage(Package) inPackage()}, this matches classes from any classloader.
+ *
* @since 2.0
*/
public static Matcher<Class> inSubpackage(final String targetPackageName) {
@@ -341,33 +346,34 @@ public class Matchers {
this.targetPackageName = targetPackageName;
}
+ @Override
public boolean matches(Class c) {
String classPackageName = c.getPackage().getName();
return classPackageName.equals(targetPackageName)
|| classPackageName.startsWith(targetPackageName + ".");
}
- @Override public boolean equals(Object other) {
+ @Override
+ public boolean equals(Object other) {
return other instanceof InSubpackage
&& ((InSubpackage) other).targetPackageName.equals(targetPackageName);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return 37 * targetPackageName.hashCode();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "inSubpackage(" + targetPackageName + ")";
}
private static final long serialVersionUID = 0;
}
- /**
- * Returns a matcher which matches methods with matching return types.
- */
- public static Matcher<Method> returns(
- final Matcher<? super Class<?>> returnType) {
+ /** Returns a matcher which matches methods with matching return types. */
+ public static Matcher<Method> returns(final Matcher<? super Class<?>> returnType) {
return new Returns(returnType);
}
@@ -378,20 +384,23 @@ public class Matchers {
this.returnType = checkNotNull(returnType, "return type matcher");
}
+ @Override
public boolean matches(Method m) {
return returnType.matches(m.getReturnType());
}
- @Override public boolean equals(Object other) {
- return other instanceof Returns
- && ((Returns) other).returnType.equals(returnType);
+ @Override
+ public boolean equals(Object other) {
+ return other instanceof Returns && ((Returns) other).returnType.equals(returnType);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return 37 * returnType.hashCode();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "returns(" + returnType + ")";
}
diff --git a/core/src/com/google/inject/matcher/package-info.java b/core/src/com/google/inject/matcher/package-info.java
index ced3238c..d37eed29 100644
--- a/core/src/com/google/inject/matcher/package-info.java
+++ b/core/src/com/google/inject/matcher/package-info.java
@@ -14,8 +14,5 @@
* limitations under the License.
*/
-/**
- * Used for matching things. Primarily used to pick out methods to which to
- * apply interceptors.
- */
-package com.google.inject.matcher; \ No newline at end of file
+/** Used for matching things. Primarily used to pick out methods to which to apply interceptors. */
+package com.google.inject.matcher;
diff --git a/core/src/com/google/inject/multibindings/ClassMapKey.java b/core/src/com/google/inject/multibindings/ClassMapKey.java
new file mode 100644
index 00000000..19527c79
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/ClassMapKey.java
@@ -0,0 +1,37 @@
+/*
+ * 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.multibindings;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Allows {@literal @}{@link ProvidesIntoMap} to specify a class map key.
+ *
+ * @since 4.0
+ */
+@MapKey(unwrapValue = true)
+@Documented
+@Target(METHOD)
+@Retention(RUNTIME)
+public @interface ClassMapKey {
+ Class<?> value();
+}
diff --git a/core/src/com/google/inject/multibindings/MapBinder.java b/core/src/com/google/inject/multibindings/MapBinder.java
new file mode 100644
index 00000000..fbc506c7
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/MapBinder.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2008 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.multibindings;
+
+import static com.google.inject.internal.RealMapBinder.newMapRealBinder;
+import static com.google.inject.internal.RealMapBinder.newRealMapBinder;
+
+import com.google.inject.Binder;
+import com.google.inject.TypeLiteral;
+import com.google.inject.binder.LinkedBindingBuilder;
+import com.google.inject.internal.RealMapBinder;
+import java.lang.annotation.Annotation;
+import java.util.Map;
+
+/**
+ * An API to bind multiple map entries separately, only to later inject them as a complete map.
+ * MapBinder is intended for use in your application's module:
+ *
+ * <pre><code>
+ * public class SnacksModule extends AbstractModule {
+ * protected void configure() {
+ * MapBinder&lt;String, Snack&gt; mapbinder
+ * = MapBinder.newMapBinder(binder(), String.class, Snack.class);
+ * mapbinder.addBinding("twix").toInstance(new Twix());
+ * mapbinder.addBinding("snickers").toProvider(SnickersProvider.class);
+ * mapbinder.addBinding("skittles").to(Skittles.class);
+ * }
+ * }</code></pre>
+ *
+ * <p>With this binding, a {@link Map}{@code <String, Snack>} can now be injected:
+ *
+ * <pre><code>
+ * class SnackMachine {
+ * {@literal @}Inject
+ * public SnackMachine(Map&lt;String, Snack&gt; snacks) { ... }
+ * }</code></pre>
+ *
+ * <p>In addition to binding {@code Map<K, V>}, a mapbinder will also bind {@code Map<K,
+ * Provider<V>>} for lazy value provision:
+ *
+ * <pre><code>
+ * class SnackMachine {
+ * {@literal @}Inject
+ * public SnackMachine(Map&lt;String, Provider&lt;Snack&gt;&gt; snackProviders) { ... }
+ * }</code></pre>
+ *
+ * <p>Contributing mapbindings from different modules is supported. For example, it is okay to have
+ * both {@code CandyModule} and {@code ChipsModule} both create their own {@code MapBinder<String,
+ * Snack>}, and to each contribute bindings to the snacks map. When that map is injected, it will
+ * contain entries from both modules.
+ *
+ * <p>The map's iteration order is consistent with the binding order. This is convenient when
+ * multiple elements are contributed by the same module because that module can order its bindings
+ * appropriately. Avoid relying on the iteration order of elements contributed by different modules,
+ * since there is no equivalent mechanism to order modules.
+ *
+ * <p>The map is unmodifiable. Elements can only be added to the map by configuring the MapBinder.
+ * Elements can never be removed from the map.
+ *
+ * <p>Values are resolved at map injection time. If a value is bound to a provider, that provider's
+ * get method will be called each time the map is injected (unless the binding is also scoped, or a
+ * map of providers is injected).
+ *
+ * <p>Annotations are used to create different maps of the same key/value type. Each distinct
+ * annotation gets its own independent map.
+ *
+ * <p><strong>Keys must be distinct.</strong> If the same key is bound more than once, map injection
+ * will fail. However, use {@link #permitDuplicates()} in order to allow duplicate keys; extra
+ * bindings to {@code Map<K, Set<V>>} and {@code Map<K, Set<Provider<V>>} will be added.
+ *
+ * <p><strong>Keys must be non-null.</strong> {@code addBinding(null)} will throw an unchecked
+ * exception.
+ *
+ * <p><strong>Values must be non-null to use map injection.</strong> If any value is null, map
+ * injection will fail (although injecting a map of providers will not).
+ *
+ * @author dpb@google.com (David P. Baker)
+ */
+public class MapBinder<K, V> {
+ // This class is non-final due to users mocking this in tests :(
+
+ /**
+ * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link
+ * Map} that is itself bound with no binding annotation.
+ */
+ public static <K, V> MapBinder<K, V> newMapBinder(
+ Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType) {
+ return new MapBinder<K, V>(
+ newMapRealBinder(binder.skipSources(MapBinder.class), keyType, valueType));
+ }
+
+ /**
+ * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link
+ * Map} that is itself bound with no binding annotation.
+ */
+ public static <K, V> MapBinder<K, V> newMapBinder(
+ Binder binder, Class<K> keyType, Class<V> valueType) {
+ return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType));
+ }
+
+ /**
+ * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link
+ * Map} that is itself bound with {@code annotation}.
+ */
+ public static <K, V> MapBinder<K, V> newMapBinder(
+ Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType, Annotation annotation) {
+ return new MapBinder<K, V>(
+ newRealMapBinder(binder.skipSources(MapBinder.class), keyType, valueType, annotation));
+ }
+
+ /**
+ * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link
+ * Map} that is itself bound with {@code annotation}.
+ */
+ public static <K, V> MapBinder<K, V> newMapBinder(
+ Binder binder, Class<K> keyType, Class<V> valueType, Annotation annotation) {
+ return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType), annotation);
+ }
+
+ /**
+ * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link
+ * Map} that is itself bound with {@code annotationType}.
+ */
+ public static <K, V> MapBinder<K, V> newMapBinder(
+ Binder binder,
+ TypeLiteral<K> keyType,
+ TypeLiteral<V> valueType,
+ Class<? extends Annotation> annotationType) {
+ return new MapBinder<K, V>(
+ newRealMapBinder(binder.skipSources(MapBinder.class), keyType, valueType, annotationType));
+ }
+
+ /**
+ * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link
+ * Map} that is itself bound with {@code annotationType}.
+ */
+ public static <K, V> MapBinder<K, V> newMapBinder(
+ Binder binder,
+ Class<K> keyType,
+ Class<V> valueType,
+ Class<? extends Annotation> annotationType) {
+ return newMapBinder(
+ binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType), annotationType);
+ }
+
+ private final RealMapBinder<K, V> delegate;
+
+ private MapBinder(RealMapBinder<K, V> delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * Configures the {@code MapBinder} to handle duplicate entries.
+ *
+ * <p>When multiple equal keys are bound, the value that gets included in the map is arbitrary.
+ *
+ * <p>In addition to the {@code Map<K, V>} and {@code Map<K, Provider<V>>} maps that are normally
+ * bound, a {@code Map<K, Set<V>>} and {@code Map<K, Set<Provider<V>>>} are <em>also</em> bound,
+ * which contain all values bound to each key.
+ *
+ * <p>When multiple modules contribute elements to the map, this configuration option impacts all
+ * of them.
+ *
+ * @return this map binder
+ * @since 3.0
+ */
+ public MapBinder<K, V> permitDuplicates() {
+ delegate.permitDuplicates();
+ return this;
+ }
+
+ /**
+ * Returns a binding builder used to add a new entry in the map. Each key must be distinct (and
+ * non-null). Bound providers will be evaluated each time the map is injected.
+ *
+ * <p>It is an error to call this method without also calling one of the {@code to} methods on the
+ * returned binding builder.
+ *
+ * <p>Scoping elements independently is supported. Use the {@code in} method to specify a binding
+ * scope.
+ */
+ public LinkedBindingBuilder<V> addBinding(K key) {
+ return delegate.addBinding(key);
+ }
+
+ // Some tests rely on MapBinder implementing equals/hashCode
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof MapBinder) {
+ return delegate.equals(((MapBinder<?, ?>) obj).delegate);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+}
diff --git a/core/src/com/google/inject/multibindings/MapBinderBinding.java b/core/src/com/google/inject/multibindings/MapBinderBinding.java
new file mode 100644
index 00000000..b45806f5
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/MapBinderBinding.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2010 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.multibindings;
+
+import com.google.inject.Binding;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+import com.google.inject.spi.Element;
+import com.google.inject.spi.Elements;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * A binding for a MapBinder.
+ *
+ * <p>Although MapBinders may be injected through a variety of generic types (Map&lt;K, V>, Map
+ * &lt;K, Provider&lt;V>>, Map&lt;K, Set&lt;V>>, Map<K, Set&lt; Provider&lt;V>>, and even
+ * Set&lt;Map.Entry&lt;K, Provider&lt;V>>), a MapBinderBinding exists only on the Binding associated
+ * with the Map&lt;K, V> key. Other bindings can be validated to be derived from this
+ * MapBinderBinding using {@link #containsElement(Element)}.
+ *
+ * @param <T> The fully qualified type of the map, including Map. For example: <code>
+ * MapBinderBinding&lt;Map&lt;String, Snack>></code>
+ * @since 3.0
+ * @author sameb@google.com (Sam Berlin)
+ */
+public interface MapBinderBinding<T> {
+
+ /** Returns the {@link Key} for the map. */
+ Key<T> getMapKey();
+
+ /**
+ * Returns the TypeLiteral describing the keys of the map.
+ *
+ * <p>The TypeLiteral will always match the type Map's generic type. For example, if getMapKey
+ * returns a key of <code>Map&lt;String, Snack></code>, then this will always return a <code>
+ * TypeLiteral&lt;String></code>.
+ */
+ TypeLiteral<?> getKeyTypeLiteral();
+
+ /**
+ * Returns the TypeLiteral describing the values of the map.
+ *
+ * <p>The TypeLiteral will always match the type Map's generic type. For example, if getMapKey
+ * returns a key of <code>Map&lt;String, Snack></code>, then this will always return a <code>
+ * TypeLiteral&lt;Snack></code>.
+ */
+ TypeLiteral<?> getValueTypeLiteral();
+
+ /**
+ * Returns all entries in the Map. The returned list of Map.Entries contains the key and a binding
+ * to the value. Duplicate keys or values will exist as separate Map.Entries in the returned list.
+ * This is only supported on bindings returned from an injector. This will throw {@link
+ * UnsupportedOperationException} if it is called on an element retrieved from {@link
+ * Elements#getElements}.
+ *
+ * <p>The elements will always match the type Map's generic type. For example, if getMapKey
+ * returns a key of <code>Map&lt;String, Snack></code>, then this will always return a list of
+ * type <code>List&lt;Map.Entry&lt;String, Binding&lt;Snack>>></code>.
+ */
+ List<Map.Entry<?, Binding<?>>> getEntries();
+
+ /**
+ * Similar to {@link #getEntries()}, but can be used on a MapBinderBinding retrieved from {@link
+ * Elements#getElements}.
+ *
+ * <p>One way to use this is to pass in the results of {@link Elements#getElements} as the {@code
+ * elements} parameter.
+ *
+ * <p>This differs from {@link #getEntries()} in that it will return duplicates if they are
+ * present in the {@code elements} passed in. This does not run the normal Guice de-duplication
+ * that {@link #getEntries()} does.
+ *
+ * @throws IllegalArgumentException if the provided elements contain partial map entries. If the
+ * elements come from {@link Elements#getElements} on a module with a MapBinder, there will be
+ * a 1:1 relationship and no exception will be thrown.
+ * @since 4.2
+ */
+ List<Map.Entry<?, Binding<?>>> getEntries(Iterable<? extends Element> elements);
+
+ /**
+ * Returns true if the MapBinder permits duplicates. This is only supported on bindings returned
+ * from an injector. This will throw {@link UnsupportedOperationException} if it is called on a
+ * MapBinderBinding retrieved from {@link Elements#getElements}.
+ */
+ boolean permitsDuplicates();
+
+ /**
+ * Returns true if this MapBinder contains the given Element in order to build the map or uses the
+ * given Element in order to support building and injecting the map. This will work for
+ * MapBinderBindings retrieved from an injector and {@link Elements#getElements}. Usually this is
+ * only necessary if you are working with elements retrieved from modules (without an Injector),
+ * otherwise {@link #getEntries} and {@link #permitsDuplicates} are better options.
+ *
+ * <p>If you need to introspect the details of the map, such as the keys, values or if it permits
+ * duplicates, it is necessary to pass the elements through an Injector and use {@link
+ * #getEntries()} and {@link #permitsDuplicates()}.
+ */
+ boolean containsElement(Element element);
+}
diff --git a/core/src/com/google/inject/multibindings/MapKey.java b/core/src/com/google/inject/multibindings/MapKey.java
new file mode 100644
index 00000000..3f8af89d
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/MapKey.java
@@ -0,0 +1,60 @@
+/*
+ * 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.multibindings;
+
+import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Allows users define customized key type annotations for map bindings by annotating an annotation
+ * of a {@code Map}'s key type. The custom key annotation can be applied to methods also annotated
+ * with {@literal @}{@link ProvidesIntoMap}.
+ *
+ * <p>A {@link StringMapKey} and {@link ClassMapKey} are provided for convenience with maps whose
+ * keys are strings or classes. For maps with enums or primitive types as keys, you must provide
+ * your own MapKey annotation, such as this one for an enum:
+ *
+ * <pre>
+ * {@literal @}MapKey(unwrapValue = true)
+ * {@literal @}Retention(RUNTIME)
+ * public {@literal @}interface MyCustomEnumKey {
+ * MyCustomEnum value();
+ * }
+ * </pre>
+ *
+ * You can also use the whole annotation as the key, if {@code unwrapValue=false}. When unwrapValue
+ * is false, the annotation type will be the key type for the injected map and the annotation
+ * instances will be the key values. If {@code unwrapValue=true}, the value() type will be the key
+ * type for injected map and the value() instances will be the keys values.
+ *
+ * @since 4.0
+ */
+@Documented
+@Target(ANNOTATION_TYPE)
+@Retention(RUNTIME)
+public @interface MapKey {
+ /**
+ * if {@code unwrapValue} is false, then the whole annotation will be the type and annotation
+ * instances will be the keys. If {@code unwrapValue} is true, the value() type of key type
+ * annotation will be the key type for injected map and the value instances will be the keys.
+ */
+ boolean unwrapValue() default true;
+}
diff --git a/core/src/com/google/inject/multibindings/Multibinder.java b/core/src/com/google/inject/multibindings/Multibinder.java
new file mode 100644
index 00000000..058fffe9
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/Multibinder.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2008 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.multibindings;
+
+import static com.google.inject.internal.RealMultibinder.newRealSetBinder;
+
+import com.google.inject.Binder;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+import com.google.inject.binder.LinkedBindingBuilder;
+import com.google.inject.internal.RealMultibinder;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * An API to bind multiple values separately, only to later inject them as a complete collection.
+ * Multibinder is intended for use in your application's module:
+ *
+ * <pre><code>
+ * public class SnacksModule extends AbstractModule {
+ * protected void configure() {
+ * Multibinder&lt;Snack&gt; multibinder
+ * = Multibinder.newSetBinder(binder(), Snack.class);
+ * multibinder.addBinding().toInstance(new Twix());
+ * multibinder.addBinding().toProvider(SnickersProvider.class);
+ * multibinder.addBinding().to(Skittles.class);
+ * }
+ * }</code></pre>
+ *
+ * <p>With this binding, a {@link Set}{@code <Snack>} can now be injected:
+ *
+ * <pre><code>
+ * class SnackMachine {
+ * {@literal @}Inject
+ * public SnackMachine(Set&lt;Snack&gt; snacks) { ... }
+ * }</code></pre>
+ *
+ * If desired, {@link Collection}{@code <Provider<Snack>>} can also be injected.
+ *
+ * <p>Contributing multibindings from different modules is supported. For example, it is okay for
+ * both {@code CandyModule} and {@code ChipsModule} to create their own {@code Multibinder<Snack>},
+ * and to each contribute bindings to the set of snacks. When that set is injected, it will contain
+ * elements from both modules.
+ *
+ * <p>The set's iteration order is consistent with the binding order. This is convenient when
+ * multiple elements are contributed by the same module because that module can order its bindings
+ * appropriately. Avoid relying on the iteration order of elements contributed by different modules,
+ * since there is no equivalent mechanism to order modules.
+ *
+ * <p>The set is unmodifiable. Elements can only be added to the set by configuring the multibinder.
+ * Elements can never be removed from the set.
+ *
+ * <p>Elements are resolved at set injection time. If an element is bound to a provider, that
+ * provider's get method will be called each time the set is injected (unless the binding is also
+ * scoped).
+ *
+ * <p>Annotations are be used to create different sets of the same element type. Each distinct
+ * annotation gets its own independent collection of elements.
+ *
+ * <p><strong>Elements must be distinct.</strong> If multiple bound elements have the same value,
+ * set injection will fail.
+ *
+ * <p><strong>Elements must be non-null.</strong> If any set element is null, set injection will
+ * fail.
+ *
+ * @author jessewilson@google.com (Jesse Wilson)
+ */
+public class Multibinder<T> {
+ // This class is non-final due to users mocking this in tests :(
+
+ /**
+ * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is
+ * itself bound with no binding annotation.
+ */
+ public static <T> Multibinder<T> newSetBinder(Binder binder, TypeLiteral<T> type) {
+ return newSetBinder(binder, Key.get(type));
+ }
+
+ /**
+ * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is
+ * itself bound with no binding annotation.
+ */
+ public static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type) {
+ return newSetBinder(binder, Key.get(type));
+ }
+
+ /**
+ * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is
+ * itself bound with {@code annotation}.
+ */
+ public static <T> Multibinder<T> newSetBinder(
+ Binder binder, TypeLiteral<T> type, Annotation annotation) {
+ return newSetBinder(binder, Key.get(type, annotation));
+ }
+
+ /**
+ * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is
+ * itself bound with {@code annotation}.
+ */
+ public static <T> Multibinder<T> newSetBinder(
+ Binder binder, Class<T> type, Annotation annotation) {
+ return newSetBinder(binder, Key.get(type, annotation));
+ }
+
+ /**
+ * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is
+ * itself bound with {@code annotationType}.
+ */
+ public static <T> Multibinder<T> newSetBinder(
+ Binder binder, TypeLiteral<T> type, Class<? extends Annotation> annotationType) {
+ return newSetBinder(binder, Key.get(type, annotationType));
+ }
+
+ /**
+ * Returns a new multibinder that collects instances of the key's type in a {@link Set} that is
+ * itself bound with the annotation (if any) of the key.
+ *
+ * @since 4.0
+ */
+ public static <T> Multibinder<T> newSetBinder(Binder binder, Key<T> key) {
+ return new Multibinder<T>(newRealSetBinder(binder.skipSources(Multibinder.class), key));
+ }
+
+ /**
+ * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is
+ * itself bound with {@code annotationType}.
+ */
+ public static <T> Multibinder<T> newSetBinder(
+ Binder binder, Class<T> type, Class<? extends Annotation> annotationType) {
+ return newSetBinder(binder, Key.get(type, annotationType));
+ }
+
+ private final RealMultibinder<T> delegate;
+
+ private Multibinder(RealMultibinder<T> delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * Configures the bound set to silently discard duplicate elements. When multiple equal values are
+ * bound, the one that gets included is arbitrary. When multiple modules contribute elements to
+ * the set, this configuration option impacts all of them.
+ *
+ * @return this multibinder
+ * @since 3.0
+ */
+ public Multibinder<T> permitDuplicates() {
+ delegate.permitDuplicates();
+ return this;
+ }
+
+ /**
+ * Returns a binding builder used to add a new element in the set. Each bound element must have a
+ * distinct value. Bound providers will be evaluated each time the set is injected.
+ *
+ * <p>It is an error to call this method without also calling one of the {@code to} methods on the
+ * returned binding builder.
+ *
+ * <p>Scoping elements independently is supported. Use the {@code in} method to specify a binding
+ * scope.
+ */
+ public LinkedBindingBuilder<T> addBinding() {
+ return delegate.addBinding();
+ }
+
+ // Some tests rely on Multibinder implementing equals/hashCode
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof Multibinder) {
+ return delegate.equals(((Multibinder<?>) obj).delegate);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+}
diff --git a/core/src/com/google/inject/multibindings/MultibinderBinding.java b/core/src/com/google/inject/multibindings/MultibinderBinding.java
new file mode 100644
index 00000000..43db6a23
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/MultibinderBinding.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010 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.multibindings;
+
+import com.google.inject.Binding;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+import com.google.inject.spi.Element;
+import com.google.inject.spi.Elements;
+import java.util.List;
+
+/**
+ * A binding for a Multibinder.
+ *
+ * @param <T> The fully qualified type of the set, including Set. For example: <code>
+ * MultibinderBinding&lt;Set&lt;Boolean>></code>
+ * @since 3.0
+ * @author sameb@google.com (Sam Berlin)
+ */
+public interface MultibinderBinding<T> {
+
+ /** Returns the key for the set. */
+ Key<T> getSetKey();
+
+ /**
+ * Returns the TypeLiteral that describes the type of elements in the set.
+ *
+ * <p>The elements will always match the type Set's generic type. For example, if getSetKey
+ * returns a key of <code>Set&lt;String></code>, then this will always return a <code>
+ * TypeLiteral&lt;String></code>.
+ */
+ TypeLiteral<?> getElementTypeLiteral();
+
+ /**
+ * Returns all bindings that make up the set. This is only supported on bindings returned from an
+ * injector. This will throw {@link UnsupportedOperationException} if it is called on an element
+ * retrieved from {@link Elements#getElements}.
+ *
+ * <p>The elements will always match the type Set's generic type. For example, if getSetKey
+ * returns a key of <code>Set&lt;String></code>, then this will always return a list of type
+ * <code>List&lt;Binding&lt;String>></code>.
+ */
+ List<Binding<?>> getElements();
+
+ /**
+ * Returns true if the multibinder permits duplicates. This is only supported on bindings returned
+ * from an injector. This will throw {@link UnsupportedOperationException} if it is called on a
+ * MultibinderBinding retrieved from {@link Elements#getElements}.
+ */
+ boolean permitsDuplicates();
+
+ /**
+ * Returns true if this Multibinder uses the given Element. This will be true for bindings that
+ * derive the elements of the set and other bindings that Multibinder uses internally. This will
+ * work for MultibinderBindings retrieved from an injector and {@link Elements#getElements}.
+ * Usually this is only necessary if you are working with elements retrieved from modules (without
+ * an Injector), otherwise {@link #getElements} and {@link #permitsDuplicates} are better options.
+ *
+ * <p>If you need to introspect the details of the set, such as the values or if it permits
+ * duplicates, it is necessary to pass the elements through an Injector and use {@link
+ * #getElements()} and {@link #permitsDuplicates()}.
+ */
+ boolean containsElement(Element element);
+}
diff --git a/core/src/com/google/inject/multibindings/MultibindingsScanner.java b/core/src/com/google/inject/multibindings/MultibindingsScanner.java
new file mode 100644
index 00000000..3ede7c5e
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/MultibindingsScanner.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.multibindings;
+
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.Binder;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.spi.InjectionPoint;
+import com.google.inject.spi.ModuleAnnotatedMethodScanner;
+import com.google.inject.util.Modules;
+import java.lang.annotation.Annotation;
+import java.util.Set;
+
+/**
+ * Scans a module for annotations that signal multibindings, mapbindings, and optional bindings.
+ *
+ * @since 4.0
+ * @deprecated This functionality is installed by default. All references to this can be safely
+ * removed. This class will be removed in Guice 4.4
+ */
+@Deprecated
+public class MultibindingsScanner {
+ private MultibindingsScanner() {}
+
+ /**
+ * Returns a module that, when installed, will scan all modules for methods with the annotations
+ * {@literal @}{@link ProvidesIntoMap}, {@literal @}{@link ProvidesIntoSet}, and
+ * {@literal @}{@link ProvidesIntoOptional}.
+ *
+ * <p>This is a convenience method, equivalent to doing {@code
+ * binder().scanModulesForAnnotatedMethods(MultibindingsScanner.scanner())}.
+ *
+ * @deprecated This functionality is now installed by default. All references/installations can be
+ * eliminated.
+ */
+ @Deprecated
+ public static Module asModule() {
+ return Modules.EMPTY_MODULE;
+ }
+
+ /**
+ * @deprecated This method returns an empty scanner since the preexisting functionality is
+ * installed by default.
+ */
+ @Deprecated
+ public static ModuleAnnotatedMethodScanner scanner() {
+ return new ModuleAnnotatedMethodScanner() {
+ @Override
+ public Set<? extends Class<? extends Annotation>> annotationClasses() {
+ return ImmutableSet.of();
+ }
+
+ @Override
+ public <T> Key<T> prepareMethod(
+ Binder binder, Annotation annotation, Key<T> key, InjectionPoint injectionPoint) {
+ throw new IllegalStateException("Unexpected annotation: " + annotation);
+ }
+ };
+ }
+}
diff --git a/core/src/com/google/inject/multibindings/MultibindingsTargetVisitor.java b/core/src/com/google/inject/multibindings/MultibindingsTargetVisitor.java
new file mode 100644
index 00000000..b6a2eb31
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/MultibindingsTargetVisitor.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 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.multibindings;
+
+import com.google.inject.spi.BindingTargetVisitor;
+
+/**
+ * A visitor for the multibinder extension.
+ *
+ * <p>If your {@link BindingTargetVisitor} implements this interface, bindings created by using
+ * {@link Multibinder}, {@link MapBinder} or {@link OptionalBinderBinding} will be visited through
+ * this interface.
+ *
+ * @since 3.0
+ * @author sameb@google.com (Sam Berlin)
+ */
+public interface MultibindingsTargetVisitor<T, V> extends BindingTargetVisitor<T, V> {
+
+ /** Visits a binding created through {@link Multibinder}. */
+ V visit(MultibinderBinding<? extends T> multibinding);
+
+ /** Visits a binding created through {@link MapBinder}. */
+ V visit(MapBinderBinding<? extends T> mapbinding);
+
+ /**
+ * Visits a binding created through {@link OptionalBinder}.
+ *
+ * @since 4.0
+ */
+ V visit(OptionalBinderBinding<? extends T> optionalbinding);
+}
diff --git a/core/src/com/google/inject/multibindings/OptionalBinder.java b/core/src/com/google/inject/multibindings/OptionalBinder.java
new file mode 100644
index 00000000..0e015c5d
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/OptionalBinder.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2014 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.multibindings;
+
+import static com.google.inject.internal.RealOptionalBinder.newRealOptionalBinder;
+
+import com.google.common.base.Optional;
+import com.google.inject.Binder;
+import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
+import com.google.inject.binder.LinkedBindingBuilder;
+import com.google.inject.internal.RealOptionalBinder;
+
+/**
+ * An API to bind optional values, optionally with a default value. OptionalBinder fulfills two
+ * roles:
+ *
+ * <ol>
+ * <li>It allows a framework to define an injection point that may or may not be bound by users.
+ * <li>It allows a framework to supply a default value that can be changed by users.
+ * </ol>
+ *
+ * <p>When an OptionalBinder is added, it will always supply the bindings: {@code Optional<T>} and
+ * {@code Optional<Provider<T>>}. If {@link #setBinding} or {@link #setDefault} are called, it will
+ * also bind {@code T}.
+ *
+ * <p>{@code setDefault} is intended for use by frameworks that need a default value. User code can
+ * call {@code setBinding} to override the default. <b>Warning: Even if setBinding is called, the
+ * default binding will still exist in the object graph. If it is a singleton, it will be
+ * 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.
+ *
+ * <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
+ * user-supplied binding of that type exists, or if setBinding or setDefault are called, the
+ * optionals will return present if they are bound to a non-null value.
+ *
+ * <p>Values are resolved at injection time. If a value is bound to a provider, that provider's get
+ * method will be called each time the optional is injected (unless the binding is also scoped, or
+ * an optional of provider is injected).
+ *
+ * <p>Annotations are used to create different optionals of the same key/value type. Each distinct
+ * annotation gets its own independent binding.
+ *
+ * <pre><code>
+ * public class FrameworkModule extends AbstractModule {
+ * protected void configure() {
+ * OptionalBinder.newOptionalBinder(binder(), Renamer.class);
+ * }
+ * }</code></pre>
+ *
+ * <p>With this module, an {@link Optional}{@code <Renamer>} can now be injected. With no other
+ * bindings, the optional will be absent. Users can specify bindings in one of two ways:
+ *
+ * <p>Option 1:
+ *
+ * <pre><code>
+ * public class UserRenamerModule extends AbstractModule {
+ * protected void configure() {
+ * bind(Renamer.class).to(ReplacingRenamer.class);
+ * }
+ * }</code></pre>
+ *
+ * <p>or Option 2:
+ *
+ * <pre><code>
+ * public class UserRenamerModule extends AbstractModule {
+ * protected void configure() {
+ * OptionalBinder.newOptionalBinder(binder(), Renamer.class)
+ * .setBinding().to(ReplacingRenamer.class);
+ * }
+ * }</code></pre>
+ *
+ * With both options, the {@code Optional<Renamer>} will be present and supply the ReplacingRenamer.
+ *
+ * <p>Default values can be supplied using:
+ *
+ * <pre><code>
+ * public class FrameworkModule extends AbstractModule {
+ * protected void configure() {
+ * OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, LookupUrl.class))
+ * .setDefault().toInstance(DEFAULT_LOOKUP_URL);
+ * }
+ * }</code></pre>
+ *
+ * With the above module, code can inject an {@code @LookupUrl String} and it will supply the
+ * DEFAULT_LOOKUP_URL. A user can change this value by binding
+ *
+ * <pre><code>
+ * public class UserLookupModule extends AbstractModule {
+ * protected void configure() {
+ * OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, LookupUrl.class))
+ * .setBinding().toInstance(CUSTOM_LOOKUP_URL);
+ * }
+ * }</code></pre>
+ *
+ * ... which will override the default value.
+ *
+ * <p>If one module uses setDefault the only way to override the default is to use setBinding. It is
+ * an error for a user to specify the binding without using OptionalBinder if setDefault or
+ * setBinding are called. For example,
+ *
+ * <pre><code>
+ * public class FrameworkModule extends AbstractModule {
+ * protected void configure() {
+ * OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, LookupUrl.class))
+ * .setDefault().toInstance(DEFAULT_LOOKUP_URL);
+ * }
+ * }
+ * public class UserLookupModule extends AbstractModule {
+ * protected void configure() {
+ * bind(Key.get(String.class, LookupUrl.class)).toInstance(CUSTOM_LOOKUP_URL);
+ * }
+ * }</code></pre>
+ *
+ * ... would generate an error, because both the framework and the user are trying to bind
+ * {@code @LookupUrl String}.
+ *
+ * @author sameb@google.com (Sam Berlin)
+ * @since 4.0
+ */
+public class OptionalBinder<T> {
+ // This class is non-final due to users mocking this in tests :(
+
+ public static <T> OptionalBinder<T> newOptionalBinder(Binder binder, Class<T> type) {
+ return new OptionalBinder<T>(
+ newRealOptionalBinder(binder.skipSources(OptionalBinder.class), Key.get(type)));
+ }
+
+ public static <T> OptionalBinder<T> newOptionalBinder(Binder binder, TypeLiteral<T> type) {
+ return new OptionalBinder<T>(
+ newRealOptionalBinder(binder.skipSources(OptionalBinder.class), Key.get(type)));
+ }
+
+ public static <T> OptionalBinder<T> newOptionalBinder(Binder binder, Key<T> type) {
+ return new OptionalBinder<T>(
+ newRealOptionalBinder(binder.skipSources(OptionalBinder.class), type));
+ }
+
+ private final RealOptionalBinder<T> delegate;
+
+ private OptionalBinder(RealOptionalBinder<T> delegate) {
+ this.delegate = delegate;
+ }
+
+ /**
+ * Returns a binding builder used to set the default value that will be injected. The binding set
+ * by this method will be ignored if {@link #setBinding} is called.
+ *
+ * <p>It is an error to call this method without also calling one of the {@code to} methods on the
+ * returned binding builder.
+ */
+ public LinkedBindingBuilder<T> setDefault() {
+ return delegate.setDefault();
+ }
+
+ /**
+ * Returns a binding builder used to set the actual value that will be injected. This overrides
+ * any binding set by {@link #setDefault}.
+ *
+ * <p>It is an error to call this method without also calling one of the {@code to} methods on the
+ * returned binding builder.
+ */
+ public LinkedBindingBuilder<T> setBinding() {
+ return delegate.setBinding();
+ }
+
+ // Some tests depend on equals/hashCode behavior of OptionalBinder
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof OptionalBinder) {
+ return delegate.equals(((OptionalBinder<?>) obj).delegate);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return delegate.hashCode();
+ }
+}
diff --git a/core/src/com/google/inject/multibindings/OptionalBinderBinding.java b/core/src/com/google/inject/multibindings/OptionalBinderBinding.java
new file mode 100644
index 00000000..5fedc4b5
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/OptionalBinderBinding.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2014 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.multibindings;
+
+import com.google.inject.Binding;
+import com.google.inject.Key;
+import com.google.inject.spi.Element;
+import com.google.inject.spi.Elements;
+
+/**
+ * A binding for a OptionalBinder.
+ *
+ * <p>Although OptionalBinders may be injected through a variety of types {@code T}, {@code
+ * Optional<T>}, {@code Optional<Provider<T>>}, etc..), an OptionalBinderBinding exists only on the
+ * Binding associated with the {@code Optional<T>} key. Other bindings can be validated to be
+ * derived from this OptionalBinderBinding using {@link #containsElement}.
+ *
+ * @param <T> The fully qualified type of the optional binding, including Optional. For example:
+ * {@code Optional<String>}.
+ * @since 4.0
+ * @author sameb@google.com (Sam Berlin)
+ */
+public interface OptionalBinderBinding<T> {
+
+ /** Returns the {@link Key} for this binding. */
+ Key<T> getKey();
+
+ /**
+ * Returns the default binding (set by {@link OptionalBinder#setDefault}) if one exists or null if
+ * no default binding is set. This will throw {@link UnsupportedOperationException} if it is
+ * called on an element retrieved from {@link Elements#getElements}.
+ *
+ * <p>The Binding's type will always match the type Optional's generic type. For example, if
+ * getKey returns a key of <code>Optional&lt;String></code>, then this will always return a <code>
+ * Binding&lt;String></code>.
+ */
+ Binding<?> getDefaultBinding();
+
+ /**
+ * Returns the actual binding (set by {@link OptionalBinder#setBinding}) or null if not set. This
+ * will throw {@link UnsupportedOperationException} if it is called on an element retrieved from
+ * {@link Elements#getElements}.
+ *
+ * <p>The Binding's type will always match the type Optional's generic type. For example, if
+ * getKey returns a key of <code>Optional&lt;String></code>, then this will always return a <code>
+ * Binding&lt;String></code>.
+ */
+ Binding<?> getActualBinding();
+
+ /**
+ * Returns true if this OptionalBinder contains the given Element in order to build the optional
+ * binding or uses the given Element in order to support building and injecting its data. This
+ * will work for OptionalBinderBinding retrieved from an injector and {@link
+ * Elements#getElements}. Usually this is only necessary if you are working with elements
+ * retrieved from modules (without an Injector), otherwise {@link #getDefaultBinding} and {@link
+ * #getActualBinding} are better options.
+ */
+ boolean containsElement(Element element);
+}
diff --git a/core/src/com/google/inject/multibindings/ProvidesIntoMap.java b/core/src/com/google/inject/multibindings/ProvidesIntoMap.java
new file mode 100644
index 00000000..9ab0dd93
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/ProvidesIntoMap.java
@@ -0,0 +1,57 @@
+/*
+ * 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.multibindings;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.inject.Module;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates methods of a {@link Module} to add items to a {@link MapBinder}. The method's return
+ * type, binding annotation and additional key annotation determines what Map this will contribute
+ * to. For example,
+ *
+ * <pre>
+ * {@literal @}ProvidesIntoMap
+ * {@literal @}StringMapKey("Foo")
+ * {@literal @}Named("urls")
+ * Plugin provideFooUrl(FooManager fm) { return fm.getPlugin(); }
+ *
+ * {@literal @}ProvidesIntoMap
+ * {@literal @}StringMapKey("Bar")
+ * {@literal @}Named("urls")
+ * 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.
+ *
+ * <p>Because the key is specified as an annotation, only Strings, Classes, enums, primitive types
+ * and annotation instances are supported as keys.
+ *
+ * @author sameb@google.com (Sam Berlin)
+ * @since 4.0
+ */
+@Documented
+@Target(METHOD)
+@Retention(RUNTIME)
+public @interface ProvidesIntoMap {}
diff --git a/core/src/com/google/inject/multibindings/ProvidesIntoOptional.java b/core/src/com/google/inject/multibindings/ProvidesIntoOptional.java
new file mode 100644
index 00000000..19799c80
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/ProvidesIntoOptional.java
@@ -0,0 +1,62 @@
+/*
+ * 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.multibindings;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.inject.Module;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates methods of a {@link Module} to add items to a {@link Multibinder}. The method's return
+ * type and binding annotation determines what Optional this will contribute to. For example,
+ *
+ * <pre>
+ * {@literal @}ProvidesIntoOptional(DEFAULT)
+ * {@literal @}Named("url")
+ * String provideFooUrl(FooManager fm) { returm fm.getUrl(); }
+ *
+ * {@literal @}ProvidesIntoOptional(ACTUAL)
+ * {@literal @}Named("url")
+ * String provideBarUrl(BarManager bm) { return bm.getUrl(); }
+ * </pre>
+ *
+ * will set the default value of {@code @Named("url") Optional<String>} to foo's URL, and then
+ * override it to bar's URL.
+ *
+ * @author sameb@google.com (Sam Berlin)
+ * @since 4.0
+ */
+@Documented
+@Target(METHOD)
+@Retention(RUNTIME)
+public @interface ProvidesIntoOptional {
+ /** @since 4.0 */
+ enum Type {
+ /** Corresponds to {@link OptionalBinder#setBinding}. */
+ ACTUAL,
+
+ /** Corresponds to {@link OptionalBinder#setDefault}. */
+ DEFAULT
+ }
+
+ /** Specifies if the binding is for the actual or default value. */
+ Type value();
+}
diff --git a/core/src/com/google/inject/multibindings/ProvidesIntoSet.java b/core/src/com/google/inject/multibindings/ProvidesIntoSet.java
new file mode 100644
index 00000000..a7618b6f
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/ProvidesIntoSet.java
@@ -0,0 +1,50 @@
+/*
+ * 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.multibindings;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.inject.Module;
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Annotates methods of a {@link Module} to add items to a {@link Multibinder}. The method's return
+ * type and binding annotation determines what Set this will contribute to. For example,
+ *
+ * <pre>
+ * {@literal @}ProvidesIntoSet
+ * {@literal @}Named("urls")
+ * String provideFooUrl(FooManager fm) { returm fm.getUrl(); }
+ *
+ * {@literal @}ProvidesIntoSet
+ * {@literal @}Named("urls")
+ * String provideBarUrl(BarManager bm) { return bm.getUrl(); }
+ * </pre>
+ *
+ * will add two items to the {@code @Named("urls") Set<String>} set. The items are bound as
+ * providers and will be evaluated at injection time.
+ *
+ * @author sameb@google.com (Sam Berlin)
+ * @since 4.0
+ */
+@Documented
+@Target(METHOD)
+@Retention(RUNTIME)
+public @interface ProvidesIntoSet {}
diff --git a/core/src/com/google/inject/multibindings/StringMapKey.java b/core/src/com/google/inject/multibindings/StringMapKey.java
new file mode 100644
index 00000000..7c6e041f
--- /dev/null
+++ b/core/src/com/google/inject/multibindings/StringMapKey.java
@@ -0,0 +1,37 @@
+/*
+ * 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.multibindings;
+
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Allows {@literal @}{@link ProvidesIntoMap} to specify a string map key.
+ *
+ * @since 4.0
+ */
+@MapKey(unwrapValue = true)
+@Documented
+@Target(METHOD)
+@Retention(RUNTIME)
+public @interface StringMapKey {
+ String value();
+}
diff --git a/core/src/com/google/inject/internal/ContextualCallable.java b/core/src/com/google/inject/multibindings/package-info.java
index 56c0630c..71517791 100644
--- a/core/src/com/google/inject/internal/ContextualCallable.java
+++ b/core/src/com/google/inject/multibindings/package-info.java
@@ -1,5 +1,5 @@
-/**
- * Copyright (C) 2006 Google Inc.
+/*
+ * Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,11 +14,8 @@
* limitations under the License.
*/
-package com.google.inject.internal;
-
/**
- * @author crazybob@google.com (Bob Lee)
+ * Extension for binding multiple instances in a collection; this extension requires {@code
+ * guice-multibindings.jar}.
*/
-interface ContextualCallable<T> {
- T call(InternalContext context) throws ErrorsException;
-}
+package com.google.inject.multibindings;
diff --git a/core/src/com/google/inject/name/Named.java b/core/src/com/google/inject/name/Named.java
index 23b3d5dc..b1d9a4e8 100644
--- a/core/src/com/google/inject/name/Named.java
+++ b/core/src/com/google/inject/name/Named.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,7 +19,6 @@ package com.google.inject.name;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.inject.BindingAnnotation;
-
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -30,7 +29,7 @@ import java.lang.annotation.Target;
* @author crazybob@google.com (Bob Lee)
*/
@Retention(RUNTIME)
-@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
+@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
@BindingAnnotation
public @interface Named {
String value();
diff --git a/core/src/com/google/inject/name/NamedImpl.java b/core/src/com/google/inject/name/NamedImpl.java
index 2fe01071..9c4d10e4 100644
--- a/core/src/com/google/inject/name/NamedImpl.java
+++ b/core/src/com/google/inject/name/NamedImpl.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,6 +18,7 @@ package com.google.inject.name;
import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.inject.internal.Annotations;
import java.io.Serializable;
import java.lang.annotation.Annotation;
@@ -29,15 +30,18 @@ class NamedImpl implements Named, Serializable {
this.value = checkNotNull(value, "name");
}
+ @Override
public String value() {
return this.value;
}
+ @Override
public int hashCode() {
// This is specified in java.lang.Annotation.
return (127 * "value".hashCode()) ^ value.hashCode();
}
+ @Override
public boolean equals(Object o) {
if (!(o instanceof Named)) {
return false;
@@ -47,10 +51,12 @@ class NamedImpl implements Named, Serializable {
return value.equals(other.value());
}
+ @Override
public String toString() {
- return "@" + Named.class.getName() + "(value=" + value + ")";
+ return "@" + Named.class.getName() + "(value=" + Annotations.memberValueString(value) + ")";
}
+ @Override
public Class<? extends Annotation> annotationType() {
return Named.class;
}
diff --git a/core/src/com/google/inject/name/Names.java b/core/src/com/google/inject/name/Names.java
index f7ec971a..619de81e 100644
--- a/core/src/com/google/inject/name/Names.java
+++ b/core/src/com/google/inject/name/Names.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,6 @@ package com.google.inject.name;
import com.google.inject.Binder;
import com.google.inject.Key;
-
import java.util.Enumeration;
import java.util.Map;
import java.util.Properties;
@@ -32,17 +31,12 @@ public class Names {
private Names() {}
- /**
- * Creates a {@link Named} annotation with {@code name} as the value.
- */
+ /** Creates a {@link Named} annotation with {@code name} as the value. */
public static Named named(String name) {
return new NamedImpl(name);
}
- /**
- * Creates a constant binding to {@code @Named(key)} for each entry in
- * {@code properties}.
- */
+ /** Creates a constant binding to {@code @Named(key)} for each entry in {@code properties}. */
public static void bindProperties(Binder binder, Map<String, String> properties) {
binder = binder.skipSources(Names.class);
for (Map.Entry<String, String> entry : properties.entrySet()) {
@@ -53,9 +47,8 @@ public class Names {
}
/**
- * Creates a constant binding to {@code @Named(key)} for each property. This
- * method binds all properties including those inherited from
- * {@link Properties#defaults defaults}.
+ * Creates a constant binding to {@code @Named(key)} for each property. This method binds all
+ * properties including those inherited from {@link Properties#defaults defaults}.
*/
public static void bindProperties(Binder binder, Properties properties) {
binder = binder.skipSources(Names.class);
diff --git a/core/src/com/google/inject/name/package-info.java b/core/src/com/google/inject/name/package-info.java
index d6bf05da..8d4482d1 100644
--- a/core/src/com/google/inject/name/package-info.java
+++ b/core/src/com/google/inject/name/package-info.java
@@ -14,7 +14,5 @@
* limitations under the License.
*/
-/**
- * Support for binding to string-based names.
- */
-package com.google.inject.name; \ No newline at end of file
+/** Support for binding to string-based names. */
+package com.google.inject.name;
diff --git a/core/src/com/google/inject/package-info.java b/core/src/com/google/inject/package-info.java
index 626bde2b..12b3b1eb 100644
--- a/core/src/com/google/inject/package-info.java
+++ b/core/src/com/google/inject/package-info.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,33 +15,25 @@
*/
/**
- * <i>Google Guice</i> (pronounced "juice") is an ultra-lightweight dependency
- * injection framework. Please refer to the Guice
- * <a href="http://docs.google.com/Doc?id=dd2fhx4z_5df5hw8">User's Guide</a>
- * for a gentle introduction.
+ * <i>Google Guice</i> (pronounced "juice") is an ultra-lightweight dependency injection framework.
+ * Please refer to the Guice <a href="http://docs.google.com/Doc?id=dd2fhx4z_5df5hw8">User's
+ * Guide</a> for a gentle introduction.
*
* <p>The principal public APIs in this package are:
*
* <dl>
* <dt>{@link com.google.inject.Inject}
- * <dd>The annotation you will use in your implementation classes to tell Guice
- * where and how it should send in ("inject") the objects you depend on
- * (your "dependencies").
- *
+ * <dd>The annotation you will use in your implementation classes to tell Guice where and how it
+ * should send in ("inject") the objects you depend on (your "dependencies").
* <dt>{@link com.google.inject.Module}
- * <dd>The interface you will implement in order to specify "bindings" --
- * instructions for how Guice should handle injection -- for a particular
- * set of interfaces.
- *
+ * <dd>The interface you will implement in order to specify "bindings" -- instructions for how Guice
+ * should handle injection -- for a particular set of interfaces.
* <dt>{@link com.google.inject.Binder}
- * <dd>The object that Guice passes into your {@link com.google.inject.Module}
- * to collect these bindings.
- *
+ * <dd>The object that Guice passes into your {@link com.google.inject.Module} to collect these
+ * bindings.
* <dt>{@link com.google.inject.Provider}
- * <dd>The interface you will implement when you need to customize exactly how
- * Guice creates instances for a particular binding.
- *
+ * <dd>The interface you will implement when you need to customize exactly how Guice creates
+ * instances for a particular binding.
* </dl>
- *
*/
-package com.google.inject; \ No newline at end of file
+package com.google.inject;
diff --git a/core/src/com/google/inject/spi/BindingScopingVisitor.java b/core/src/com/google/inject/spi/BindingScopingVisitor.java
index 2abfc9eb..41bd0699 100644
--- a/core/src/com/google/inject/spi/BindingScopingVisitor.java
+++ b/core/src/com/google/inject/spi/BindingScopingVisitor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,14 +17,13 @@
package com.google.inject.spi;
import com.google.inject.Scope;
-
import java.lang.annotation.Annotation;
/**
* Visits each of the strategies used to scope an injection.
*
- * @param <V> any type to be returned by the visit method. Use {@link Void} with
- * {@code return null} if no return type is needed.
+ * @param <V> any type to be returned by the visit method. Use {@link Void} with {@code return null}
+ * if no return type is needed.
* @since 2.0
*/
public interface BindingScopingVisitor<V> {
@@ -35,9 +34,7 @@ public interface BindingScopingVisitor<V> {
*/
V visitEagerSingleton();
- /**
- * Visit a scope instance. This scope strategy is found on both module and injector bindings.
- */
+ /** Visit a scope instance. This scope strategy is found on both module and injector bindings. */
V visitScope(Scope scope);
/**
@@ -49,9 +46,9 @@ public interface BindingScopingVisitor<V> {
/**
* Visit an unspecified or unscoped strategy. On a module, this strategy indicates that the
- * injector should use scoping annotations to find a scope. On an injector, it indicates that
- * no scope is applied to the binding. An unscoped binding will behave like a scoped one when it
- * is linked to a scoped binding.
+ * injector should use scoping annotations to find a scope. On an injector, it indicates that no
+ * scope is applied to the binding. An unscoped binding will behave like a scoped one when it is
+ * linked to a scoped binding.
*/
V visitNoScoping();
}
diff --git a/core/src/com/google/inject/spi/BindingTargetVisitor.java b/core/src/com/google/inject/spi/BindingTargetVisitor.java
index 7137d743..890aebac 100644
--- a/core/src/com/google/inject/spi/BindingTargetVisitor.java
+++ b/core/src/com/google/inject/spi/BindingTargetVisitor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,8 +19,8 @@ package com.google.inject.spi;
/**
* Visits each of the strategies used to find an instance to satisfy an injection.
*
- * @param <V> any type to be returned by the visit method. Use {@link Void} with
- * {@code return null} if no return type is needed.
+ * @param <V> any type to be returned by the visit method. Use {@link Void} with {@code return null}
+ * if no return type is needed.
* @since 2.0
*/
public interface BindingTargetVisitor<T, V> {
@@ -45,8 +45,8 @@ public interface BindingTargetVisitor<T, V> {
V visit(ProviderKeyBinding<? extends T> binding);
/**
- * Visit a linked key binding. The other key's binding is used to resolve injections. This
- * target is found in both module and injector bindings.
+ * Visit a linked key binding. The other key's binding is used to resolve injections. This target
+ * is found in both module and injector bindings.
*/
V visit(LinkedKeyBinding<? extends T> binding);
@@ -57,8 +57,8 @@ public interface BindingTargetVisitor<T, V> {
V visit(ExposedBinding<? extends T> binding);
/**
- * Visit an untargetted binding. This target is found only on module bindings. It indicates
- * that the injector should use its implicit binding strategies to resolve injections.
+ * Visit an untargetted binding. This target is found only on module bindings. It indicates that
+ * the injector should use its implicit binding strategies to resolve injections.
*/
V visit(UntargettedBinding<? extends T> binding);
@@ -69,8 +69,8 @@ public interface BindingTargetVisitor<T, V> {
V visit(ConstructorBinding<? extends T> binding);
/**
- * Visit a binding created from converting a bound instance to a new type. The source binding
- * has the same binding annotation but a different type. This target is found only on injector
+ * Visit a binding created from converting a bound instance to a new type. The source binding has
+ * the same binding annotation but a different type. This target is found only on injector
* bindings.
*/
V visit(ConvertedConstantBinding<? extends T> binding);
diff --git a/core/src/com/google/inject/spi/ConstructorBinding.java b/core/src/com/google/inject/spi/ConstructorBinding.java
index 6799941d..4e6e5f59 100644
--- a/core/src/com/google/inject/spi/ConstructorBinding.java
+++ b/core/src/com/google/inject/spi/ConstructorBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,6 @@
package com.google.inject.spi;
import com.google.inject.Binding;
-
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
@@ -32,17 +31,15 @@ import java.util.Set;
*/
public interface ConstructorBinding<T> extends Binding<T>, HasDependencies {
- /**
- * Gets the constructor this binding injects.
- */
+ /** Gets the constructor this binding injects. */
InjectionPoint getConstructor();
/**
* Returns all instance method and field injection points on {@code type}.
*
* @return a possibly empty set of injection points. The set has a specified iteration order. All
- * fields are returned and then all methods. Within the fields, supertype fields are returned
- * before subtype fields. Similarly, supertype methods are returned before subtype methods.
+ * fields are returned and then all methods. Within the fields, supertype fields are returned
+ * before subtype fields. Similarly, supertype methods are returned before subtype methods.
*/
Set<InjectionPoint> getInjectableMembers();
@@ -54,4 +51,4 @@ public interface ConstructorBinding<T> extends Binding<T>, HasDependencies {
*/
Map<Method, List<org.aopalliance.intercept.MethodInterceptor>> getMethodInterceptors();
/*end[AOP]*/
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/spi/ConvertedConstantBinding.java b/core/src/com/google/inject/spi/ConvertedConstantBinding.java
index 5582fb6a..ebafdf60 100644
--- a/core/src/com/google/inject/spi/ConvertedConstantBinding.java
+++ b/core/src/com/google/inject/spi/ConvertedConstantBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,6 @@ package com.google.inject.spi;
import com.google.inject.Binding;
import com.google.inject.Key;
-
import java.util.Set;
/**
@@ -30,14 +29,12 @@ import java.util.Set;
*/
public interface ConvertedConstantBinding<T> extends Binding<T>, HasDependencies {
- /**
- * Returns the converted value.
- */
+ /** Returns the converted value. */
T getValue();
/**
* Returns the type converter binding used to convert the constant.
- *
+ *
* @since 3.0
*/
TypeConverterBinding getTypeConverterBinding();
@@ -48,8 +45,7 @@ public interface ConvertedConstantBinding<T> extends Binding<T>, HasDependencies
*/
Key<String> getSourceKey();
- /**
- * Returns a singleton set containing only the converted key.
- */
+ /** Returns a singleton set containing only the converted key. */
+ @Override
Set<Dependency<?>> getDependencies();
}
diff --git a/core/src/com/google/inject/spi/DefaultBindingScopingVisitor.java b/core/src/com/google/inject/spi/DefaultBindingScopingVisitor.java
index b5172720..edaa6603 100644
--- a/core/src/com/google/inject/spi/DefaultBindingScopingVisitor.java
+++ b/core/src/com/google/inject/spi/DefaultBindingScopingVisitor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,40 +17,40 @@
package com.google.inject.spi;
import com.google.inject.Scope;
-
import java.lang.annotation.Annotation;
/**
- * No-op visitor for subclassing. All interface methods simply delegate to
- * {@link #visitOther()}, returning its result.
+ * No-op visitor for subclassing. All interface methods simply delegate to {@link #visitOther()},
+ * returning its result.
*
- * @param <V> any type to be returned by the visit method. Use {@link Void} with
- * {@code return null} if no return type is needed.
- *
+ * @param <V> any type to be returned by the visit method. Use {@link Void} with {@code return null}
+ * if no return type is needed.
* @author jessewilson@google.com (Jesse Wilson)
* @since 2.0
*/
public class DefaultBindingScopingVisitor<V> implements BindingScopingVisitor<V> {
- /**
- * Default visit implementation. Returns {@code null}.
- */
+ /** Default visit implementation. Returns {@code null}. */
protected V visitOther() {
return null;
}
+ @Override
public V visitEagerSingleton() {
return visitOther();
}
+ @Override
public V visitScope(Scope scope) {
return visitOther();
}
+ @Override
public V visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
return visitOther();
}
+ @Override
public V visitNoScoping() {
return visitOther();
}
diff --git a/core/src/com/google/inject/spi/DefaultBindingTargetVisitor.java b/core/src/com/google/inject/spi/DefaultBindingTargetVisitor.java
index 3deb9dd9..5bd10661 100644
--- a/core/src/com/google/inject/spi/DefaultBindingTargetVisitor.java
+++ b/core/src/com/google/inject/spi/DefaultBindingTargetVisitor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -22,53 +22,59 @@ import com.google.inject.Binding;
* No-op visitor for subclassing. All interface methods simply delegate to {@link
* #visitOther(Binding)}, returning its result.
*
- * @param <V> any type to be returned by the visit method. Use {@link Void} with
- * {@code return null} if no return type is needed.
- *
+ * @param <V> any type to be returned by the visit method. Use {@link Void} with {@code return null}
+ * if no return type is needed.
* @author jessewilson@google.com (Jesse Wilson)
* @since 2.0
*/
public abstract class DefaultBindingTargetVisitor<T, V> implements BindingTargetVisitor<T, V> {
- /**
- * Default visit implementation. Returns {@code null}.
- */
+ /** Default visit implementation. Returns {@code null}. */
protected V visitOther(Binding<? extends T> binding) {
return null;
}
+ @Override
public V visit(InstanceBinding<? extends T> instanceBinding) {
return visitOther(instanceBinding);
}
+ @Override
public V visit(ProviderInstanceBinding<? extends T> providerInstanceBinding) {
return visitOther(providerInstanceBinding);
}
+ @Override
public V visit(ProviderKeyBinding<? extends T> providerKeyBinding) {
return visitOther(providerKeyBinding);
}
+ @Override
public V visit(LinkedKeyBinding<? extends T> linkedKeyBinding) {
return visitOther(linkedKeyBinding);
}
+ @Override
public V visit(ExposedBinding<? extends T> exposedBinding) {
return visitOther(exposedBinding);
}
+ @Override
public V visit(UntargettedBinding<? extends T> untargettedBinding) {
return visitOther(untargettedBinding);
}
+ @Override
public V visit(ConstructorBinding<? extends T> constructorBinding) {
return visitOther(constructorBinding);
}
+ @Override
public V visit(ConvertedConstantBinding<? extends T> convertedConstantBinding) {
return visitOther(convertedConstantBinding);
}
+ @Override
@SuppressWarnings("unchecked")
public V visit(ProviderBinding<? extends T> providerBinding) {
// TODO(cushon): remove raw (Binding) cast when we don't care about javac 6 anymore
diff --git a/core/src/com/google/inject/spi/DefaultElementVisitor.java b/core/src/com/google/inject/spi/DefaultElementVisitor.java
index 1bbea0d2..1f1aacee 100644
--- a/core/src/com/google/inject/spi/DefaultElementVisitor.java
+++ b/core/src/com/google/inject/spi/DefaultElementVisitor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,90 +19,104 @@ package com.google.inject.spi;
import com.google.inject.Binding;
/**
- * No-op visitor for subclassing. All interface methods simply delegate to
- * {@link #visitOther(Element)}, returning its result.
- *
- * @param <V> any type to be returned by the visit method. Use {@link Void} with
- * {@code return null} if no return type is needed.
+ * No-op visitor for subclassing. All interface methods simply delegate to {@link
+ * #visitOther(Element)}, returning its result.
*
+ * @param <V> any type to be returned by the visit method. Use {@link Void} with {@code return null}
+ * if no return type is needed.
* @author sberlin@gmail.com (Sam Berlin)
* @since 2.0
*/
public abstract class DefaultElementVisitor<V> implements ElementVisitor<V> {
- /**
- * Default visit implementation. Returns {@code null}.
- */
+ /** Default visit implementation. Returns {@code null}. */
protected V visitOther(Element element) {
return null;
}
+ @Override
public V visit(Message message) {
return visitOther(message);
}
+ @Override
public <T> V visit(Binding<T> binding) {
return visitOther(binding);
}
/*if[AOP]*/
+ @Override
public V visit(InterceptorBinding interceptorBinding) {
return visitOther(interceptorBinding);
}
/*end[AOP]*/
+ @Override
public V visit(ScopeBinding scopeBinding) {
return visitOther(scopeBinding);
}
+ @Override
public V visit(TypeConverterBinding typeConverterBinding) {
return visitOther(typeConverterBinding);
}
+ @Override
public <T> V visit(ProviderLookup<T> providerLookup) {
return visitOther(providerLookup);
}
+ @Override
public V visit(InjectionRequest<?> injectionRequest) {
return visitOther(injectionRequest);
}
+ @Override
public V visit(StaticInjectionRequest staticInjectionRequest) {
return visitOther(staticInjectionRequest);
}
+ @Override
public V visit(PrivateElements privateElements) {
return visitOther(privateElements);
}
+ @Override
public <T> V visit(MembersInjectorLookup<T> lookup) {
return visitOther(lookup);
}
+ @Override
public V visit(TypeListenerBinding binding) {
return visitOther(binding);
}
-
+
+ @Override
public V visit(ProvisionListenerBinding binding) {
return visitOther(binding);
}
-
+
+ @Override
public V visit(DisableCircularProxiesOption option) {
return visitOther(option);
}
-
+
+ @Override
public V visit(RequireExplicitBindingsOption option) {
return visitOther(option);
}
-
+
+ @Override
public V visit(RequireAtInjectOnConstructorsOption option) {
return visitOther(option);
}
+ @Override
public V visit(RequireExactBindingAnnotationsOption option) {
return visitOther(option);
}
+ @Override
public V visit(ModuleAnnotatedMethodScannerBinding binding) {
return visitOther(binding);
}
diff --git a/core/src/com/google/inject/spi/Dependency.java b/core/src/com/google/inject/spi/Dependency.java
index f86e2559..5a084c6a 100644
--- a/core/src/com/google/inject/spi/Dependency.java
+++ b/core/src/com/google/inject/spi/Dependency.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.inject.Key;
import com.google.inject.internal.MoreTypes;
-
import java.util.List;
import java.util.Set;
@@ -58,9 +57,7 @@ public final class Dependency<T> {
return new Dependency<T>(null, MoreTypes.canonicalizeKey(key), true, -1);
}
- /**
- * Returns the dependencies from the given injection points.
- */
+ /** Returns the dependencies from the given injection points. */
public static Set<Dependency<?>> forInjectionPoints(Set<InjectionPoint> injectionPoints) {
List<Dependency<?>> dependencies = Lists.newArrayList();
for (InjectionPoint injectionPoint : injectionPoints) {
@@ -69,16 +66,12 @@ public final class Dependency<T> {
return ImmutableSet.copyOf(dependencies);
}
- /**
- * Returns the key to the binding that satisfies this dependency.
- */
+ /** Returns the key to the binding that satisfies this dependency. */
public Key<T> getKey() {
return this.key;
}
- /**
- * Returns true if null is a legal value for this dependency.
- */
+ /** Returns true if null is a legal value for this dependency. */
public boolean isNullable() {
return nullable;
}
@@ -100,11 +93,13 @@ public final class Dependency<T> {
return parameterIndex;
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return Objects.hashCode(injectionPoint, parameterIndex, key);
}
- @Override public boolean equals(Object o) {
+ @Override
+ public boolean equals(Object o) {
if (o instanceof Dependency) {
Dependency dependency = (Dependency) o;
return Objects.equal(injectionPoint, dependency.injectionPoint)
@@ -115,7 +110,8 @@ public final class Dependency<T> {
}
}
- @Override public String toString() {
+ @Override
+ public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(key);
if (injectionPoint != null) {
diff --git a/core/src/com/google/inject/spi/DependencyAndSource.java b/core/src/com/google/inject/spi/DependencyAndSource.java
index ce52aaed..321e9495 100644
--- a/core/src/com/google/inject/spi/DependencyAndSource.java
+++ b/core/src/com/google/inject/spi/DependencyAndSource.java
@@ -1,12 +1,12 @@
/*
* Copyright (C) 2011 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
@@ -20,16 +20,19 @@ import com.google.inject.Binder;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.internal.util.StackTraceElements;
-
import java.lang.reflect.Member;
/**
- * A combination of a {@link Dependency} and the {@link Binding#getSource()
- * source} where the dependency was bound.
- *
+ * A combination of a {@link Dependency} and the {@link Binding#getSource() source} where the
+ * dependency was bound.
+ *
* @author sameb@google.com (Sam Berlin)
* @since 4.0
+ * @deprecated The only use of this object is for {@link
+ * ProvisionListener.ProvisionInvocation#getDependencyChain()} which is also deprecated. This
+ * object will also be removed in Guice 4.4.
*/
+@Deprecated
public final class DependencyAndSource {
private final Dependency<?> dependency;
private final Object source;
@@ -40,21 +43,19 @@ public final class DependencyAndSource {
}
/**
- * Returns the Dependency, if one exists. For anything that can be referenced
- * by {@link Injector#getBinding}, a dependency exists. A dependency will not
- * exist (and this will return null) for types initialized with
- * {@link Binder#requestInjection} or {@link Injector#injectMembers(Object)},
- * nor will it exist for objects injected into Providers bound with
- * LinkedBindingBuilder#toProvider(Provider).
+ * Returns the Dependency, if one exists. For anything that can be referenced by {@link
+ * Injector#getBinding}, a dependency exists. A dependency will not exist (and this will return
+ * null) for types initialized with {@link Binder#requestInjection} or {@link
+ * Injector#injectMembers(Object)}, nor will it exist for objects injected into Providers bound
+ * with LinkedBindingBuilder#toProvider(Provider).
*/
public Dependency<?> getDependency() {
return dependency;
}
/**
- * Returns a string describing where this dependency was bound. If the binding
- * was just-in-time, there is no valid binding source, so this describes the
- * class in question.
+ * Returns a string describing where this dependency was bound. If the binding was just-in-time,
+ * there is no valid binding source, so this describes the class in question.
*/
public String getBindingSource() {
if (source instanceof Class) {
@@ -76,4 +77,4 @@ public final class DependencyAndSource {
return "Source: " + source;
}
}
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/spi/DisableCircularProxiesOption.java b/core/src/com/google/inject/spi/DisableCircularProxiesOption.java
index 4193e0ab..ad6812c0 100644
--- a/core/src/com/google/inject/spi/DisableCircularProxiesOption.java
+++ b/core/src/com/google/inject/spi/DisableCircularProxiesOption.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,14 +33,17 @@ public final class DisableCircularProxiesOption implements Element {
this.source = checkNotNull(source, "source");
}
+ @Override
public Object getSource() {
return source;
}
+ @Override
public void applyTo(Binder binder) {
binder.withSource(getSource()).disableCircularProxies();
}
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
diff --git a/core/src/com/google/inject/spi/Element.java b/core/src/com/google/inject/spi/Element.java
index 814ccef8..9b42b7ee 100644
--- a/core/src/com/google/inject/spi/Element.java
+++ b/core/src/com/google/inject/spi/Element.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -60,5 +60,4 @@ public interface Element {
* element.
*/
void applyTo(Binder binder);
-
}
diff --git a/core/src/com/google/inject/spi/ElementSource.java b/core/src/com/google/inject/spi/ElementSource.java
index 52783c99..5a0d6cc3 100644
--- a/core/src/com/google/inject/spi/ElementSource.java
+++ b/core/src/com/google/inject/spi/ElementSource.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,79 +20,76 @@ import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.inject.internal.util.StackTraceElements;
import com.google.inject.internal.util.StackTraceElements.InMemoryStackTraceElement;
-
import java.util.List;
/**
- * Contains information about where and how an {@link Element element} was
- * bound.
- * <p>
- * The {@link #getDeclaringSource() declaring source} refers to a location in
- * source code that defines the Guice {@link Element element}. For example, if
- * the element is created from a method annotated by {@literal @Provides}, the
- * declaring source of element would be the method itself.
- * <p>
- * The {@link #getStackTrace()} refers to the sequence of calls ends at one of
- * {@link com.google.inject.Binder} {@code bindXXX()} methods and eventually
- * defines the element. Note that {@link #getStackTrace()} lists
- * {@link StackTraceElement StackTraceElements} in reverse chronological order.
- * The first element (index zero) is the last method call and the last element
- * is the first method invocation. By default, the stack trace is not collected.
- * The default behavior can be changed by setting the
- * {@code guice_include_stack_traces} flag value. The value can be either
- * {@code OFF}, {@code ONLY_FOR_DECLARING_SOURCE} or {@code COMPLETE}. Note that
- * collecting stack traces for every binding can cause a performance hit when
- * the injector is created.
- * <p>
- * The sequence of class names of {@link com.google.inject.Module modules}
- * involved in the element creation can be retrieved by
- * {@link #getModuleClassNames()}. Similar to {@link #getStackTrace()}, the
- * order is reverse chronological. The first module (index 0) is the module that
- * installs the {@link Element element}. The last module is the root module.
- * <p>
- * In order to support the cases where a Guice {@link Element element} is
- * created from another Guice {@link Element element} (original) (e.g., by
- * {@link Element#applyTo}), it also provides a reference to the original
- * element source ({@link #getOriginalElementSource()}).
+ * Contains information about where and how an {@link Element element} was bound.
+ *
+ * <p>The {@link #getDeclaringSource() declaring source} refers to a location in source code that
+ * defines the Guice {@link Element element}. For example, if the element is created from a method
+ * annotated by {@literal @Provides}, the declaring source of element would be the method itself.
+ *
+ * <p>The {@link #getStackTrace()} refers to the sequence of calls ends at one of {@link
+ * com.google.inject.Binder} {@code bindXXX()} methods and eventually defines the element. Note that
+ * {@link #getStackTrace()} lists {@link StackTraceElement StackTraceElements} in reverse
+ * chronological order. The first element (index zero) is the last method call and the last element
+ * is the first method invocation. By default, the stack trace is not collected. The default
+ * behavior can be changed by setting the {@code guice_include_stack_traces} flag value. The value
+ * can be either {@code OFF}, {@code ONLY_FOR_DECLARING_SOURCE} or {@code COMPLETE}. Note that
+ * collecting stack traces for every binding can cause a performance hit when the injector is
+ * created.
+ *
+ * <p>The sequence of class names of {@link com.google.inject.Module modules} involved in the
+ * element creation can be retrieved by {@link #getModuleClassNames()}. Similar to {@link
+ * #getStackTrace()}, the order is reverse chronological. The first module (index 0) is the module
+ * that installs the {@link Element element}. The last module is the root module.
+ *
+ * <p>In order to support the cases where a Guice {@link Element element} is created from another
+ * Guice {@link Element element} (original) (e.g., by {@link Element#applyTo}), it also provides a
+ * reference to the original element source ({@link #getOriginalElementSource()}).
*
* @since 4.0
*/
public final class ElementSource {
- /**
+ /**
* The {@link ElementSource source} of element that this element created from (if there is any),
* otherwise {@code null}.
*/
final ElementSource originalElementSource;
-
+
/** The {@link ModuleSource source} of module creates the element. */
final ModuleSource moduleSource;
-
- /**
+
+ /**
* The partial call stack that starts at the last module {@link Module#Configure(Binder)
* configure(Binder)} call. The value is empty if stack trace collection is off.
*/
final InMemoryStackTraceElement[] partialCallStack;
-
- /**
- * Refers to a single location in source code that causes the element creation. It can be any
- * object such as {@link Constructor}, {@link Method}, {@link Field}, {@link StackTraceElement},
- * etc. For example, if the element is created from a method annotated by {@literal @Provides},
+
+ /**
+ * Refers to a single location in source code that causes the element creation. It can be any
+ * object such as {@link Constructor}, {@link Method}, {@link Field}, {@link StackTraceElement},
+ * etc. For example, if the element is created from a method annotated by {@literal @Provides},
* the declaring source of element would be the method itself.
*/
final Object declaringSource;
/**
- * Creates a new {@ElementSource} from the given parameters.
+ * Creates a new {@ElementSource} from the given parameters.
+ *
* @param originalElementSource The source of element that this element created from (if there is
- * any), otherwise {@code null}.
+ * any), otherwise {@code null}.
* @param declaringSource the source (in)directly declared the element.
* @param moduleSource the moduleSource when the element is bound
- * @param partialCallStack the partial call stack from the top module to where the element is
- * bound
+ * @param partialCallStack the partial call stack from the top module to where the element is
+ * bound
*/
- ElementSource(/* @Nullable */ ElementSource originalSource, Object declaringSource,
- ModuleSource moduleSource, StackTraceElement[] partialCallStack) {
+ ElementSource(
+ /* @Nullable */ ElementSource originalSource,
+ Object declaringSource,
+ ModuleSource moduleSource,
+ StackTraceElement[] partialCallStack) {
Preconditions.checkNotNull(declaringSource, "declaringSource cannot be null.");
Preconditions.checkNotNull(moduleSource, "moduleSource cannot be null.");
Preconditions.checkNotNull(partialCallStack, "partialCallStack cannot be null.");
@@ -101,7 +98,7 @@ public final class ElementSource {
this.moduleSource = moduleSource;
this.partialCallStack = StackTraceElements.convertToInMemoryStackTraceElement(partialCallStack);
}
-
+
/**
* Returns the {@link ElementSource} of the element this was created or copied from. If this was
* not created or copied from another element, returns {@code null}.
@@ -109,22 +106,22 @@ public final class ElementSource {
public ElementSource getOriginalElementSource() {
return originalElementSource;
}
-
+
/**
- * Returns a single location in source code that defines the element. It can be any object
- * such as {@link java.lang.reflect.Constructor}, {@link java.lang.reflect.Method},
- * {@link java.lang.reflect.Field}, {@link StackTraceElement}, etc. For
- * example, if the element is created from a method annotated by {@literal @Provides}, the
- * declaring source of element would be the method itself.
+ * Returns a single location in source code that defines the element. It can be any object such as
+ * {@link java.lang.reflect.Constructor}, {@link java.lang.reflect.Method}, {@link
+ * java.lang.reflect.Field}, {@link StackTraceElement}, etc. For example, if the element is
+ * created from a method annotated by {@literal @Provides}, the declaring source of element would
+ * be the method itself.
*/
public Object getDeclaringSource() {
return declaringSource;
}
-
+
/**
- * Returns the class names of modules involved in creating this {@link Element}. The first
- * element (index 0) is the class name of module that defined the element, and the last element
- * is the class name of root module.
+ * Returns the class names of modules involved in creating this {@link Element}. The first element
+ * (index 0) is the class name of module that defined the element, and the last element is the
+ * class name of root module.
*/
public List<String> getModuleClassNames() {
return moduleSource.getModuleClassNames();
@@ -134,18 +131,18 @@ public final class ElementSource {
* Returns the position of {@link com.google.inject.Module#configure configure(Binder)} method
* call in the {@link #getStackTrace stack trace} for modules that their classes returned by
* {@link #getModuleClassNames}. For example, if the stack trace looks like the following:
- * <p>
- * {@code
- * 0 - Binder.bind(),
- * 1 - ModuleTwo.configure(),
- * 2 - Binder.install(),
- * 3 - ModuleOne.configure(),
- * 4 - theRest().
- * }
- * <p>
- * 1 and 3 are returned.
- * <p>
- * In the cases where stack trace is not available (i.e., the stack trace was not collected),
+ *
+ * <ol>
+ * <li>{@code Binder.bind()}
+ * <li>{@code ModuleTwo.configure()}
+ * <li>{@code Binder.install()}
+ * <li>{@code ModuleOne.configure()}
+ * <li>{@code theRest().
+ * </ol>
+ *
+ * <p>1 and 3 are returned.
+ *
+ * <p>In the cases where stack trace is not available (i.e., the stack trace was not collected),
* it returns -1 for all module positions.
*/
public List<Integer> getModuleConfigurePositionsInStackTrace() {
@@ -164,11 +161,11 @@ public final class ElementSource {
/**
* Returns the sequence of method calls that ends at one of {@link com.google.inject.Binder}
- * {@code bindXXX()} methods and eventually defines the element. Note that
- * {@link #getStackTrace} lists {@link StackTraceElement StackTraceElements} in reverse
- * chronological order. The first element (index zero) is the last method call and the last
- * element is the first method invocation. In the cases where stack trace is not available
- * (i.e.,the stack trace was not collected), it returns an empty array.
+ * {@code bindXXX()} methods and eventually defines the element. Note that {@link #getStackTrace}
+ * lists {@link StackTraceElement StackTraceElements} in reverse chronological order. The first
+ * element (index zero) is the last method call and the last element is the first method
+ * invocation. In the cases where stack trace is not available (i.e.,the stack trace was not
+ * collected), it returns an empty array.
*/
public StackTraceElement[] getStackTrace() {
int modulesCallStackSize = moduleSource.getStackTraceSize();
@@ -176,15 +173,16 @@ public final class ElementSource {
int size = moduleSource.getStackTraceSize() + chunkSize;
StackTraceElement[] callStack = new StackTraceElement[size];
System.arraycopy(
- StackTraceElements.convertToStackTraceElement(partialCallStack), 0, callStack, 0,
+ StackTraceElements.convertToStackTraceElement(partialCallStack),
+ 0,
+ callStack,
+ 0,
chunkSize);
System.arraycopy(moduleSource.getStackTrace(), 0, callStack, chunkSize, modulesCallStackSize);
return callStack;
}
- /**
- * Returns {@code getDeclaringSource().toString()} value.
- */
+ /** Returns {@code getDeclaringSource().toString()} value. */
@Override
public String toString() {
return getDeclaringSource().toString();
diff --git a/core/src/com/google/inject/spi/ElementVisitor.java b/core/src/com/google/inject/spi/ElementVisitor.java
index bc0d9106..b99f884a 100644
--- a/core/src/com/google/inject/spi/ElementVisitor.java
+++ b/core/src/com/google/inject/spi/ElementVisitor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,59 +23,42 @@ import com.google.inject.Inject;
/**
* Visit elements.
*
- * @param <V> any type to be returned by the visit method. Use {@link Void} with
- * {@code return null} if no return type is needed.
- *
+ * @param <V> any type to be returned by the visit method. Use {@link Void} with {@code return null}
+ * if no return type is needed.
* @since 2.0
*/
public interface ElementVisitor<V> {
/**
- * Visit a mapping from a key (type and optional annotation) to the strategy for getting
- * instances of the type.
+ * Visit a mapping from a key (type and optional annotation) to the strategy for getting instances
+ * of the type.
*/
<T> V visit(Binding<T> binding);
/*if[AOP]*/
- /**
- * Visit a registration of interceptors for matching methods of matching classes.
- */
+ /** Visit a registration of interceptors for matching methods of matching classes. */
V visit(InterceptorBinding binding);
/*end[AOP]*/
- /**
- * Visit a registration of a scope annotation with the scope that implements it.
- */
+ /** Visit a registration of a scope annotation with the scope that implements it. */
V visit(ScopeBinding binding);
- /**
- * Visit a registration of type converters for matching target types.
- */
+ /** Visit a registration of type converters for matching target types. */
V visit(TypeConverterBinding binding);
- /**
- * Visit a request to inject the instance fields and methods of an instance.
- */
+ /** Visit a request to inject the instance fields and methods of an instance. */
V visit(InjectionRequest<?> request);
- /**
- * Visit a request to inject the static fields and methods of type.
- */
+ /** Visit a request to inject the static fields and methods of type. */
V visit(StaticInjectionRequest request);
- /**
- * Visit a lookup of the provider for a type.
- */
+ /** Visit a lookup of the provider for a type. */
<T> V visit(ProviderLookup<T> lookup);
- /**
- * Visit a lookup of the members injector.
- */
+ /** Visit a lookup of the members injector. */
<T> V visit(MembersInjectorLookup<T> lookup);
- /**
- * Visit an error message and the context in which it occured.
- */
+ /** Visit an error message and the context in which it occured. */
V visit(Message message);
/**
@@ -84,35 +67,33 @@ public interface ElementVisitor<V> {
*/
V visit(PrivateElements elements);
- /**
- * Visit an injectable type listener binding.
- */
+ /** Visit an injectable type listener binding. */
V visit(TypeListenerBinding binding);
-
+
/**
* Visit a provision listener binding.
*
* @since 4.0
*/
V visit(ProvisionListenerBinding binding);
-
+
/**
* Visit a require explicit bindings command.
- *
+ *
* @since 3.0
*/
V visit(RequireExplicitBindingsOption option);
-
+
/**
* Visit a disable circular proxies command.
- *
+ *
* @since 3.0
*/
V visit(DisableCircularProxiesOption option);
-
+
/**
* Visit a require explicit {@literal @}{@link Inject} command.
- *
+ *
* @since 4.0
*/
V visit(RequireAtInjectOnConstructorsOption option);
diff --git a/core/src/com/google/inject/spi/Elements.java b/core/src/com/google/inject/spi/Elements.java
index 9348276b..724fa1ca 100644
--- a/core/src/com/google/inject/spi/Elements.java
+++ b/core/src/com/google/inject/spi/Elements.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -50,7 +50,6 @@ import com.google.inject.internal.ProviderMethodsModule;
import com.google.inject.internal.util.SourceProvider;
import com.google.inject.internal.util.StackTraceElements;
import com.google.inject.matcher.Matcher;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Arrays;
@@ -69,41 +68,35 @@ import java.util.Set;
*/
public final class Elements {
- private static final BindingTargetVisitor<Object, Object> GET_INSTANCE_VISITOR
- = new DefaultBindingTargetVisitor<Object, Object>() {
- @Override public Object visit(InstanceBinding<?> binding) {
- return binding.getInstance();
- }
+ private static final BindingTargetVisitor<Object, Object> GET_INSTANCE_VISITOR =
+ new DefaultBindingTargetVisitor<Object, Object>() {
+ @Override
+ public Object visit(InstanceBinding<?> binding) {
+ return binding.getInstance();
+ }
- @Override protected Object visitOther(Binding<?> binding) {
- throw new IllegalArgumentException();
- }
- };
+ @Override
+ protected Object visitOther(Binding<?> binding) {
+ throw new IllegalArgumentException();
+ }
+ };
- /**
- * Records the elements executed by {@code modules}.
- */
+ /** Records the elements executed by {@code modules}. */
public static List<Element> getElements(Module... modules) {
return getElements(Stage.DEVELOPMENT, Arrays.asList(modules));
}
- /**
- * Records the elements executed by {@code modules}.
- */
+ /** Records the elements executed by {@code modules}. */
public static List<Element> getElements(Stage stage, Module... modules) {
return getElements(stage, Arrays.asList(modules));
}
- /**
- * Records the elements executed by {@code modules}.
- */
+ /** Records the elements executed by {@code modules}. */
public static List<Element> getElements(Iterable<? extends Module> modules) {
return getElements(Stage.DEVELOPMENT, modules);
}
- /**
- * Records the elements executed by {@code modules}.
- */
+ /** Records the elements executed by {@code modules}. */
public static List<Element> getElements(Stage stage, Iterable<? extends Module> modules) {
RecordingBinder binder = new RecordingBinder(stage);
for (Module module : modules) {
@@ -133,9 +126,7 @@ public final class Elements {
}
}
- /**
- * Returns the module composed of {@code elements}.
- */
+ /** Returns the module composed of {@code elements}. */
public static Module getModule(final Iterable<? extends Element> elements) {
return new ElementsAsModule(elements);
}
@@ -164,11 +155,13 @@ public final class Elements {
private final Object source;
/** The current modules stack */
private ModuleSource moduleSource = null;
+
private final SourceProvider sourceProvider;
private final Set<ModuleAnnotatedMethodScanner> scanners;
/** The binder where exposed bindings will be created */
private final RecordingBinder parent;
+
private final PrivateElementsImpl privateElements;
/** All children private binders, so we can scan through them. */
@@ -180,9 +173,14 @@ public final class Elements {
this.scanners = Sets.newLinkedHashSet();
this.elements = Lists.newArrayList();
this.source = null;
- this.sourceProvider = SourceProvider.DEFAULT_INSTANCE.plusSkippedClasses(
- Elements.class, RecordingBinder.class, AbstractModule.class,
- ConstantBindingBuilderImpl.class, AbstractBindingBuilder.class, BindingBuilder.class);
+ this.sourceProvider =
+ SourceProvider.DEFAULT_INSTANCE.plusSkippedClasses(
+ Elements.class,
+ RecordingBinder.class,
+ AbstractModule.class,
+ ConstantBindingBuilderImpl.class,
+ AbstractBindingBuilder.class,
+ BindingBuilder.class);
this.parent = null;
this.privateElements = null;
this.privateBinders = Lists.newArrayList();
@@ -225,8 +223,8 @@ public final class Elements {
Matcher<? super Class<?>> classMatcher,
Matcher<? super Method> methodMatcher,
org.aopalliance.intercept.MethodInterceptor... interceptors) {
- elements.add(new InterceptorBinding(
- getElementSource(), classMatcher, methodMatcher, interceptors));
+ elements.add(
+ new InterceptorBinding(getElementSource(), classMatcher, methodMatcher, interceptors));
}
/*end[AOP]*/
@@ -243,31 +241,37 @@ public final class Elements {
@Override
public <T> void requestInjection(TypeLiteral<T> type, T instance) {
- elements.add(new InjectionRequest<T>(getElementSource(), MoreTypes.canonicalizeForKey(type),
- instance));
+ elements.add(
+ new InjectionRequest<T>(
+ getElementSource(), MoreTypes.canonicalizeForKey(type), instance));
}
@Override
public <T> MembersInjector<T> getMembersInjector(final TypeLiteral<T> typeLiteral) {
- final MembersInjectorLookup<T> element = new MembersInjectorLookup<T>(getElementSource(),
- MoreTypes.canonicalizeForKey(typeLiteral));
+ final MembersInjectorLookup<T> element =
+ new MembersInjectorLookup<T>(
+ getElementSource(), MoreTypes.canonicalizeForKey(typeLiteral));
elements.add(element);
return element.getMembersInjector();
}
+ @Override
public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
return getMembersInjector(TypeLiteral.get(type));
}
+ @Override
public void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener) {
elements.add(new TypeListenerBinding(getElementSource(), listener, typeMatcher));
}
-
- public void bindListener(Matcher<? super Binding<?>> bindingMatcher,
- ProvisionListener... listeners) {
+
+ @Override
+ public void bindListener(
+ Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listeners) {
elements.add(new ProvisionListenerBinding(getElementSource(), bindingMatcher, listeners));
}
+ @Override
public void requestStaticInjection(Class<?>... types) {
for (Class<?> type : types) {
elements.add(new StaticInjectionRequest(getElementSource(), type));
@@ -275,10 +279,9 @@ public final class Elements {
}
/**
- * Applies all scanners to the modules we've installed. We skip certain
- * PrivateModules because store them in more than one Modules map and only
- * want to process them through one of the maps. (They're stored in both
- * maps to prevent a module from being installed more than once.)
+ * Applies all scanners to the modules we've installed. We skip certain PrivateModules because
+ * store them in more than one Modules map and only want to process them through one of the
+ * maps. (They're stored in both maps to prevent a module from being installed more than once.)
*/
void scanForAnnotatedMethods() {
for (ModuleAnnotatedMethodScanner scanner : scanners) {
@@ -293,7 +296,7 @@ public final class Elements {
moduleSource = entry.getValue().moduleSource;
try {
info.binder.install(ProviderMethodsModule.forModule(module, scanner));
- } catch(RuntimeException e) {
+ } catch (RuntimeException e) {
Collection<Message> messages = Errors.getMessagesFromThrowable(e);
if (!messages.isEmpty()) {
elements.addAll(messages);
@@ -306,6 +309,7 @@ public final class Elements {
moduleSource = null;
}
+ @Override
public void install(Module module) {
if (!modules.containsKey(module)) {
RecordingBinder binder = this;
@@ -354,64 +358,78 @@ public final class Elements {
}
}
+ @Override
public Stage currentStage() {
return stage;
}
+ @Override
public void addError(String message, Object... arguments) {
elements.add(new Message(getElementSource(), Errors.format(message, arguments)));
}
+ @Override
public void addError(Throwable t) {
String message = "An exception was caught and reported. Message: " + t.getMessage();
elements.add(new Message(ImmutableList.of((Object) getElementSource()), message, t));
}
+ @Override
public void addError(Message message) {
elements.add(message);
}
+ @Override
public <T> AnnotatedBindingBuilder<T> bind(Key<T> key) {
BindingBuilder<T> builder =
new BindingBuilder<T>(this, elements, getElementSource(), MoreTypes.canonicalizeKey(key));
return builder;
}
+ @Override
public <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
return bind(Key.get(typeLiteral));
}
+ @Override
public <T> AnnotatedBindingBuilder<T> bind(Class<T> type) {
return bind(Key.get(type));
}
+ @Override
public AnnotatedConstantBindingBuilder bindConstant() {
return new ConstantBindingBuilderImpl<Void>(this, elements, getElementSource());
}
+ @Override
public <T> Provider<T> getProvider(final Key<T> key) {
return getProvider(Dependency.get(key));
}
+ @Override
public <T> Provider<T> getProvider(final Dependency<T> dependency) {
- final ProviderLookup<T> element = new ProviderLookup<T>(getElementSource(), dependency);
+ final ProviderLookup<T> element = new ProviderLookup<>(getElementSource(), dependency);
elements.add(element);
return element.getProvider();
}
+ @Override
public <T> Provider<T> getProvider(Class<T> type) {
return getProvider(Key.get(type));
}
- public void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
- TypeConverter converter) {
+ @Override
+ public void convertToTypes(
+ Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter) {
elements.add(new TypeConverterBinding(getElementSource(), typeMatcher, converter));
}
- public RecordingBinder withSource(final Object source) {
+ @Override
+ public RecordingBinder withSource(final Object source) {
return source == this.source ? this : new RecordingBinder(this, source, null);
}
+ @Override
public RecordingBinder skipSources(Class... classesToSkip) {
// if a source is specified explicitly, we don't need to skip sources
if (source != null) {
@@ -457,6 +475,7 @@ public final class Elements {
elements.add(new ModuleAnnotatedMethodScannerBinding(getElementSource(), scanner));
}
+ @Override
public void expose(Key<?> key) {
exposeInternal(key);
}
@@ -473,11 +492,14 @@ public final class Elements {
private <T> AnnotatedElementBuilder exposeInternal(Key<T> key) {
if (privateElements == null) {
- addError("Cannot expose %s on a standard binder. "
- + "Exposed bindings are only applicable to private binders.", key);
+ 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) {}
};
@@ -516,9 +538,9 @@ public final class Elements {
declaringSource = originalSource.getDeclaringSource();
}
IncludeStackTraceOption stackTraceOption = getIncludeStackTraceOption();
- if (stackTraceOption == IncludeStackTraceOption.COMPLETE ||
- (stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE
- && declaringSource == null)) {
+ if (stackTraceOption == IncludeStackTraceOption.COMPLETE
+ || (stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE
+ && declaringSource == null)) {
callStack = new Throwable().getStackTrace();
}
if (stackTraceOption == IncludeStackTraceOption.COMPLETE) {
@@ -526,8 +548,8 @@ public final class Elements {
}
if (declaringSource == null) {
// So 'source' and 'originalSource' are null otherwise declaringSource has some value
- if (stackTraceOption == IncludeStackTraceOption.COMPLETE ||
- stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE) {
+ if (stackTraceOption == IncludeStackTraceOption.COMPLETE
+ || stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE) {
// With the above conditions and assignments 'callStack' is non-null
declaringSource = sourceProvider.get(callStack);
} else { // or if (stackTraceOption == IncludeStackTraceOptions.OFF)
@@ -536,14 +558,13 @@ public final class Elements {
}
}
// Build the binding call stack
- return new ElementSource(
- originalSource, declaringSource, moduleSource, partialCallStack);
+ return new ElementSource(originalSource, declaringSource, moduleSource, partialCallStack);
}
/**
* 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.
+ * 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;
@@ -558,7 +579,8 @@ public final class Elements {
return partialCallStack;
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "Binder";
}
}
diff --git a/core/src/com/google/inject/spi/ExposedBinding.java b/core/src/com/google/inject/spi/ExposedBinding.java
index 16a569eb..501d8845 100644
--- a/core/src/com/google/inject/spi/ExposedBinding.java
+++ b/core/src/com/google/inject/spi/ExposedBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,13 +27,10 @@ import com.google.inject.Binding;
*/
public interface ExposedBinding<T> extends Binding<T>, HasDependencies {
- /**
- * Returns the enclosed environment that holds the original binding.
- */
+ /** Returns the enclosed environment that holds the original binding. */
PrivateElements getPrivateElements();
- /**
- * Unsupported. Always throws {@link UnsupportedOperationException}.
- */
+ /** Unsupported. Always throws {@link UnsupportedOperationException}. */
+ @Override
void applyTo(Binder binder);
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/spi/HasDependencies.java b/core/src/com/google/inject/spi/HasDependencies.java
index 77a55231..f28f1a3e 100644
--- a/core/src/com/google/inject/spi/HasDependencies.java
+++ b/core/src/com/google/inject/spi/HasDependencies.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -31,7 +31,7 @@ public interface HasDependencies {
* Returns the known dependencies for this type. If this has dependencies whose values are not
* known statically, a dependency for the {@link com.google.inject.Injector Injector} will be
* included in the returned set.
- *
+ *
* @return a possibly empty set
*/
Set<Dependency<?>> getDependencies();
diff --git a/core/src/com/google/inject/spi/InjectionPoint.java b/core/src/com/google/inject/spi/InjectionPoint.java
index 267e0abb..2a302a4f 100644
--- a/core/src/com/google/inject/spi/InjectionPoint.java
+++ b/core/src/com/google/inject/spi/InjectionPoint.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,9 +18,11 @@ package com.google.inject.spi;
import static com.google.inject.internal.MoreTypes.getRawType;
+import com.google.common.collect.ComparisonChain;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
+import com.google.common.collect.Ordering;
import com.google.inject.ConfigurationException;
import com.google.inject.Inject;
import com.google.inject.Key;
@@ -30,7 +32,6 @@ import com.google.inject.internal.Errors;
import com.google.inject.internal.ErrorsException;
import com.google.inject.internal.Nullability;
import com.google.inject.internal.util.Classes;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
@@ -58,7 +59,7 @@ import java.util.logging.Logger;
* @since 2.0
*/
public final class InjectionPoint {
-
+
private static final Logger logger = Logger.getLogger(InjectionPoint.class.getName());
private final boolean optional;
@@ -77,8 +78,8 @@ public final class InjectionPoint {
this.member = constructor;
this.declaringType = declaringType;
this.optional = false;
- this.dependencies = forMember(
- constructor, declaringType, constructor.getParameterAnnotations());
+ this.dependencies =
+ forMember(constructor, declaringType, constructor.getParameterAnnotations());
}
InjectionPoint(TypeLiteral<?> declaringType, Field field, boolean optional) {
@@ -99,21 +100,21 @@ public final class InjectionPoint {
}
errors.throwConfigurationExceptionIfErrorsExist();
- this.dependencies = ImmutableList.<Dependency<?>>of(
- newDependency(key, Nullability.allowsNull(annotations), -1));
+ this.dependencies =
+ ImmutableList.<Dependency<?>>of(
+ newDependency(key, Nullability.allowsNull(annotations), -1));
}
- private ImmutableList<Dependency<?>> forMember(Member member, TypeLiteral<?> type,
- Annotation[][] paramterAnnotations) {
+ private ImmutableList<Dependency<?>> forMember(
+ Member member, TypeLiteral<?> type, Annotation[][] paramterAnnotations) {
Errors errors = new Errors(member);
- Iterator<Annotation[]> annotationsIterator = Arrays.asList(paramterAnnotations).iterator();
List<Dependency<?>> dependencies = Lists.newArrayList();
int index = 0;
for (TypeLiteral<?> parameterType : type.getParameterTypes(member)) {
try {
- Annotation[] parameterAnnotations = annotationsIterator.next();
+ Annotation[] parameterAnnotations = paramterAnnotations[index];
Key<?> key = Annotations.getKey(parameterType, member, parameterAnnotations, errors);
dependencies.add(newDependency(key, Nullability.allowsNull(parameterAnnotations), index));
index++;
@@ -133,9 +134,7 @@ public final class InjectionPoint {
return new Dependency<T>(this, key, allowsNull, parameterIndex);
}
- /**
- * Returns the injected constructor, field, or method.
- */
+ /** Returns the injected constructor, field, or method. */
public Member getMember() {
// TODO: Don't expose the original member (which probably has setAccessible(true)).
return member;
@@ -161,38 +160,41 @@ public final class InjectionPoint {
public boolean isOptional() {
return optional;
}
-
+
/**
* Returns true if the element is annotated with {@literal @}{@link Toolable}.
- *
+ *
* @since 3.0
*/
public boolean isToolable() {
- return ((AnnotatedElement)member).isAnnotationPresent(Toolable.class);
+ return ((AnnotatedElement) member).isAnnotationPresent(Toolable.class);
}
/**
* Returns the generic type that defines this injection point. If the member exists on a
* parameterized type, the result will include more type information than the member's {@link
* Member#getDeclaringClass() raw declaring class}.
- *
+ *
* @since 3.0
*/
public TypeLiteral<?> getDeclaringType() {
return declaringType;
}
- @Override public boolean equals(Object o) {
+ @Override
+ public boolean equals(Object o) {
return o instanceof InjectionPoint
&& member.equals(((InjectionPoint) o).member)
&& declaringType.equals(((InjectionPoint) o).declaringType);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return member.hashCode() ^ declaringType.hashCode();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return Classes.toString(member);
}
@@ -202,7 +204,6 @@ public final class InjectionPoint {
* type literal.
*
* @param constructor any single constructor present on {@code type}.
- *
* @since 3.0
*/
public static <T> InjectionPoint forConstructor(Constructor<T> constructor) {
@@ -214,7 +215,6 @@ public final class InjectionPoint {
*
* @param constructor any single constructor present on {@code type}.
* @param type the concrete type that defines {@code constructor}.
- *
* @since 3.0
*/
public static <T> InjectionPoint forConstructor(
@@ -307,13 +307,11 @@ public final class InjectionPoint {
}
/**
- * Returns a new injection point for the specified method of {@code type}.
- * This is useful for extensions that need to build dependency graphs from
- * arbitrary methods.
+ * Returns a new injection point for the specified method of {@code type}. This is useful for
+ * extensions that need to build dependency graphs from arbitrary methods.
*
* @param method any single method present on {@code type}.
* @param type the concrete type that defines {@code method}.
- *
* @since 4.0
*/
public static <T> InjectionPoint forMethod(Method method, TypeLiteral<T> type) {
@@ -324,25 +322,25 @@ public final class InjectionPoint {
* Returns all static method and field injection points on {@code type}.
*
* @return a possibly empty set of injection points. The set has a specified iteration order. All
- * fields are returned and then all methods. Within the fields, supertype fields are returned
- * before subtype fields. Similarly, supertype methods are returned before subtype methods.
+ * fields are returned and then all methods. Within the fields, supertype fields are returned
+ * before subtype fields. Similarly, supertype methods are returned before subtype methods.
* @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
- * a field with multiple binding annotations. The exception's {@link
- * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
- * of the valid injection points.
+ * a field with multiple binding annotations. The exception's {@link
+ * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} of
+ * the valid injection points.
*/
public static Set<InjectionPoint> forStaticMethodsAndFields(TypeLiteral<?> type) {
Errors errors = new Errors();
-
+
Set<InjectionPoint> result;
-
+
if (type.getRawType().isInterface()) {
errors.staticInjectionOnInterface(type.getRawType());
result = null;
} else {
result = getInjectionPoints(type, true, errors);
}
-
+
if (errors.hasErrors()) {
throw new ConfigurationException(errors.getMessages()).withPartialValue(result);
}
@@ -353,12 +351,12 @@ public final class InjectionPoint {
* Returns all static method and field injection points on {@code type}.
*
* @return a possibly empty set of injection points. The set has a specified iteration order. All
- * fields are returned and then all methods. Within the fields, supertype fields are returned
- * before subtype fields. Similarly, supertype methods are returned before subtype methods.
+ * fields are returned and then all methods. Within the fields, supertype fields are returned
+ * before subtype fields. Similarly, supertype methods are returned before subtype methods.
* @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
- * a field with multiple binding annotations. The exception's {@link
- * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
- * of the valid injection points.
+ * a field with multiple binding annotations. The exception's {@link
+ * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} of
+ * the valid injection points.
*/
public static Set<InjectionPoint> forStaticMethodsAndFields(Class<?> type) {
return forStaticMethodsAndFields(TypeLiteral.get(type));
@@ -368,12 +366,12 @@ public final class InjectionPoint {
* Returns all instance method and field injection points on {@code type}.
*
* @return a possibly empty set of injection points. The set has a specified iteration order. All
- * fields are returned and then all methods. Within the fields, supertype fields are returned
- * before subtype fields. Similarly, supertype methods are returned before subtype methods.
+ * fields are returned and then all methods. Within the fields, supertype fields are returned
+ * before subtype fields. Similarly, supertype methods are returned before subtype methods.
* @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
- * a field with multiple binding annotations. The exception's {@link
- * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
- * of the valid injection points.
+ * a field with multiple binding annotations. The exception's {@link
+ * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} of
+ * the valid injection points.
*/
public static Set<InjectionPoint> forInstanceMethodsAndFields(TypeLiteral<?> type) {
Errors errors = new Errors();
@@ -388,23 +386,22 @@ public final class InjectionPoint {
* Returns all instance method and field injection points on {@code type}.
*
* @return a possibly empty set of injection points. The set has a specified iteration order. All
- * fields are returned and then all methods. Within the fields, supertype fields are returned
- * before subtype fields. Similarly, supertype methods are returned before subtype methods.
+ * fields are returned and then all methods. Within the fields, supertype fields are returned
+ * before subtype fields. Similarly, supertype methods are returned before subtype methods.
* @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
- * a field with multiple binding annotations. The exception's {@link
- * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
- * of the valid injection points.
+ * a field with multiple binding annotations. The exception's {@link
+ * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} of
+ * the valid injection points.
*/
public static Set<InjectionPoint> forInstanceMethodsAndFields(Class<?> type) {
return forInstanceMethodsAndFields(TypeLiteral.get(type));
}
- /**
- * Returns true if the binding annotation is in the wrong place.
- */
+ /** Returns true if the binding annotation is in the wrong place. */
private static boolean checkForMisplacedBindingAnnotations(Member member, Errors errors) {
- Annotation misplacedBindingAnnotation = Annotations.findBindingAnnotation(
- errors, member, ((AnnotatedElement) member).getAnnotations());
+ Annotation misplacedBindingAnnotation =
+ Annotations.findBindingAnnotation(
+ errors, member, ((AnnotatedElement) member).getAnnotations());
if (misplacedBindingAnnotation == null) {
return false;
}
@@ -424,10 +421,8 @@ public final class InjectionPoint {
return true;
}
- /**
- * Node in the doubly-linked list of injectable members (fields and methods).
- */
- static abstract class InjectableMember {
+ /** Node in the doubly-linked list of injectable members (fields and methods). */
+ abstract static class InjectableMember {
final TypeLiteral<?> declaringType;
final boolean optional;
final boolean jsr330;
@@ -452,8 +447,8 @@ public final class InjectionPoint {
static class InjectableField extends InjectableMember {
final Field field;
- InjectableField(TypeLiteral<?> declaringType, Field field,
- Annotation atInject) {
+
+ InjectableField(TypeLiteral<?> declaringType, Field field, Annotation atInject) {
super(declaringType, atInject);
this.field = field;
}
@@ -467,13 +462,12 @@ public final class InjectionPoint {
static class InjectableMethod extends InjectableMember {
final Method method;
/**
- * true if this method overrode a method that was annotated
- * with com.google.inject.Inject. used to allow different
- * override behavior for guice inject vs javax.inject.Inject
+ * true if this method overrode a method that was annotated with com.google.inject.Inject. used
+ * to allow different override behavior for guice inject vs javax.inject.Inject
*/
boolean overrodeGuiceInject;
- InjectableMethod(TypeLiteral<?> declaringType, Method method,
- Annotation atInject) {
+
+ InjectableMethod(TypeLiteral<?> declaringType, Method method, Annotation atInject) {
super(declaringType, atInject);
this.method = method;
}
@@ -493,9 +487,7 @@ public final class InjectionPoint {
return a == null ? member.getAnnotation(Inject.class) : a;
}
- /**
- * Linked list of injectable members.
- */
+ /** Linked list of injectable members. */
static class InjectableMembers {
InjectableMember head;
InjectableMember tail;
@@ -555,23 +547,19 @@ public final class InjectionPoint {
Signature lastSignature;
/**
- * Removes a method overridden by the given method, if present. In order to
- * remain backwards compatible with prior Guice versions, this will *not*
- * remove overridden methods if 'alwaysRemove' is false and the overridden
- * signature was annotated with a com.google.inject.Inject.
- *
- * @param method
- * The method used to determine what is overridden and should be
- * removed.
- * @param alwaysRemove
- * true if overridden methods should be removed even if they were
- * guice @Inject
- * @param injectableMethod
- * if this method overrode any guice @Inject methods,
- * {@link InjectableMethod#overrodeGuiceInject} is set to true
+ * Removes a method overridden by the given method, if present. In order to remain backwards
+ * compatible with prior Guice versions, this will *not* remove overridden methods if
+ * 'alwaysRemove' is false and the overridden signature was annotated with a
+ * com.google.inject.Inject.
+ *
+ * @param method The method used to determine what is overridden and should be removed.
+ * @param alwaysRemove true if overridden methods should be removed even if they were
+ * guice @Inject
+ * @param injectableMethod if this method overrode any guice @Inject methods, {@link
+ * InjectableMethod#overrodeGuiceInject} is set to true
*/
- boolean removeIfOverriddenBy(Method method, boolean alwaysRemove,
- InjectableMethod injectableMethod) {
+ boolean removeIfOverriddenBy(
+ Method method, boolean alwaysRemove, InjectableMethod injectableMethod) {
if (position == Position.TOP) {
// If we're at the top of the hierarchy, there's nothing to override.
return false;
@@ -580,13 +568,18 @@ public final class InjectionPoint {
if (bySignature == null) {
// We encountered a method in a subclass. Time to index the
// methods in the parent class.
- bySignature = new HashMap<Signature, List<InjectableMethod>>();
- for (InjectableMember member = injectableMembers.head; member != null;
+ bySignature = new HashMap<>();
+ for (InjectableMember member = injectableMembers.head;
+ member != null;
member = member.next) {
- if (!(member instanceof InjectableMethod)) continue;
+ if (!(member instanceof InjectableMethod)) {
+ continue;
+ }
InjectableMethod im = (InjectableMethod) member;
- if (im.isFinal()) continue;
- List<InjectableMethod> methods = new ArrayList<InjectableMethod>();
+ if (im.isFinal()) {
+ continue;
+ }
+ List<InjectableMethod> methods = new ArrayList<>();
methods.add(im);
bySignature.put(new Signature(im.method), methods);
}
@@ -597,19 +590,18 @@ public final class InjectionPoint {
List<InjectableMethod> methods = bySignature.get(signature);
boolean removed = false;
if (methods != null) {
- for (Iterator<InjectableMethod> iterator = methods.iterator();
- iterator.hasNext();) {
+ for (Iterator<InjectableMethod> iterator = methods.iterator(); iterator.hasNext(); ) {
InjectableMethod possiblyOverridden = iterator.next();
if (overrides(method, possiblyOverridden.method)) {
boolean wasGuiceInject =
- !possiblyOverridden.jsr330 || possiblyOverridden.overrodeGuiceInject;
- if(injectableMethod != null) {
+ !possiblyOverridden.jsr330 || possiblyOverridden.overrodeGuiceInject;
+ if (injectableMethod != null) {
injectableMethod.overrodeGuiceInject = wasGuiceInject;
}
// Only actually remove the methods if we want to force
// remove or if the signature never specified @com.google.inject.Inject
// somewhere.
- if(alwaysRemove || !wasGuiceInject) {
+ if (alwaysRemove || !wasGuiceInject) {
removed = true;
iterator.remove();
injectableMembers.remove(possiblyOverridden);
@@ -621,23 +613,25 @@ public final class InjectionPoint {
}
/**
- * Adds the given method to the list of injection points. Keeps track of it in this index
- * in case it gets overridden.
+ * Adds the given method to the list of injection points. Keeps track of it in this index in
+ * case it gets overridden.
*/
void add(InjectableMethod injectableMethod) {
injectableMembers.add(injectableMethod);
- if (position == Position.BOTTOM
- || injectableMethod.isFinal()) {
+ if (position == Position.BOTTOM || injectableMethod.isFinal()) {
// This method can't be overridden, so there's no need to index it.
return;
}
if (bySignature != null) {
// Try to reuse the signature we created during removal
- Signature signature = injectableMethod.method == lastMethod
- ? lastSignature : new Signature(injectableMethod.method);
+ @SuppressWarnings("ReferenceEquality")
+ Signature signature =
+ injectableMethod.method == lastMethod
+ ? lastSignature
+ : new Signature(injectableMethod.method);
List<InjectableMethod> methods = bySignature.get(signature);
if (methods == null) {
- methods = new ArrayList<InjectableMethod>();
+ methods = new ArrayList<>();
bySignature.put(signature, methods);
}
methods.add(injectableMethod);
@@ -648,13 +642,14 @@ public final class InjectionPoint {
/**
* Returns an ordered, immutable set of injection points for the given type. Members in
* superclasses come before members in subclasses. Within a class, fields come before methods.
- * Overridden methods are filtered out.
+ * Overridden methods are filtered out. The order of fields/methods within a class is consistent
+ * but undefined.
*
* @param statics true is this method should return static members, false for instance members
* @param errors used to record errors
*/
- private static Set<InjectionPoint> getInjectionPoints(final TypeLiteral<?> type,
- boolean statics, Errors errors) {
+ private static Set<InjectionPoint> getInjectionPoints(
+ final TypeLiteral<?> type, boolean statics, Errors errors) {
InjectableMembers injectableMembers = new InjectableMembers();
OverrideIndex overrideIndex = null;
@@ -672,7 +667,7 @@ public final class InjectionPoint {
TypeLiteral<?> current = hierarchy.get(i);
- for (Field field : current.getRawType().getDeclaredFields()) {
+ for (Field field : getDeclaredFields(current)) {
if (Modifier.isStatic(field.getModifiers()) == statics) {
Annotation atInject = getAtInject(field);
if (atInject != null) {
@@ -685,22 +680,25 @@ public final class InjectionPoint {
}
}
- for (Method method : current.getRawType().getDeclaredMethods()) {
+ for (Method method : getDeclaredMethods(current)) {
if (isEligibleForInjection(method, statics)) {
Annotation atInject = getAtInject(method);
if (atInject != null) {
- InjectableMethod injectableMethod = new InjectableMethod(
- current, method, atInject);
+ InjectableMethod injectableMethod = new InjectableMethod(current, method, atInject);
if (checkForMisplacedBindingAnnotations(method, errors)
|| !isValidMethod(injectableMethod, errors)) {
if (overrideIndex != null) {
- boolean removed = overrideIndex.removeIfOverriddenBy(method, false, injectableMethod);
- if(removed) {
- logger.log(Level.WARNING, "Method: {0} is not a valid injectable method ("
- + "because it either has misplaced binding annotations "
- + "or specifies type parameters) but is overriding a method that is valid. "
- + "Because it is not valid, the method will not be injected. "
- + "To fix this, make the method a valid injectable method.", method);
+ boolean removed =
+ overrideIndex.removeIfOverriddenBy(method, false, injectableMethod);
+ if (removed) {
+ logger.log(
+ Level.WARNING,
+ "Method: {0} is not a valid injectable method ("
+ + "because it either has misplaced binding annotations "
+ + "or specifies type parameters) but is overriding a method that is "
+ + "valid. Because it is not valid, the method will not be injected. "
+ + "To fix this, make the method a valid injectable method.",
+ method);
}
}
continue;
@@ -717,20 +715,23 @@ public final class InjectionPoint {
*/
overrideIndex = new OverrideIndex(injectableMembers);
} else {
- // Forcibly remove the overriden method, otherwise we'll inject
+ // Forcibly remove the overridden method, otherwise we'll inject
// it twice.
overrideIndex.removeIfOverriddenBy(method, true, injectableMethod);
}
overrideIndex.add(injectableMethod);
}
} else {
- if(overrideIndex != null) {
+ if (overrideIndex != null) {
boolean removed = overrideIndex.removeIfOverriddenBy(method, false, null);
- if(removed) {
- logger.log(Level.WARNING, "Method: {0} is not annotated with @Inject but "
- + "is overriding a method that is annotated with @javax.inject.Inject. Because "
- + "it is not annotated with @Inject, the method will not be injected. "
- + "To fix this, annotate the method with @Inject.", method);
+ if (removed) {
+ logger.log(
+ Level.WARNING,
+ "Method: {0} is not annotated with @Inject but "
+ + "is overriding a method that is annotated with @javax.inject.Inject."
+ + "Because it is not annotated with @Inject, the method will not be "
+ + "injected. To fix this, annotate the method with @Inject.",
+ method);
}
}
}
@@ -743,8 +744,7 @@ public final class InjectionPoint {
}
ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder();
- for (InjectableMember im = injectableMembers.head; im != null;
- im = im.next) {
+ for (InjectableMember im = injectableMembers.head; im != null; im = im.next) {
try {
builder.add(im.toInjectionPoint());
} catch (ConfigurationException ignorable) {
@@ -756,22 +756,86 @@ public final class InjectionPoint {
return builder.build();
}
- /**
- * Returns true if the method is eligible to be injected. This is different than
- * {@link #isValidMethod}, because ineligibility will not drop a method
- * from being injected if a superclass was eligible & valid.
- * Bridge & synthetic methods are excluded from eligibility for two reasons:
- *
- * <p>Prior to Java8, javac would generate these methods in subclasses without
- * annotations, which means this would accidentally stop injecting a method
- * annotated with {@link javax.inject.Inject}, since the spec says to stop
- * injecting if a subclass isn't annotated with it.
- *
- * <p>Starting at Java8, javac copies the annotations to the generated subclass
- * method, except it leaves out the generic types. If this considered it a valid
- * injectable method, this would eject the parent's overridden method that had the
- * proper generic types, and would use invalid injectable parameters as a result.
- *
+ private static Field[] getDeclaredFields(TypeLiteral<?> type) {
+ Field[] fields = type.getRawType().getDeclaredFields();
+ Arrays.sort(fields, FIELD_ORDERING);
+ return fields;
+ }
+
+ private static Method[] getDeclaredMethods(TypeLiteral<?> type) {
+ Method[] methods = type.getRawType().getDeclaredMethods();
+ Arrays.sort(methods, METHOD_ORDERING);
+ return methods;
+ }
+
+ /**
+ * An ordering suitable for comparing two classes if they are loaded by the same classloader
+ *
+ * <p>Within a single classloader there can only be one class with a given name, so we just
+ * compare the names.
+ */
+ private static final Ordering<Class<?>> CLASS_ORDERING =
+ new Ordering<Class<?>>() {
+ @Override
+ public int compare(Class<?> o1, Class<?> o2) {
+ return o1.getName().compareTo(o2.getName());
+ }
+ };
+
+ /**
+ * An ordering suitable for comparing two fields if they are owned by the same class.
+ *
+ * <p>Within a single class it is sufficent to compare the non-generic field signature which
+ * consists of the field name and type.
+ */
+ private static final Ordering<Field> FIELD_ORDERING =
+ new Ordering<Field>() {
+ @Override
+ public int compare(Field left, Field right) {
+ return ComparisonChain.start()
+ .compare(left.getName(), right.getName())
+ .compare(left.getType(), right.getType(), CLASS_ORDERING)
+ .result();
+ }
+ };
+
+ /**
+ * An ordering suitable for comparing two methods if they are owned by the same class.
+ *
+ * <p>Within a single class it is sufficient to compare the non-generic method signature which
+ * consists of the name, return type and parameter types.
+ */
+ private static final Ordering<Method> METHOD_ORDERING =
+ new Ordering<Method>() {
+ @Override
+ public int compare(Method left, Method right) {
+ return ComparisonChain.start()
+ .compare(left.getName(), right.getName())
+ .compare(left.getReturnType(), right.getReturnType(), CLASS_ORDERING)
+ .compare(
+ Arrays.asList(left.getParameterTypes()),
+ Arrays.asList(right.getParameterTypes()),
+ CLASS_ORDERING.lexicographical())
+ .result();
+ }
+ };
+
+ /**
+ * Returns true if the method is eligible to be injected. This is different than {@link
+ * #isValidMethod}, because ineligibility will not drop a method from being injected if a
+ * superclass was eligible & valid. Bridge & synthetic methods are excluded from eligibility for
+ * two reasons:
+ *
+ * <p>Prior to Java8, javac would generate these methods in subclasses without annotations, which
+ * means this would accidentally stop injecting a method annotated with {@link
+ * javax.inject.Inject}, since the spec says to stop injecting if a subclass isn't annotated with
+ * it.
+ *
+ * <p>Starting at Java8, javac copies the annotations to the generated subclass method, except it
+ * leaves out the generic types. If this considered it a valid injectable method, this would eject
+ * the parent's overridden method that had the proper generic types, and would use invalid
+ * injectable parameters as a result.
+ *
* <p>The fix for both is simply to ignore these synthetic bridge methods.
*/
private static boolean isEligibleForInjection(Method method, boolean statics) {
@@ -780,8 +844,7 @@ public final class InjectionPoint {
&& !method.isSynthetic();
}
- private static boolean isValidMethod(InjectableMethod injectableMethod,
- Errors errors) {
+ private static boolean isValidMethod(InjectableMethod injectableMethod, Errors errors) {
boolean result = true;
if (injectableMethod.jsr330) {
Method method = injectableMethod.method;
@@ -798,7 +861,7 @@ public final class InjectionPoint {
}
private static List<TypeLiteral<?>> hierarchyFor(TypeLiteral<?> type) {
- List<TypeLiteral<?>> hierarchy = new ArrayList<TypeLiteral<?>>();
+ List<TypeLiteral<?>> hierarchy = new ArrayList<>();
TypeLiteral<?> current = type;
while (current.getRawType() != Object.class) {
hierarchy.add(current);
@@ -824,9 +887,7 @@ public final class InjectionPoint {
return a.getDeclaringClass().getPackage().equals(b.getDeclaringClass().getPackage());
}
- /**
- * A method signature. Used to handle method overridding.
- */
+ /** A method signature. Used to handle method overridding. */
static class Signature {
final String name;
@@ -845,11 +906,13 @@ public final class InjectionPoint {
this.hash = h;
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return this.hash;
}
- @Override public boolean equals(Object o) {
+ @Override
+ public boolean equals(Object o) {
if (!(o instanceof Signature)) {
return false;
}
diff --git a/core/src/com/google/inject/spi/InjectionRequest.java b/core/src/com/google/inject/spi/InjectionRequest.java
index f80e37a4..8fbd16df 100644
--- a/core/src/com/google/inject/spi/InjectionRequest.java
+++ b/core/src/com/google/inject/spi/InjectionRequest.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,13 +21,13 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.inject.Binder;
import com.google.inject.ConfigurationException;
import com.google.inject.TypeLiteral;
-
import java.util.Set;
/**
* A request to inject the instance fields and methods of an instance. Requests are created
* explicitly in a module using {@link com.google.inject.Binder#requestInjection(Object)
* requestInjection()} statements:
+ *
* <pre>
* requestInjection(serviceInstance);</pre>
*
@@ -46,6 +46,7 @@ public final class InjectionRequest<T> implements Element {
this.instance = checkNotNull(instance, "instance");
}
+ @Override
public Object getSource() {
return source;
}
@@ -63,21 +64,23 @@ public final class InjectionRequest<T> implements Element {
* this request.
*
* @return a possibly empty set of injection points. The set has a specified iteration order. All
- * fields are returned and then all methods. Within the fields, supertype fields are returned
- * before subtype fields. Similarly, supertype methods are returned before subtype methods.
+ * fields are returned and then all methods. Within the fields, supertype fields are returned
+ * before subtype fields. Similarly, supertype methods are returned before subtype methods.
* @throws ConfigurationException if there is a malformed injection point on the class of {@code
- * instance}, such as a field with multiple binding annotations. The exception's {@link
- * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
- * of the valid injection points.
+ * instance}, such as a field with multiple binding annotations. The exception's {@link
+ * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} of
+ * the valid injection points.
*/
public Set<InjectionPoint> getInjectionPoints() throws ConfigurationException {
return InjectionPoint.forInstanceMethodsAndFields(instance.getClass());
}
+ @Override
public <R> R acceptVisitor(ElementVisitor<R> visitor) {
return visitor.visit(this);
}
+ @Override
public void applyTo(Binder binder) {
binder.withSource(getSource()).requestInjection(type, instance);
}
diff --git a/core/src/com/google/inject/spi/InstanceBinding.java b/core/src/com/google/inject/spi/InstanceBinding.java
index 2e2270cf..478b0850 100644
--- a/core/src/com/google/inject/spi/InstanceBinding.java
+++ b/core/src/com/google/inject/spi/InstanceBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,7 +17,6 @@
package com.google.inject.spi;
import com.google.inject.Binding;
-
import java.util.Set;
/**
@@ -28,9 +27,7 @@ import java.util.Set;
*/
public interface InstanceBinding<T> extends Binding<T>, HasDependencies {
- /**
- * Returns the user-supplied instance.
- */
+ /** Returns the user-supplied instance. */
T getInstance();
/**
@@ -40,5 +37,4 @@ public interface InstanceBinding<T> extends Binding<T>, HasDependencies {
* @return a possibly empty set
*/
Set<InjectionPoint> getInjectionPoints();
-
}
diff --git a/core/src/com/google/inject/spi/InterceptorBinding.java b/core/src/com/google/inject/spi/InterceptorBinding.java
index a16e701b..49e6349b 100644
--- a/core/src/com/google/inject/spi/InterceptorBinding.java
+++ b/core/src/com/google/inject/spi/InterceptorBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,16 +21,15 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.common.collect.ImmutableList;
import com.google.inject.Binder;
import com.google.inject.matcher.Matcher;
-
-import org.aopalliance.intercept.MethodInterceptor;
-
import java.lang.reflect.Method;
import java.util.List;
+import org.aopalliance.intercept.MethodInterceptor;
/**
* Registration of interceptors for matching methods of matching classes. Instances are created
- * explicitly in a module using {@link com.google.inject.Binder#bindInterceptor(
- * Matcher, Matcher, MethodInterceptor[]) bindInterceptor()} statements:
+ * explicitly in a module using {@link com.google.inject.Binder#bindInterceptor( Matcher, Matcher,
+ * MethodInterceptor[]) bindInterceptor()} statements:
+ *
* <pre>
* bindInterceptor(Matchers.subclassesOf(MyAction.class),
* Matchers.annotatedWith(Transactional.class),
@@ -59,6 +58,7 @@ public final class InterceptorBinding implements Element {
this.interceptors = ImmutableList.copyOf(interceptors);
}
+ @Override
public Object getSource() {
return source;
}
@@ -75,12 +75,18 @@ public final class InterceptorBinding implements Element {
return interceptors;
}
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
+ @Override
public void applyTo(Binder binder) {
- binder.withSource(getSource()).bindInterceptor(classMatcher, methodMatcher,
- interceptors.toArray(new MethodInterceptor[interceptors.size()]));
+ binder
+ .withSource(getSource())
+ .bindInterceptor(
+ classMatcher,
+ methodMatcher,
+ interceptors.toArray(new MethodInterceptor[interceptors.size()]));
}
}
diff --git a/core/src/com/google/inject/spi/LinkedKeyBinding.java b/core/src/com/google/inject/spi/LinkedKeyBinding.java
index 7b823a6d..2d59d8e2 100644
--- a/core/src/com/google/inject/spi/LinkedKeyBinding.java
+++ b/core/src/com/google/inject/spi/LinkedKeyBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -32,5 +32,4 @@ public interface LinkedKeyBinding<T> extends Binding<T> {
* injector using {@link com.google.inject.Injector#getBinding(Key) Injector.getBinding(key)}.
*/
Key<? extends T> getLinkedKey();
-
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/spi/MembersInjectorLookup.java b/core/src/com/google/inject/spi/MembersInjectorLookup.java
index d4da8bdd..2944de3b 100644
--- a/core/src/com/google/inject/spi/MembersInjectorLookup.java
+++ b/core/src/com/google/inject/spi/MembersInjectorLookup.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -26,6 +26,7 @@ import com.google.inject.TypeLiteral;
/**
* A lookup of the members injector for a type. Lookups are created explicitly in a module using
* {@link com.google.inject.Binder#getMembersInjector(Class) getMembersInjector()} statements:
+ *
* <pre>
* MembersInjector&lt;PaymentService&gt; membersInjector
* = getMembersInjector(PaymentService.class);</pre>
@@ -44,17 +45,17 @@ public final class MembersInjectorLookup<T> implements Element {
this.type = checkNotNull(type, "type");
}
+ @Override
public Object getSource() {
return source;
}
- /**
- * Gets the type containing the members to be injected.
- */
+ /** Gets the type containing the members to be injected. */
public TypeLiteral<T> getType() {
return type;
}
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
@@ -69,14 +70,15 @@ public final class MembersInjectorLookup<T> implements Element {
this.delegate = checkNotNull(delegate, "delegate");
}
+ @Override
public void applyTo(Binder binder) {
initializeDelegate(binder.withSource(getSource()).getMembersInjector(type));
}
/**
- * Returns the delegate members injector, or {@code null} if it has not yet been initialized.
- * The delegate will be initialized when this element is processed, or otherwise used to create
- * an injector.
+ * Returns the delegate members injector, or {@code null} if it has not yet been initialized. The
+ * delegate will be initialized when this element is processed, or otherwise used to create an
+ * injector.
*/
public MembersInjector<T> getDelegate() {
return delegate;
@@ -89,15 +91,20 @@ public final class MembersInjectorLookup<T> implements Element {
*/
public MembersInjector<T> getMembersInjector() {
return new MembersInjector<T>() {
+ @Override
public void injectMembers(T instance) {
- checkState(delegate != null,
- "This MembersInjector cannot be used until the Injector has been created.");
- delegate.injectMembers(instance);
+ MembersInjector<T> local = delegate;
+ if (local == null) {
+ throw new IllegalStateException(
+ "This MembersInjector cannot be used until the Injector has been created.");
+ }
+ local.injectMembers(instance);
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "MembersInjector<" + type + ">";
}
};
}
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/spi/Message.java b/core/src/com/google/inject/spi/Message.java
index 59c40728..282f80ce 100644
--- a/core/src/com/google/inject/spi/Message.java
+++ b/core/src/com/google/inject/spi/Message.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2006 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableList;
import com.google.inject.Binder;
import com.google.inject.internal.Errors;
import com.google.inject.internal.util.SourceProvider;
-
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.util.List;
@@ -32,6 +31,7 @@ import java.util.List;
* An error message and the context in which it occured. Messages are usually created internally by
* Guice and its extensions. Messages can be created explicitly in a module using {@link
* com.google.inject.Binder#addError(Throwable) addError()} statements:
+ *
* <pre>
* try {
* bindPropertiesFromFile();
@@ -46,18 +46,14 @@ public final class Message implements Serializable, Element {
private final Throwable cause;
private final List<Object> sources;
- /**
- * @since 2.0
- */
+ /** @since 2.0 */
public Message(List<Object> sources, String message, Throwable cause) {
this.sources = ImmutableList.copyOf(sources);
this.message = checkNotNull(message, "message");
this.cause = cause;
}
- /**
- * @since 4.0
- */
+ /** @since 4.0 */
public Message(String message, Throwable cause) {
this(ImmutableList.of(), message, cause);
}
@@ -70,6 +66,7 @@ public final class Message implements Serializable, Element {
this(ImmutableList.of(), message, null);
}
+ @Override
public String getSource() {
return sources.isEmpty()
? SourceProvider.UNKNOWN_SOURCE.toString()
@@ -81,21 +78,20 @@ public final class Message implements Serializable, Element {
return sources;
}
- /**
- * Gets the error message text.
- */
+ /** Gets the error message text. */
public String getMessage() {
return message;
}
/** @since 2.0 */
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
/**
- * Returns the throwable that caused this message, or {@code null} if this
- * message was not caused by a throwable.
+ * Returns the throwable that caused this message, or {@code null} if this message was not caused
+ * by a throwable.
*
* @since 2.0
*/
@@ -103,15 +99,18 @@ public final class Message implements Serializable, Element {
return cause;
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return message;
}
- @Override public int hashCode() {
- return message.hashCode();
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(message, cause, sources);
}
- @Override public boolean equals(Object o) {
+ @Override
+ public boolean equals(Object o) {
if (!(o instanceof Message)) {
return false;
}
@@ -120,6 +119,7 @@ public final class Message implements Serializable, Element {
}
/** @since 2.0 */
+ @Override
public void applyTo(Binder binder) {
binder.withSource(getSource()).addError(this);
}
diff --git a/core/src/com/google/inject/spi/ModuleAnnotatedMethodScanner.java b/core/src/com/google/inject/spi/ModuleAnnotatedMethodScanner.java
index 3c908257..48343cb3 100644
--- a/core/src/com/google/inject/spi/ModuleAnnotatedMethodScanner.java
+++ b/core/src/com/google/inject/spi/ModuleAnnotatedMethodScanner.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,13 +18,12 @@ package com.google.inject.spi;
import com.google.inject.Binder;
import com.google.inject.Key;
-
import java.lang.annotation.Annotation;
import java.util.Set;
/**
- * Allows extensions to scan modules for annotated methods and bind those methods
- * as providers, similar to {@code @Provides} methods.
+ * Allows extensions to scan modules for annotated methods and bind those methods as providers,
+ * similar to {@code @Provides} methods.
*
* @since 4.0
*/
@@ -40,16 +39,15 @@ public abstract class ModuleAnnotatedMethodScanner {
/**
* Prepares a method for binding. This {@code key} parameter is the key discovered from looking at
* the binding annotation and return value of the method. Implementations can modify the key to
- * instead bind to another key. For example, Multibinder may want to change
- * {@code @SetProvides String provideFoo()} to bind into a unique Key within the multibinder
- * instead of binding {@code String}.
+ * instead bind to another key. For example, Multibinder may want to change {@code @SetProvides
+ * String provideFoo()} to bind into a unique Key within the multibinder instead of binding {@code
+ * String}.
*
* <p>The injection point and annotation are provided in case the implementation wants to set the
* key based on the property of the annotation or if any additional preparation is needed for any
* of the dependencies. The annotation is guaranteed to be an instance of one the classes returned
* by {@link #annotationClasses}.
*/
- public abstract <T> Key<T> prepareMethod(Binder binder, Annotation annotation, Key<T> key,
- InjectionPoint injectionPoint);
-
+ public abstract <T> Key<T> prepareMethod(
+ Binder binder, Annotation annotation, Key<T> key, InjectionPoint injectionPoint);
}
diff --git a/core/src/com/google/inject/spi/ModuleAnnotatedMethodScannerBinding.java b/core/src/com/google/inject/spi/ModuleAnnotatedMethodScannerBinding.java
index d6324206..91cbe676 100644
--- a/core/src/com/google/inject/spi/ModuleAnnotatedMethodScannerBinding.java
+++ b/core/src/com/google/inject/spi/ModuleAnnotatedMethodScannerBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2015 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,7 +23,7 @@ import com.google.inject.internal.Errors;
/**
* Represents a call to {@link Binder#scanModulesForAnnotatedMethods} in a module.
- *
+ *
* @author sameb@google.com (Sam Berlin)
* @since 4.0
*/
@@ -36,6 +36,7 @@ public final class ModuleAnnotatedMethodScannerBinding implements Element {
this.scanner = checkNotNull(scanner, "scanner");
}
+ @Override
public Object getSource() {
return source;
}
@@ -43,17 +44,24 @@ public final class ModuleAnnotatedMethodScannerBinding implements Element {
public ModuleAnnotatedMethodScanner getScanner() {
return scanner;
}
-
+
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
+ @Override
public void applyTo(Binder binder) {
binder.withSource(getSource()).scanModulesForAnnotatedMethods(scanner);
}
- @Override public String toString() {
- return scanner + " which scans for " + scanner.annotationClasses()
- + " (bound at " + Errors.convert(source) + ")";
+ @Override
+ public String toString() {
+ return scanner
+ + " which scans for "
+ + scanner.annotationClasses()
+ + " (bound at "
+ + Errors.convert(source)
+ + ")";
}
}
diff --git a/core/src/com/google/inject/spi/ModuleSource.java b/core/src/com/google/inject/spi/ModuleSource.java
index 1e07de2b..cd9435a5 100644
--- a/core/src/com/google/inject/spi/ModuleSource.java
+++ b/core/src/com/google/inject/spi/ModuleSource.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2013 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,7 +21,6 @@ import com.google.common.collect.ImmutableList;
import com.google.inject.Module;
import com.google.inject.internal.util.StackTraceElements;
import com.google.inject.internal.util.StackTraceElements.InMemoryStackTraceElement;
-
import java.util.List;
/**
@@ -31,14 +30,10 @@ import java.util.List;
*/
final class ModuleSource {
- /**
- * The class name of module that this {@link ModuleSource} associated to.
- */
+ /** The class name of module that this {@link ModuleSource} associated to. */
private final String moduleClassName;
- /**
- * The parent {@link ModuleSource module source}.
- */
+ /** The parent {@link ModuleSource module source}. */
private final ModuleSource parent;
/**
@@ -51,22 +46,24 @@ 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
- * Module#configure(Binder) configure(Binder)} method invocation
+ * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
+ * Module#configure(Binder) configure(Binder)} method invocation
*/
ModuleSource(Object module, StackTraceElement[] partialCallStack) {
this(null, module, partialCallStack);
}
- /**
+ /**
* Creates a new {@link ModuleSource} Object.
+ *
* @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
- * Module#configure(Binder) configure(Binder)} method invocation
+ * 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, Object module, StackTraceElement[] partialCallStack) {
@@ -96,27 +93,24 @@ final class ModuleSource {
return StackTraceElements.convertToStackTraceElement(partialCallStack);
}
- /**
- * Returns the size of partial call stack if stack trace collection is on otherwise zero.
- */
+ /** 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
- * Module#configure(Binder) configure(Binder)} method invocation
+ * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link
+ * Module#configure(Binder) configure(Binder)} method invocation
*/
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;
}
diff --git a/core/src/com/google/inject/spi/PrivateElements.java b/core/src/com/google/inject/spi/PrivateElements.java
index fc36305e..f3bc0e6a 100644
--- a/core/src/com/google/inject/spi/PrivateElements.java
+++ b/core/src/com/google/inject/spi/PrivateElements.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,6 @@ package com.google.inject.spi;
import com.google.inject.Injector;
import com.google.inject.Key;
-
import java.util.List;
import java.util.Set;
@@ -31,9 +30,7 @@ import java.util.Set;
*/
public interface PrivateElements extends Element {
- /**
- * Returns the configuration information in this private environment.
- */
+ /** Returns the configuration information in this private environment. */
List<Element> getElements();
/**
@@ -42,9 +39,7 @@ public interface PrivateElements extends Element {
*/
Injector getInjector();
- /**
- * Returns the unique exposed keys for these private elements.
- */
+ /** Returns the unique exposed keys for these private elements. */
Set<Key<?>> getExposedKeys();
/**
diff --git a/core/src/com/google/inject/spi/ProviderBinding.java b/core/src/com/google/inject/spi/ProviderBinding.java
index caec274b..092f645c 100644
--- a/core/src/com/google/inject/spi/ProviderBinding.java
+++ b/core/src/com/google/inject/spi/ProviderBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -35,4 +35,4 @@ public interface ProviderBinding<T extends Provider<?>> extends Binding<T> {
* Injector.getBinding(providedKey)}
*/
Key<?> getProvidedKey();
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/spi/ProviderInstanceBinding.java b/core/src/com/google/inject/spi/ProviderInstanceBinding.java
index 99cd9db9..73f3b2e1 100644
--- a/core/src/com/google/inject/spi/ProviderInstanceBinding.java
+++ b/core/src/com/google/inject/spi/ProviderInstanceBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +18,6 @@ package com.google.inject.spi;
import com.google.inject.Binding;
import com.google.inject.Provider;
-
import java.util.Set;
/**
@@ -33,14 +32,15 @@ public interface ProviderInstanceBinding<T> extends Binding<T>, HasDependencies
/**
* If the user supplied a JSR330 binding, then this will wrap that one. To always return the
* user-supplied provider, use {@link #getUserSuppliedProvider}.
- *
+ *
* @deprecated Use {@link #getUserSuppliedProvider} instead.
*/
@Deprecated
Provider<? extends T> getProviderInstance();
-
+
/**
* Returns the user-supplied, unscoped provider.
+ *
* @since 4.0
*/
javax.inject.Provider<? extends T> getUserSuppliedProvider();
@@ -52,5 +52,4 @@ public interface ProviderInstanceBinding<T> extends Binding<T>, HasDependencies
* @return a possibly empty set
*/
Set<InjectionPoint> getInjectionPoints();
-
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/spi/ProviderKeyBinding.java b/core/src/com/google/inject/spi/ProviderKeyBinding.java
index 4a6cfdc0..9f28967f 100644
--- a/core/src/com/google/inject/spi/ProviderKeyBinding.java
+++ b/core/src/com/google/inject/spi/ProviderKeyBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,5 +34,4 @@ public interface ProviderKeyBinding<T> extends Binding<T> {
* Injector.getBinding(providerKey)}
*/
Key<? extends javax.inject.Provider<? extends T>> getProviderKey();
-
-} \ No newline at end of file
+}
diff --git a/core/src/com/google/inject/spi/ProviderLookup.java b/core/src/com/google/inject/spi/ProviderLookup.java
index 3cc2d050..a3b51631 100644
--- a/core/src/com/google/inject/spi/ProviderLookup.java
+++ b/core/src/com/google/inject/spi/ProviderLookup.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,12 +24,12 @@ import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.util.Types;
-
import java.util.Set;
/**
- * A lookup of the provider for a type. Lookups are created explicitly in a module using
- * {@link com.google.inject.Binder#getProvider(Class) getProvider()} statements:
+ * A lookup of the provider for a type. Lookups are created explicitly in a module using {@link
+ * com.google.inject.Binder#getProvider(Class) getProvider()} statements:
+ *
* <pre>
* Provider&lt;PaymentService&gt; paymentServiceProvider
* = getProvider(PaymentService.class);</pre>
@@ -52,6 +52,7 @@ public final class ProviderLookup<T> implements Element {
this.dependency = checkNotNull(dependency, "dependency");
}
+ @Override
public Object getSource() {
return source;
}
@@ -65,6 +66,7 @@ public final class ProviderLookup<T> implements Element {
return dependency;
}
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
@@ -79,6 +81,7 @@ public final class ProviderLookup<T> implements Element {
this.delegate = checkNotNull(delegate, "delegate");
}
+ @Override
public void applyTo(Binder binder) {
initializeDelegate(binder.withSource(getSource()).getProvider(dependency));
}
@@ -98,12 +101,17 @@ public final class ProviderLookup<T> implements Element {
*/
public Provider<T> getProvider() {
return new ProviderWithDependencies<T>() {
+ @Override
public T get() {
- checkState(delegate != null,
- "This Provider cannot be used until the Injector has been created.");
- return delegate.get();
+ Provider<T> local = delegate;
+ if (local == null) {
+ throw new IllegalStateException(
+ "This Provider cannot be used until the Injector has been created.");
+ }
+ return local.get();
}
+ @Override
public Set<Dependency<?>> getDependencies() {
// We depend on Provider<T>, not T directly. This is an important distinction
// for dependency analysis tools that short-circuit on providers.
@@ -111,7 +119,8 @@ public final class ProviderLookup<T> implements Element {
return ImmutableSet.<Dependency<?>>of(Dependency.get(providerKey));
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "Provider<" + getKey().getTypeLiteral() + ">";
}
};
diff --git a/core/src/com/google/inject/spi/ProviderWithDependencies.java b/core/src/com/google/inject/spi/ProviderWithDependencies.java
index be87379f..a47a051e 100644
--- a/core/src/com/google/inject/spi/ProviderWithDependencies.java
+++ b/core/src/com/google/inject/spi/ProviderWithDependencies.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/core/src/com/google/inject/spi/ProviderWithExtensionVisitor.java b/core/src/com/google/inject/spi/ProviderWithExtensionVisitor.java
index b835b715..2d3f3bee 100644
--- a/core/src/com/google/inject/spi/ProviderWithExtensionVisitor.java
+++ b/core/src/com/google/inject/spi/ProviderWithExtensionVisitor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,26 +20,25 @@ import com.google.inject.Binding;
import com.google.inject.Provider;
/**
- * A Provider that is part of an extension which supports a custom
- * BindingTargetVisitor.
- * <p>
- * When an extension binds a provider instance, the provider can implement this
- * interface to allow users using the
- * {@link Binding#acceptTargetVisitor(BindingTargetVisitor)} method to visit a
- * custom visitor designed for that extension. A typical implementation within
- * the extension would look like
- * <pre>
+ * A Provider that is part of an extension which supports a custom BindingTargetVisitor.
+ *
+ * <p>When an extension binds a provider instance, the provider can implement this interface to
+ * allow users using the {@link Binding#acceptTargetVisitor(BindingTargetVisitor)} method to visit a
+ * custom visitor designed for that extension. A typical implementation within the extension would
+ * look like
+ *
+ * <pre>
* &lt;V, B> V acceptExtensionVisitor(BindingTargetVisitor&lt;B, V> visitor, ProviderInstanceBinding&lt;? extends B> binding) {
* if(visitor instanceof MyCustomExtensionVisitor) {
* return ((MyCustomExtensionVisitor&lt;B, V>)visitor).visitCustomExtension(customProperties, binding);
* } else {
* return visitor.visit(binding);
* }
- * }</pre>
- * 'MyCustomExtensionVisitor' in the example above would be an interface the
- * extension provides that users can implement in order to be notified of custom
- * extension information. These visitor interfaces must extend from
- * BindingTargetVisitor.
+ * }</pre>
+ *
+ * 'MyCustomExtensionVisitor' in the example above would be an interface the extension provides that
+ * users can implement in order to be notified of custom extension information. These visitor
+ * interfaces must extend from BindingTargetVisitor.
*
* @since 3.0
* @author sameb@google.com (Sam Berlin)
@@ -47,15 +46,13 @@ import com.google.inject.Provider;
public interface ProviderWithExtensionVisitor<T> extends Provider<T> {
/**
- * Instructs the extension determine if the visitor is an instance of a custom
- * extension visitor, and if so, visit it using that method. If the visitor is
- * not an instance of the custom extension visitor, this method <b>MUST</b>
- * call visitor.visit(binding).
- * <p>
- * Due to issues with generics, the type parameters of this method do not
- * relate to the type of the provider. In practice, the 'B' type will always
- * be a supertype of 'T'.
+ * Instructs the extension determine if the visitor is an instance of a custom extension visitor,
+ * and if so, visit it using that method. If the visitor is not an instance of the custom
+ * extension visitor, this method <b>MUST</b> call visitor.visit(binding).
+ *
+ * <p>Due to issues with generics, the type parameters of this method do not relate to the type of
+ * the provider. In practice, the 'B' type will always be a supertype of 'T'.
*/
- <B, V> V acceptExtensionVisitor(BindingTargetVisitor<B, V> visitor,
- ProviderInstanceBinding<? extends B> binding);
+ <B, V> V acceptExtensionVisitor(
+ BindingTargetVisitor<B, V> visitor, ProviderInstanceBinding<? extends B> binding);
}
diff --git a/core/src/com/google/inject/spi/ProvidesMethodBinding.java b/core/src/com/google/inject/spi/ProvidesMethodBinding.java
index a862fcc6..ec56300a 100644
--- a/core/src/com/google/inject/spi/ProvidesMethodBinding.java
+++ b/core/src/com/google/inject/spi/ProvidesMethodBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,33 +18,32 @@ package com.google.inject.spi;
import com.google.inject.Key;
import com.google.inject.Provides;
-
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
- * An {@literal @}{@link Provides} binding or binding produced by a
- * {@link ModuleAnnotatedMethodScanner}.
+ * An {@literal @}{@link Provides} binding or binding produced by a {@link
+ * ModuleAnnotatedMethodScanner}.
*
* @since 4.0
* @author sameb@google.com (Sam Berlin)
*/
public interface ProvidesMethodBinding<T> extends HasDependencies {
-
+
/** Returns the method this binding uses. */
- Method getMethod();
-
+ Method getMethod();
+
/** Returns the instance of the object the method is defined in. */
Object getEnclosingInstance();
-
+
/** Returns the key of the binding. */
Key<T> getKey();
/**
* Returns the annotation that caused this binding to be created. For {@code @Provides} methods,
- * this is an instance of the {@code @Provides} annotation. For bindings from
- * {@link ModuleAnnotatedMethodScanner}, this is the annotation that caused the scanner to produce
- * the binding.
+ * this is an instance of the {@code @Provides} annotation. For bindings from {@link
+ * ModuleAnnotatedMethodScanner}, this is the annotation that caused the scanner to produce the
+ * binding.
*/
Annotation getAnnotation();
}
diff --git a/core/src/com/google/inject/spi/ProvidesMethodTargetVisitor.java b/core/src/com/google/inject/spi/ProvidesMethodTargetVisitor.java
index 62c87217..1a8c0f61 100644
--- a/core/src/com/google/inject/spi/ProvidesMethodTargetVisitor.java
+++ b/core/src/com/google/inject/spi/ProvidesMethodTargetVisitor.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2014 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,19 +17,18 @@
package com.google.inject.spi;
import com.google.inject.Provides;
-import com.google.inject.spi.BindingTargetVisitor;
/**
* A visitor for the {@literal @}{@link Provides} bindings.
- * <p>
- * If your {@link BindingTargetVisitor} implements this interface, bindings created by using
- * {@code @Provides} will be visited through this interface.
+ *
+ * <p>If your {@link com.google.inject.spi.BindingTargetVisitor} implements this interface, bindings
+ * created by using {@code @Provides} will be visited through this interface.
*
* @since 4.0
* @author sameb@google.com (Sam Berlin)
*/
public interface ProvidesMethodTargetVisitor<T, V> extends BindingTargetVisitor<T, V> {
-
+
/**
* Visits an {@link ProvidesMethodBinding} created with an {@literal @}{@link Provides} method.
*/
diff --git a/core/src/com/google/inject/spi/ProvisionListener.java b/core/src/com/google/inject/spi/ProvisionListener.java
index 274b8c39..3977224d 100644
--- a/core/src/com/google/inject/spi/ProvisionListener.java
+++ b/core/src/com/google/inject/spi/ProvisionListener.java
@@ -1,12 +1,12 @@
/*
* Copyright (C) 2011 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
@@ -20,32 +20,28 @@ import com.google.inject.Binding;
import com.google.inject.Provider;
import com.google.inject.Scope;
-import java.util.List;
-
/**
- * Listens for provisioning of objects. Useful for gathering timing information
- * about provisioning, post-provision initialization, and more.
- *
+ * Listens for provisioning of objects. Useful for gathering timing information about provisioning,
+ * post-provision initialization, and more.
+ *
* @author sameb@google.com (Sam Berlin)
* @since 4.0
*/
public interface ProvisionListener {
/**
- * Invoked by Guice when an object requires provisioning. Provisioning occurs
- * when Guice locates and injects the dependencies for a binding. For types
- * bound to a Provider, provisioning encapsulates the {@link Provider#get}
- * method. For toInstance or constant bindings, provisioning encapsulates
- * the injecting of {@literal @}{@code Inject}ed fields or methods.
- * For other types, provisioning encapsulates the construction of the
- * object. If a type is bound within a {@link Scope}, provisioning depends on
- * the scope. Types bound in Singleton scope will only be provisioned once.
- * Types bound in no scope will be provisioned every time they are injected.
+ * Invoked by Guice when an object requires provisioning. Provisioning occurs when Guice locates
+ * and injects the dependencies for a binding. For types bound to a Provider, provisioning
+ * encapsulates the {@link Provider#get} method. For toInstance or constant bindings, provisioning
+ * encapsulates the injecting of {@literal @}{@code Inject}ed fields or methods. For other types,
+ * provisioning encapsulates the construction of the object. If a type is bound within a {@link
+ * Scope}, provisioning depends on the scope. Types bound in Singleton scope will only be
+ * provisioned once. Types bound in no scope will be provisioned every time they are injected.
* Other scopes define their own behavior for provisioning.
- * <p>
- * To perform the provision, call {@link ProvisionInvocation#provision()}.
- * If you do not explicitly call provision, it will be automatically done after
- * this method returns. It is an error to call provision more than once.
+ *
+ * <p>To perform the provision, call {@link ProvisionInvocation#provision()}. If you do not
+ * explicitly call provision, it will be automatically done after this method returns. It is an
+ * error to call provision more than once.
*/
<T> void onProvision(ProvisionInvocation<T> provision);
@@ -53,22 +49,57 @@ public interface ProvisionListener {
* Encapsulates a single act of provisioning.
*
* @since 4.0
- */
+ */
public abstract static class ProvisionInvocation<T> {
/**
* Returns the Binding this is provisioning.
- * <p>
- * You must not call {@link Provider#get()} on the provider returned by
- * {@link Binding#getProvider}, otherwise you will get confusing error messages.
+ *
+ * <p>You must not call {@link Provider#get()} on the provider returned by {@link
+ * Binding#getProvider}, otherwise you will get confusing error messages.
*/
public abstract Binding<T> getBinding();
/** Performs the provision, returning the object provisioned. */
public abstract T provision();
-
- /** Returns the dependency chain that led to this object being provisioned. */
- public abstract List<DependencyAndSource> getDependencyChain();
-
+
+ /**
+ * Returns the dependency chain that led to this object being provisioned.
+ *
+ * @deprecated This method is planned for removal in Guice 4.4. Some use cases can be replaced
+ * by inferring the current chain via ThreadLocals in the listener, other use cases can use
+ * the static dependency graph. For example,
+ * <pre>{@code
+ * bindListener(Matchers.any(), new MyListener());
+ * ...
+ *
+ * private static final class MyListener implements ProvisionListener {
+ * private final ThreadLocal<ArrayDeque<Binding<?>>> bindingStack =
+ * new ThreadLocal<ArrayDeque<Binding<?>>>() {
+ * {@literal @}Override protected ArrayDeque<Binding<?>> initialValue() {
+ * return new ArrayDeque<>();
+ * }
+ * };
+ * {@literal @}Override public <T> void onProvision(ProvisionInvocation<T> invocation) {
+ * bindingStack.get().push(invocation.getBinding());
+ * try {
+ * invocation.provision();
+ * } finally {
+ * bindingStack.get().pop();
+ * }
+ * // Inspect the binding stack...
+ * }
+ * }
+ *
+ * }<pre>
+ *
+ * In this example the bindingStack thread local will contain a data structure that is very
+ * similar to the data returned by this list. The main differences are that linked keys are
+ * not in the stack, but such edges do exist in the static dependency graph (inspectable via
+ * {@link HasDependencies#getDependencies()}), so you could infer some of the missing edges..
+ */
+ @Deprecated
+ public abstract java.util.List<DependencyAndSource> getDependencyChain();
+
}
}
diff --git a/core/src/com/google/inject/spi/ProvisionListenerBinding.java b/core/src/com/google/inject/spi/ProvisionListenerBinding.java
index 4f349d49..d94d1830 100644
--- a/core/src/com/google/inject/spi/ProvisionListenerBinding.java
+++ b/core/src/com/google/inject/spi/ProvisionListenerBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2011 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,7 +20,6 @@ import com.google.common.collect.ImmutableList;
import com.google.inject.Binder;
import com.google.inject.Binding;
import com.google.inject.matcher.Matcher;
-
import java.util.List;
/**
@@ -36,9 +35,8 @@ public final class ProvisionListenerBinding implements Element {
private final Matcher<? super Binding<?>> bindingMatcher;
private final List<ProvisionListener> listeners;
- ProvisionListenerBinding(Object source,
- Matcher<? super Binding<?>> bindingMatcher,
- ProvisionListener[] listeners) {
+ ProvisionListenerBinding(
+ Object source, Matcher<? super Binding<?>> bindingMatcher, ProvisionListener[] listeners) {
this.source = source;
this.bindingMatcher = bindingMatcher;
this.listeners = ImmutableList.copyOf(listeners);
@@ -51,21 +49,25 @@ public final class ProvisionListenerBinding implements Element {
/**
* Returns the binding matcher which chooses which bindings the listener should be notified of.
- */
+ */
public Matcher<? super Binding<?>> getBindingMatcher() {
return bindingMatcher;
}
+ @Override
public Object getSource() {
return source;
}
+ @Override
public <R> R acceptVisitor(ElementVisitor<R> visitor) {
return visitor.visit(this);
}
+ @Override
public void applyTo(Binder binder) {
- binder.withSource(getSource()).bindListener(bindingMatcher,
- listeners.toArray(new ProvisionListener[listeners.size()]));
+ binder
+ .withSource(getSource())
+ .bindListener(bindingMatcher, listeners.toArray(new ProvisionListener[listeners.size()]));
}
}
diff --git a/core/src/com/google/inject/spi/RequireAtInjectOnConstructorsOption.java b/core/src/com/google/inject/spi/RequireAtInjectOnConstructorsOption.java
index 03d8c345..667df449 100644
--- a/core/src/com/google/inject/spi/RequireAtInjectOnConstructorsOption.java
+++ b/core/src/com/google/inject/spi/RequireAtInjectOnConstructorsOption.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -34,14 +34,17 @@ public final class RequireAtInjectOnConstructorsOption implements Element {
this.source = checkNotNull(source, "source");
}
+ @Override
public Object getSource() {
return source;
}
+ @Override
public void applyTo(Binder binder) {
binder.withSource(getSource()).requireAtInjectOnConstructors();
}
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
diff --git a/core/src/com/google/inject/spi/RequireExactBindingAnnotationsOption.java b/core/src/com/google/inject/spi/RequireExactBindingAnnotationsOption.java
index ee52cfc6..2cc91ffd 100644
--- a/core/src/com/google/inject/spi/RequireExactBindingAnnotationsOption.java
+++ b/core/src/com/google/inject/spi/RequireExactBindingAnnotationsOption.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,14 +33,17 @@ public final class RequireExactBindingAnnotationsOption implements Element {
this.source = checkNotNull(source, "source");
}
+ @Override
public Object getSource() {
return source;
}
+ @Override
public void applyTo(Binder binder) {
binder.withSource(getSource()).requireExactBindingAnnotations();
}
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
diff --git a/core/src/com/google/inject/spi/RequireExplicitBindingsOption.java b/core/src/com/google/inject/spi/RequireExplicitBindingsOption.java
index 5962eb79..ee6f2109 100644
--- a/core/src/com/google/inject/spi/RequireExplicitBindingsOption.java
+++ b/core/src/com/google/inject/spi/RequireExplicitBindingsOption.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -33,14 +33,17 @@ public final class RequireExplicitBindingsOption implements Element {
this.source = checkNotNull(source, "source");
}
+ @Override
public Object getSource() {
return source;
}
+ @Override
public void applyTo(Binder binder) {
binder.withSource(getSource()).requireExplicitBindings();
}
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
diff --git a/core/src/com/google/inject/spi/ScopeBinding.java b/core/src/com/google/inject/spi/ScopeBinding.java
index 86ed685c..563f5f56 100644
--- a/core/src/com/google/inject/spi/ScopeBinding.java
+++ b/core/src/com/google/inject/spi/ScopeBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,13 +20,13 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.inject.Binder;
import com.google.inject.Scope;
-
import java.lang.annotation.Annotation;
/**
* Registration of a scope annotation with the scope that implements it. Instances are created
* explicitly in a module using {@link com.google.inject.Binder#bindScope(Class, Scope) bindScope()}
* statements:
+ *
* <pre>
* Scope recordScope = new RecordScope();
* bindScope(RecordScoped.class, new RecordScope());</pre>
@@ -45,6 +45,7 @@ public final class ScopeBinding implements Element {
this.scope = checkNotNull(scope, "scope");
}
+ @Override
public Object getSource() {
return source;
}
@@ -57,10 +58,12 @@ public final class ScopeBinding implements Element {
return scope;
}
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
+ @Override
public void applyTo(Binder binder) {
binder.withSource(getSource()).bindScope(annotationType, scope);
}
diff --git a/core/src/com/google/inject/spi/StaticInjectionRequest.java b/core/src/com/google/inject/spi/StaticInjectionRequest.java
index 87e53763..fddba94f 100644
--- a/core/src/com/google/inject/spi/StaticInjectionRequest.java
+++ b/core/src/com/google/inject/spi/StaticInjectionRequest.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -20,13 +20,13 @@ import static com.google.common.base.Preconditions.checkNotNull;
import com.google.inject.Binder;
import com.google.inject.ConfigurationException;
-
import java.util.Set;
/**
- * A request to inject the static fields and methods of a type. Requests are created
- * explicitly in a module using {@link com.google.inject.Binder#requestStaticInjection(Class[])
+ * A request to inject the static fields and methods of a type. Requests are created explicitly in a
+ * module using {@link com.google.inject.Binder#requestStaticInjection(Class[])
* requestStaticInjection()} statements:
+ *
* <pre>
* requestStaticInjection(MyLegacyService.class);</pre>
*
@@ -42,6 +42,7 @@ public final class StaticInjectionRequest implements Element {
this.type = checkNotNull(type, "type");
}
+ @Override
public Object getSource() {
return source;
}
@@ -55,21 +56,23 @@ public final class StaticInjectionRequest implements Element {
* request.
*
* @return a possibly empty set of injection points. The set has a specified iteration order. All
- * fields are returned and then all methods. Within the fields, supertype fields are returned
- * before subtype fields. Similarly, supertype methods are returned before subtype methods.
+ * fields are returned and then all methods. Within the fields, supertype fields are returned
+ * before subtype fields. Similarly, supertype methods are returned before subtype methods.
* @throws ConfigurationException if there is a malformed injection point on {@code type}, such as
- * a field with multiple binding annotations. The exception's {@link
- * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>}
- * of the valid injection points.
+ * a field with multiple binding annotations. The exception's {@link
+ * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} of
+ * the valid injection points.
*/
public Set<InjectionPoint> getInjectionPoints() throws ConfigurationException {
return InjectionPoint.forStaticMethodsAndFields(type);
}
+ @Override
public void applyTo(Binder binder) {
binder.withSource(getSource()).requestStaticInjection(type);
}
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
diff --git a/core/src/com/google/inject/spi/Toolable.java b/core/src/com/google/inject/spi/Toolable.java
index ffabd9dd..d09ab307 100644
--- a/core/src/com/google/inject/spi/Toolable.java
+++ b/core/src/com/google/inject/spi/Toolable.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,7 +21,6 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.inject.Injector;
import com.google.inject.Stage;
-
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@@ -29,17 +28,16 @@ import java.lang.annotation.Target;
/**
* Instructs an {@link Injector} running in {@link Stage#TOOL} that a method should be injected.
* This is typically useful for for extensions to Guice that perform additional validation in an
- * injected method or field. This only applies to objects that are already constructed when
- * bindings are created (ie., something bound using {@link
+ * injected method or field. This only applies to objects that are already constructed when bindings
+ * are created (ie., something bound using {@link
* com.google.inject.binder.LinkedBindingBuilder#toProvider toProvider}, {@link
* com.google.inject.binder.LinkedBindingBuilder#toInstance toInstance}, or {@link
* com.google.inject.Binder#requestInjection requestInjection}.
- *
+ *
* @author sberlin@gmail.com (Sam Berlin)
* @since 3.0
*/
-@Target({ METHOD })
+@Target({METHOD})
@Retention(RUNTIME)
@Documented
-public @interface Toolable {
-}
+public @interface Toolable {}
diff --git a/core/src/com/google/inject/spi/TypeConverter.java b/core/src/com/google/inject/spi/TypeConverter.java
index 6dd07a39..473c0ad4 100644
--- a/core/src/com/google/inject/spi/TypeConverter.java
+++ b/core/src/com/google/inject/spi/TypeConverter.java
@@ -26,8 +26,6 @@ import com.google.inject.TypeLiteral;
*/
public interface TypeConverter {
- /**
- * Converts a string value. Throws an exception if a conversion error occurs.
- */
+ /** Converts a string value. Throws an exception if a conversion error occurs. */
Object convert(String value, TypeLiteral<?> toType);
}
diff --git a/core/src/com/google/inject/spi/TypeConverterBinding.java b/core/src/com/google/inject/spi/TypeConverterBinding.java
index 44786273..d54ad05e 100644
--- a/core/src/com/google/inject/spi/TypeConverterBinding.java
+++ b/core/src/com/google/inject/spi/TypeConverterBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,11 +24,13 @@ import com.google.inject.internal.Errors;
import com.google.inject.matcher.Matcher;
/**
- * Registration of type converters for matching target types. Instances are created
- * explicitly in a module using {@link com.google.inject.Binder#convertToTypes(Matcher,
- * TypeConverter) convertToTypes()} statements:
+ * Registration of type converters for matching target types. Instances are created explicitly in a
+ * module using {@link com.google.inject.Binder#convertToTypes(Matcher, TypeConverter)
+ * convertToTypes()} statements:
+ *
* <pre>
- * convertToTypes(Matchers.only(TypeLiteral.get(DateTime.class)), new DateTimeConverter());</pre>
+ * convertToTypes(Matchers.only(TypeLiteral.get(DateTime.class)), new DateTimeConverter());
+ * </pre>
*
* @author jessewilson@google.com (Jesse Wilson)
* @since 2.0
@@ -39,13 +41,14 @@ public final class TypeConverterBinding implements Element {
private final TypeConverter typeConverter;
/** @since 3.0 */
- public TypeConverterBinding(Object source, Matcher<? super TypeLiteral<?>> typeMatcher,
- TypeConverter typeConverter) {
+ public TypeConverterBinding(
+ Object source, Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter typeConverter) {
this.source = checkNotNull(source, "source");
this.typeMatcher = checkNotNull(typeMatcher, "typeMatcher");
this.typeConverter = checkNotNull(typeConverter, "typeConverter");
}
+ @Override
public Object getSource() {
return source;
}
@@ -58,16 +61,23 @@ public final class TypeConverterBinding implements Element {
return typeConverter;
}
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
+ @Override
public void applyTo(Binder binder) {
binder.withSource(getSource()).convertToTypes(typeMatcher, typeConverter);
}
- @Override public String toString() {
- return typeConverter + " which matches " + typeMatcher
- + " (bound at " + Errors.convert(source) + ")";
+ @Override
+ public String toString() {
+ return typeConverter
+ + " which matches "
+ + typeMatcher
+ + " (bound at "
+ + Errors.convert(source)
+ + ")";
}
}
diff --git a/core/src/com/google/inject/spi/TypeEncounter.java b/core/src/com/google/inject/spi/TypeEncounter.java
index 2ed0ee70..159d7671 100644
--- a/core/src/com/google/inject/spi/TypeEncounter.java
+++ b/core/src/com/google/inject/spi/TypeEncounter.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,13 +21,12 @@ import com.google.inject.MembersInjector;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.matcher.Matcher;
-
import java.lang.reflect.Method;
/**
* Context of an injectable type encounter. Enables reporting errors, registering injection
- * listeners and binding method interceptors for injectable type {@code I}. It is an error to use
- * an encounter after the {@link TypeListener#hear(TypeLiteral, TypeEncounter) hear()} method has
+ * listeners and binding method interceptors for injectable type {@code I}. It is an error to use an
+ * encounter after the {@link TypeListener#hear(TypeLiteral, TypeEncounter) hear()} method has
* returned.
*
* @param <I> the injectable type encountered
@@ -38,8 +37,8 @@ public interface TypeEncounter<I> {
/**
* Records an error message for type {@code I} which will be presented to the user at a later
* time. Unlike throwing an exception, this enable us to continue configuring the Injector and
- * discover more errors. Uses {@link String#format(String, Object[])} to insert the arguments
- * into the message.
+ * discover more errors. Uses {@link String#format(String, Object[])} to insert the arguments into
+ * the message.
*/
void addError(String message, Object... arguments);
@@ -50,9 +49,7 @@ public interface TypeEncounter<I> {
*/
void addError(Throwable t);
- /**
- * Records an error message to be presented to the user at a later time.
- */
+ /** Records an error message to be presented to the user at a later time. */
void addError(Message message);
/**
@@ -72,8 +69,8 @@ public interface TypeEncounter<I> {
/**
* Returns the members injector used to inject dependencies into methods and fields on instances
* of the given type {@code T}. The returned members injector will not be valid until the main
- * injector has been created. The members injector will throw an {@code IllegalStateException}
- * if you try to use it beforehand.
+ * injector has been created. The members injector will throw an {@code IllegalStateException} if
+ * you try to use it beforehand.
*
* @param typeLiteral type to get members injector for
*/
@@ -82,8 +79,8 @@ public interface TypeEncounter<I> {
/**
* Returns the members injector used to inject dependencies into methods and fields on instances
* of the given type {@code T}. The returned members injector will not be valid until the main
- * injector has been created. The members injector will throw an {@code IllegalStateException}
- * if you try to use it beforehand.
+ * injector has been created. The members injector will throw an {@code IllegalStateException} if
+ * you try to use it beforehand.
*
* @param type type to get members injector for
*/
@@ -103,20 +100,21 @@ public interface TypeEncounter<I> {
/*if[AOP]*/
/**
- * Binds method interceptor[s] to methods matched in type {@code I} and its supertypes. A
- * method is eligible for interception if:
+ * Binds method interceptor[s] to methods matched in type {@code I} and its supertypes. A method
+ * is eligible for interception if:
*
* <ul>
- * <li>Guice created the instance the method is on</li>
- * <li>Neither the enclosing type nor the method is final</li>
- * <li>And the method is package-private or more accessible</li>
+ * <li>Guice created the instance the method is on
+ * <li>Neither the enclosing type nor the method is final
+ * <li>And the method is package-private or more accessible
* </ul>
*
- * @param methodMatcher matches methods the interceptor should apply to. For
- * example: {@code annotatedWith(Transactional.class)}.
+ * @param methodMatcher matches methods the interceptor should apply to. For example: {@code
+ * annotatedWith(Transactional.class)}.
* @param interceptors to bind
*/
- void bindInterceptor(Matcher<? super Method> methodMatcher,
+ void bindInterceptor(
+ Matcher<? super Method> methodMatcher,
org.aopalliance.intercept.MethodInterceptor... interceptors);
/*end[AOP]*/
}
diff --git a/core/src/com/google/inject/spi/TypeListener.java b/core/src/com/google/inject/spi/TypeListener.java
index ed9d8d32..b0195ab8 100644
--- a/core/src/com/google/inject/spi/TypeListener.java
+++ b/core/src/com/google/inject/spi/TypeListener.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,24 +25,22 @@ import com.google.inject.TypeLiteral;
*
* <p>Useful for extra type checking, {@linkplain TypeEncounter#register(InjectionListener)
* registering injection listeners}, and {@linkplain TypeEncounter#bindInterceptor(
- * com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[])
- * binding method interceptors}.
- *
+ * com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[]) binding method
+ * interceptors}.
+ *
* @since 2.0
*/
public interface TypeListener {
/**
- * Invoked when Guice encounters a new type eligible for constructor or members injection.
- * Called during injector creation (or afterwords if Guice encounters a type at run time and
- * creates a JIT binding).
+ * Invoked when Guice encounters a new type eligible for constructor or members injection. Called
+ * during injector creation (or afterwards if Guice encounters a type at run time and creates a
+ * JIT binding).
*
* @param type encountered by Guice
* @param encounter context of this encounter, enables reporting errors, registering injection
* listeners and binding method interceptors for {@code type}.
- *
* @param <I> the injectable type
*/
<I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter);
-
}
diff --git a/core/src/com/google/inject/spi/TypeListenerBinding.java b/core/src/com/google/inject/spi/TypeListenerBinding.java
index 8ad46729..ec609cb2 100644
--- a/core/src/com/google/inject/spi/TypeListenerBinding.java
+++ b/core/src/com/google/inject/spi/TypeListenerBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2009 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -36,8 +36,8 @@ public final class TypeListenerBinding implements Element {
private final Matcher<? super TypeLiteral<?>> typeMatcher;
private final TypeListener listener;
- TypeListenerBinding(Object source, TypeListener listener,
- Matcher<? super TypeLiteral<?>> typeMatcher) {
+ TypeListenerBinding(
+ Object source, TypeListener listener, Matcher<? super TypeLiteral<?>> typeMatcher) {
this.source = source;
this.listener = listener;
this.typeMatcher = typeMatcher;
@@ -53,14 +53,17 @@ public final class TypeListenerBinding implements Element {
return typeMatcher;
}
+ @Override
public Object getSource() {
return source;
}
+ @Override
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
+ @Override
public void applyTo(Binder binder) {
binder.withSource(getSource()).bindListener(typeMatcher, listener);
}
diff --git a/core/src/com/google/inject/spi/UntargettedBinding.java b/core/src/com/google/inject/spi/UntargettedBinding.java
index 4f6f8233..c605c941 100644
--- a/core/src/com/google/inject/spi/UntargettedBinding.java
+++ b/core/src/com/google/inject/spi/UntargettedBinding.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/core/src/com/google/inject/spi/package-info.java b/core/src/com/google/inject/spi/package-info.java
index 12248376..c217d264 100644
--- a/core/src/com/google/inject/spi/package-info.java
+++ b/core/src/com/google/inject/spi/package-info.java
@@ -14,7 +14,5 @@
* limitations under the License.
*/
-/**
- * Guice service provider interface
- */
+/** Guice service provider interface */
package com.google.inject.spi;
diff --git a/core/src/com/google/inject/util/Modules.java b/core/src/com/google/inject/util/Modules.java
index 08ec92c7..5378392f 100644
--- a/core/src/com/google/inject/util/Modules.java
+++ b/core/src/com/google/inject/util/Modules.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -39,7 +39,6 @@ import com.google.inject.spi.Elements;
import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding;
import com.google.inject.spi.PrivateElements;
import com.google.inject.spi.ScopeBinding;
-
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.LinkedHashSet;
@@ -55,19 +54,22 @@ import java.util.Set;
*/
public final class Modules {
private Modules() {}
-
+
public static final Module EMPTY_MODULE = new EmptyModule();
+
private static class EmptyModule implements Module {
+ @Override
public void configure(Binder binder) {}
}
/**
- * Returns a builder that creates a module that overlays override modules over the given
- * modules. If a key is bound in both sets of modules, only the binding from the override modules
- * is kept. If a single {@link PrivateModule} is supplied or all elements are from
- * a single {@link PrivateBinder}, then this will overwrite the private bindings.
- * Otherwise, private bindings will not be overwritten unless they are exposed.
- * This can be used to replace the bindings of a production module with test bindings:
+ * Returns a builder that creates a module that overlays override modules over the given modules.
+ * If a key is bound in both sets of modules, only the binding from the override modules is kept.
+ * If a single {@link PrivateModule} is supplied or all elements are from a single {@link
+ * PrivateBinder}, then this will overwrite the private bindings. Otherwise, private bindings will
+ * not be overwritten unless they are exposed. This can be used to replace the bindings of a
+ * production module with test bindings:
+ *
* <pre>
* Module functionalTestModule
* = Modules.override(new ProductionModule()).with(new TestModule());
@@ -82,12 +84,13 @@ public final class Modules {
}
/**
- * Returns a builder that creates a module that overlays override modules over the given
- * modules. If a key is bound in both sets of modules, only the binding from the override modules
- * is kept. If a single {@link PrivateModule} is supplied or all elements are from
- * a single {@link PrivateBinder}, then this will overwrite the private bindings.
- * Otherwise, private bindings will not be overwritten unless they are exposed.
- * This can be used to replace the bindings of a production module with test bindings:
+ * Returns a builder that creates a module that overlays override modules over the given modules.
+ * If a key is bound in both sets of modules, only the binding from the override modules is kept.
+ * If a single {@link PrivateModule} is supplied or all elements are from a single {@link
+ * PrivateBinder}, then this will overwrite the private bindings. Otherwise, private bindings will
+ * not be overwritten unless they are exposed. This can be used to replace the bindings of a
+ * production module with test bindings:
+ *
* <pre>
* Module functionalTestModule
* = Modules.override(getProductionModules()).with(getTestModules());
@@ -101,27 +104,24 @@ public final class Modules {
return new RealOverriddenModuleBuilder(modules);
}
- /**
- * Returns a new module that installs all of {@code modules}.
- */
+ /** Returns a new module that installs all of {@code modules}. */
public static Module combine(Module... modules) {
return combine(ImmutableSet.copyOf(modules));
}
- /**
- * Returns a new module that installs all of {@code modules}.
- */
+ /** Returns a new module that installs all of {@code modules}. */
public static Module combine(Iterable<? extends Module> modules) {
return new CombinedModule(modules);
}
-
+
private static class CombinedModule implements Module {
final Set<Module> modulesSet;
-
+
CombinedModule(Iterable<? extends Module> modules) {
this.modulesSet = ImmutableSet.copyOf(modules);
}
-
+
+ @Override
public void configure(Binder binder) {
binder = binder.skipSources(getClass());
for (Module module : modulesSet) {
@@ -130,19 +130,13 @@ public final class Modules {
}
}
- /**
- * See the EDSL example at {@link Modules#override(Module[]) override()}.
- */
+ /** See the EDSL example at {@link Modules#override(Module[]) override()}. */
public interface OverriddenModuleBuilder {
- /**
- * See the EDSL example at {@link Modules#override(Module[]) override()}.
- */
+ /** See the EDSL example at {@link Modules#override(Module[]) override()}. */
Module with(Module... overrides);
- /**
- * See the EDSL example at {@link Modules#override(Module[]) override()}.
- */
+ /** See the EDSL example at {@link Modules#override(Module[]) override()}. */
Module with(Iterable<? extends Module> overrides);
}
@@ -153,19 +147,21 @@ public final class Modules {
this.baseModules = ImmutableSet.copyOf(baseModules);
}
+ @Override
public Module with(Module... overrides) {
return with(Arrays.asList(overrides));
}
+ @Override
public Module with(Iterable<? extends Module> overrides) {
return new OverrideModule(overrides, baseModules);
}
}
-
+
static class OverrideModule extends AbstractModule {
private final ImmutableSet<Module> overrides;
private final ImmutableSet<Module> baseModules;
-
+
OverrideModule(Iterable<? extends Module> overrides, ImmutableSet<Module> baseModules) {
this.overrides = ImmutableSet.copyOf(overrides);
this.baseModules = baseModules;
@@ -179,24 +175,27 @@ public final class Modules {
// If the sole element was a PrivateElements, we want to override
// the private elements within that -- so refocus our elements
// and binder.
- if(baseElements.size() == 1) {
+ if (baseElements.size() == 1) {
Element element = Iterables.getOnlyElement(baseElements);
- if(element instanceof PrivateElements) {
- PrivateElements privateElements = (PrivateElements)element;
- PrivateBinder privateBinder = baseBinder.newPrivateBinder().withSource(privateElements.getSource());
- for(Key exposed : privateElements.getExposedKeys()) {
+ if (element instanceof PrivateElements) {
+ PrivateElements privateElements = (PrivateElements) element;
+ PrivateBinder privateBinder =
+ baseBinder.newPrivateBinder().withSource(privateElements.getSource());
+ for (Key exposed : privateElements.getExposedKeys()) {
privateBinder.withSource(privateElements.getExposedSource(exposed)).expose(exposed);
}
baseBinder = privateBinder;
baseElements = privateElements.getElements();
}
}
-
+
final Binder binder = baseBinder.skipSources(this.getClass());
- final LinkedHashSet<Element> elements = new LinkedHashSet<Element>(baseElements);
+ final LinkedHashSet<Element> elements = new LinkedHashSet<>(baseElements);
final Module scannersModule = extractScanners(elements);
- final List<Element> overrideElements = Elements.getElements(currentStage(),
- ImmutableList.<Module>builder().addAll(overrides).add(scannersModule).build());
+ final List<Element> overrideElements =
+ Elements.getElements(
+ currentStage(),
+ ImmutableList.<Module>builder().addAll(overrides).add(scannersModule).build());
final Set<Key<?>> overriddenKeys = Sets.newHashSet();
final Map<Class<? extends Annotation>, ScopeBinding> overridesScopeAnnotations =
@@ -204,17 +203,20 @@ public final class Modules {
// execute the overrides module, keeping track of which keys and scopes are bound
new ModuleWriter(binder) {
- @Override public <T> Void visit(Binding<T> binding) {
+ @Override
+ public <T> Void visit(Binding<T> binding) {
overriddenKeys.add(binding.getKey());
return super.visit(binding);
}
- @Override public Void visit(ScopeBinding scopeBinding) {
+ @Override
+ public Void visit(ScopeBinding scopeBinding) {
overridesScopeAnnotations.put(scopeBinding.getAnnotationType(), scopeBinding);
return super.visit(scopeBinding);
}
- @Override public Void visit(PrivateElements privateElements) {
+ @Override
+ public Void visit(PrivateElements privateElements) {
overriddenKeys.addAll(privateElements.getExposedKeys());
return super.visit(privateElements);
}
@@ -226,7 +228,8 @@ public final class Modules {
final Map<Scope, List<Object>> scopeInstancesInUse = Maps.newHashMap();
final List<ScopeBinding> scopeBindings = Lists.newArrayList();
new ModuleWriter(binder) {
- @Override public <T> Void visit(Binding<T> binding) {
+ @Override
+ public <T> Void visit(Binding<T> binding) {
if (!overriddenKeys.remove(binding.getKey())) {
super.visit(binding);
@@ -246,8 +249,8 @@ public final class Modules {
}
void rewrite(Binder binder, PrivateElements privateElements, Set<Key<?>> keysToSkip) {
- PrivateBinder privateBinder = binder.withSource(privateElements.getSource())
- .newPrivateBinder();
+ PrivateBinder privateBinder =
+ binder.withSource(privateElements.getSource()).newPrivateBinder();
Set<Key<?>> skippedExposes = Sets.newHashSet();
@@ -260,8 +263,7 @@ public final class Modules {
}
for (Element element : privateElements.getElements()) {
- if (element instanceof Binding
- && skippedExposes.remove(((Binding) element).getKey())) {
+ if (element instanceof Binding && skippedExposes.remove(((Binding) element).getKey())) {
continue;
}
if (element instanceof PrivateElements) {
@@ -272,12 +274,14 @@ public final class Modules {
}
}
- @Override public Void visit(PrivateElements privateElements) {
+ @Override
+ public Void visit(PrivateElements privateElements) {
rewrite(binder, privateElements, overriddenKeys);
return null;
}
- @Override public Void visit(ScopeBinding scopeBinding) {
+ @Override
+ public Void visit(ScopeBinding scopeBinding) {
scopeBindings.add(scopeBinding);
return null;
}
@@ -286,7 +290,8 @@ public final class Modules {
// execute the scope bindings, skipping scopes that have been overridden. Any scope that
// is overridden and in active use will prompt an error
new ModuleWriter(binder) {
- @Override public Void visit(ScopeBinding scopeBinding) {
+ @Override
+ public Void visit(ScopeBinding scopeBinding) {
ScopeBinding overideBinding =
overridesScopeAnnotations.remove(scopeBinding.getAnnotationType());
if (overideBinding == null) {
@@ -294,13 +299,15 @@ public final class Modules {
} else {
List<Object> usedSources = scopeInstancesInUse.get(scopeBinding.getScope());
if (usedSources != null) {
- StringBuilder sb = new StringBuilder(
- "The scope for @%s is bound directly and cannot be overridden.");
+ StringBuilder sb =
+ new StringBuilder(
+ "The scope for @%s is bound directly and cannot be overridden.");
sb.append("%n original binding at " + Errors.convert(scopeBinding.getSource()));
for (Object usedSource : usedSources) {
sb.append("%n bound directly at " + Errors.convert(usedSource) + "");
}
- binder.withSource(overideBinding.getSource())
+ binder
+ .withSource(overideBinding.getSource())
.addError(sb.toString(), scopeBinding.getAnnotationType().getSimpleName());
}
}
@@ -310,11 +317,13 @@ public final class Modules {
}
private Scope getScopeInstanceOrNull(Binding<?> binding) {
- return binding.acceptScopingVisitor(new DefaultBindingScopingVisitor<Scope>() {
- @Override public Scope visitScope(Scope scope) {
- return scope;
- }
- });
+ return binding.acceptScopingVisitor(
+ new DefaultBindingScopingVisitor<Scope>() {
+ @Override
+ public Scope visitScope(Scope scope) {
+ return scope;
+ }
+ });
}
}
@@ -325,7 +334,8 @@ public final class Modules {
this.binder = binder.skipSources(this.getClass());
}
- @Override protected Void visitOther(Element element) {
+ @Override
+ protected Void visitOther(Element element) {
element.applyTo(binder);
return null;
}
@@ -339,17 +349,20 @@ public final class Modules {
private static Module extractScanners(Iterable<Element> elements) {
final List<ModuleAnnotatedMethodScannerBinding> scanners = Lists.newArrayList();
- ElementVisitor<Void> visitor = new DefaultElementVisitor<Void>() {
- @Override public Void visit(ModuleAnnotatedMethodScannerBinding binding) {
- scanners.add(binding);
- return null;
- }
- };
+ ElementVisitor<Void> visitor =
+ new DefaultElementVisitor<Void>() {
+ @Override
+ public Void visit(ModuleAnnotatedMethodScannerBinding binding) {
+ scanners.add(binding);
+ return null;
+ }
+ };
for (Element element : elements) {
element.acceptVisitor(visitor);
}
return new AbstractModule() {
- @Override protected void configure() {
+ @Override
+ protected void configure() {
for (ModuleAnnotatedMethodScannerBinding scanner : scanners) {
scanner.applyTo(binder());
}
diff --git a/core/src/com/google/inject/util/Providers.java b/core/src/com/google/inject/util/Providers.java
index c18d3512..f8c5d219 100644
--- a/core/src/com/google/inject/util/Providers.java
+++ b/core/src/com/google/inject/util/Providers.java
@@ -27,12 +27,10 @@ import com.google.inject.Provider;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.ProviderWithDependencies;
-
import java.util.Set;
/**
- * Static utility methods for creating and working with instances of
- * {@link Provider}.
+ * Static utility methods for creating and working with instances of {@link Provider}.
*
* @author Kevin Bourrillion (kevinb9n@gmail.com)
* @since 2.0
@@ -42,13 +40,12 @@ public final class Providers {
private Providers() {}
/**
- * Returns a provider which always provides {@code instance}. This should not
- * be necessary to use in your application, but is helpful for several types
- * of unit tests.
+ * Returns a provider which always provides {@code instance}. This should not be necessary to use
+ * in your application, but is helpful for several types of unit tests.
*
- * @param instance the instance that should always be provided. This is also
- * permitted to be null, to enable aggressive testing, although in real
- * life a Guice-supplied Provider will never return null.
+ * @param instance the instance that should always be provided. This is also permitted to be null,
+ * to enable aggressive testing, although in real life a Guice-supplied Provider will never
+ * return null.
*/
public static <T> Provider<T> of(final T instance) {
return new ConstantProvider<T>(instance);
@@ -61,46 +58,50 @@ public final class Providers {
this.instance = instance;
}
+ @Override
public T get() {
return instance;
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "of(" + instance + ")";
}
- @Override public boolean equals(Object obj) {
+ @Override
+ public boolean equals(Object obj) {
return (obj instanceof ConstantProvider)
&& Objects.equal(instance, ((ConstantProvider<?>) obj).instance);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return Objects.hashCode(instance);
}
}
/**
- * Returns a Guice-friendly {@code com.google.inject.Provider} for the given
- * JSR-330 {@code javax.inject.Provider}. The converse method is unnecessary,
- * since Guice providers directly implement the JSR-330 interface.
- *
+ * Returns a Guice-friendly {@code com.google.inject.Provider} for the given JSR-330 {@code
+ * javax.inject.Provider}. The converse method is unnecessary, since Guice providers directly
+ * implement the JSR-330 interface.
+ *
* @since 3.0
*/
public static <T> Provider<T> guicify(javax.inject.Provider<T> provider) {
if (provider instanceof Provider) {
return (Provider<T>) provider;
}
-
+
final javax.inject.Provider<T> delegate = checkNotNull(provider, "provider");
-
+
// Ensure that we inject all injection points from the delegate provider.
Set<InjectionPoint> injectionPoints =
InjectionPoint.forInstanceMethodsAndFields(provider.getClass());
- if(injectionPoints.isEmpty()) {
+ if (injectionPoints.isEmpty()) {
return new GuicifiedProvider<T>(delegate);
} else {
Set<Dependency<?>> mutableDeps = Sets.newHashSet();
- for(InjectionPoint ip : injectionPoints) {
+ for (InjectionPoint ip : injectionPoints) {
mutableDeps.addAll(ip.getDependencies());
}
final Set<Dependency<?>> dependencies = ImmutableSet.copyOf(mutableDeps);
@@ -115,30 +116,34 @@ public final class Providers {
this.delegate = delegate;
}
+ @Override
public T get() {
return delegate.get();
}
- @Override public String toString() {
+ @Override
+ public String toString() {
return "guicified(" + delegate + ")";
}
- @Override public boolean equals(Object obj) {
+ @Override
+ public boolean equals(Object obj) {
return (obj instanceof GuicifiedProvider)
&& Objects.equal(delegate, ((GuicifiedProvider<?>) obj).delegate);
}
- @Override public int hashCode() {
+ @Override
+ public int hashCode() {
return Objects.hashCode(delegate);
}
}
- private static final class GuicifiedProviderWithDependencies<T>
- extends GuicifiedProvider<T> implements ProviderWithDependencies<T> {
+ private static final class GuicifiedProviderWithDependencies<T> extends GuicifiedProvider<T>
+ implements ProviderWithDependencies<T> {
private final Set<Dependency<?>> dependencies;
- private GuicifiedProviderWithDependencies(Set<Dependency<?>> dependencies,
- javax.inject.Provider<T> delegate) {
+ private GuicifiedProviderWithDependencies(
+ Set<Dependency<?>> dependencies, javax.inject.Provider<T> delegate) {
super(delegate);
this.dependencies = dependencies;
}
@@ -149,6 +154,7 @@ public final class Providers {
injector.injectMembers(delegate);
}
+ @Override
public Set<Dependency<?>> getDependencies() {
return dependencies;
}
diff --git a/core/src/com/google/inject/util/Types.java b/core/src/com/google/inject/util/Types.java
index c3b3a2af..32714cc7 100644
--- a/core/src/com/google/inject/util/Types.java
+++ b/core/src/com/google/inject/util/Types.java
@@ -1,4 +1,4 @@
-/**
+/*
* Copyright (C) 2008 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,7 +14,6 @@
* limitations under the License.
*/
-
package com.google.inject.util;
import com.google.inject.Provider;
@@ -22,11 +21,11 @@ import com.google.inject.internal.MoreTypes;
import com.google.inject.internal.MoreTypes.GenericArrayTypeImpl;
import com.google.inject.internal.MoreTypes.ParameterizedTypeImpl;
import com.google.inject.internal.MoreTypes.WildcardTypeImpl;
-
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -41,8 +40,8 @@ public final class Types {
private Types() {}
/**
- * Returns a new parameterized type, applying {@code typeArguments} to
- * {@code rawType}. The returned type does not have an owner type.
+ * Returns a new parameterized type, applying {@code typeArguments} to {@code rawType}. The
+ * returned type does not have an owner type.
*
* @return a {@link java.io.Serializable serializable} parameterized type.
*/
@@ -51,8 +50,8 @@ public final class Types {
}
/**
- * Returns a new parameterized type, applying {@code typeArguments} to
- * {@code rawType} and enclosed by {@code ownerType}.
+ * Returns a new parameterized type, applying {@code typeArguments} to {@code rawType} and
+ * enclosed by {@code ownerType}.
*
* @return a {@link java.io.Serializable serializable} parameterized type.
*/
@@ -62,8 +61,7 @@ public final class Types {
}
/**
- * Returns an array type whose elements are all instances of
- * {@code componentType}.
+ * Returns an array type whose elements are all instances of {@code componentType}.
*
* @return a {@link java.io.Serializable serializable} generic array type.
*/
@@ -72,27 +70,25 @@ public final class Types {
}
/**
- * Returns a type that represents an unknown type that extends {@code bound}.
- * For example, if {@code bound} is {@code CharSequence.class}, this returns
- * {@code ? extends CharSequence}. If {@code bound} is {@code Object.class},
- * this returns {@code ?}, which is shorthand for {@code ? extends Object}.
+ * Returns a type that represents an unknown type that extends {@code bound}. For example, if
+ * {@code bound} is {@code CharSequence.class}, this returns {@code ? extends CharSequence}. If
+ * {@code bound} is {@code Object.class}, this returns {@code ?}, which is shorthand for {@code ?
+ * extends Object}.
*/
public static WildcardType subtypeOf(Type bound) {
- return new WildcardTypeImpl(new Type[] { bound }, MoreTypes.EMPTY_TYPE_ARRAY);
+ return new WildcardTypeImpl(new Type[] {bound}, MoreTypes.EMPTY_TYPE_ARRAY);
}
/**
- * Returns a type that represents an unknown supertype of {@code bound}. For
- * example, if {@code bound} is {@code String.class}, this returns {@code ?
- * super String}.
+ * Returns a type that represents an unknown supertype of {@code bound}. For example, if {@code
+ * bound} is {@code String.class}, this returns {@code ? super String}.
*/
public static WildcardType supertypeOf(Type bound) {
- return new WildcardTypeImpl(new Type[] { Object.class }, new Type[] { bound });
+ return new WildcardTypeImpl(new Type[] {Object.class}, new Type[] {bound});
}
/**
- * Returns a type modelling a {@link List} whose elements are of type
- * {@code elementType}.
+ * Returns a type modelling a {@link List} whose elements are of type {@code elementType}.
*
* @return a {@link java.io.Serializable serializable} parameterized type.
*/
@@ -101,8 +97,16 @@ public final class Types {
}
/**
- * Returns a type modelling a {@link Set} whose elements are of type
- * {@code elementType}.
+ * Returns a type modelling a {@link Collection} whose elements are of type {@code elementType}.
+ *
+ * @return a {@link java.io.Serializable serializable} parameterized type.
+ */
+ public static ParameterizedType collectionOf(Type elementType) {
+ return newParameterizedType(Collection.class, elementType);
+ }
+
+ /**
+ * Returns a type modelling a {@link Set} whose elements are of type {@code elementType}.
*
* @return a {@link java.io.Serializable serializable} parameterized type.
*/
@@ -111,8 +115,8 @@ public final class Types {
}
/**
- * Returns a type modelling a {@link Map} whose keys are of type
- * {@code keyType} and whose values are of type {@code valueType}.
+ * Returns a type modelling a {@link Map} whose keys are of type {@code keyType} and whose values
+ * are of type {@code valueType}.
*
* @return a {@link java.io.Serializable serializable} parameterized type.
*/
@@ -123,12 +127,21 @@ public final class Types {
// for other custom collections types, use newParameterizedType()
/**
- * Returns a type modelling a {@link Provider} that provides elements of type
- * {@code elementType}.
+ * Returns a type modelling a {@link Provider} that provides elements of type {@code elementType}.
*
* @return a {@link java.io.Serializable serializable} parameterized type.
*/
public static ParameterizedType providerOf(Type providedType) {
return newParameterizedType(Provider.class, providedType);
}
-} \ No newline at end of file
+
+ /**
+ * Returns a type modelling a {@link javax.inject.Provider} that provides elements of type {@code
+ * elementType}.
+ *
+ * @return a {@link java.io.Serializable serializable} parameterized type.
+ */
+ public static Type javaxProviderOf(Type type) {
+ return Types.newParameterizedType(javax.inject.Provider.class, type);
+ }
+}
diff --git a/core/src/com/google/inject/util/package-info.java b/core/src/com/google/inject/util/package-info.java
index 89c5de22..3ebb87cb 100644
--- a/core/src/com/google/inject/util/package-info.java
+++ b/core/src/com/google/inject/util/package-info.java
@@ -14,7 +14,5 @@
* limitations under the License.
*/
-/**
- * Helper methods for working with Guice.
- */
-package com.google.inject.util; \ No newline at end of file
+/** Helper methods for working with Guice. */
+package com.google.inject.util;