This CL changes how singletons are loaded. Previously we registered a callback at bind-time. Now we keep track of whether bindings were eager (using the new enum LoadStrategy) and we load 'em all afterwards.
git-svn-id: https://google-guice.googlecode.com/svn/trunk@498 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/src/com/google/inject/BindCommandProcessor.java b/src/com/google/inject/BindCommandProcessor.java
index 008f6c8..f1fab1e 100644
--- a/src/com/google/inject/BindCommandProcessor.java
+++ b/src/com/google/inject/BindCommandProcessor.java
@@ -20,7 +20,10 @@
import com.google.inject.commands.BindConstantCommand;
import com.google.inject.commands.BindScoping;
import com.google.inject.commands.BindTarget;
-import com.google.inject.internal.*;
+import com.google.inject.internal.Annotations;
+import com.google.inject.internal.ErrorMessages;
+import com.google.inject.internal.ResolveFailedException;
+import com.google.inject.internal.StackTraceElements;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
@@ -38,8 +41,6 @@
private final Map<Class<? extends Annotation>, Scope> scopes;
private final List<CreationListener> creationListeners
= new ArrayList<CreationListener>();
- private final List<ContextualCallable<Void>> eagerSingletonCreators
- = new ArrayList<ContextualCallable<Void>>();
private final Stage stage;
private final Map<Key<?>, BindingImpl<?>> bindings;
private final Map<Object, Void> outstandingInjections;
@@ -71,8 +72,9 @@
validateKey(command.getSource(), command.getKey());
- // TODO(jessewilson): Scope annotation on type, like @Singleton
- final boolean shouldPreload = command.getScoping().isEagerSingleton();
+ final LoadStrategy loadStrategy = command.getScoping().isEagerSingleton()
+ ? LoadStrategy.EAGER
+ : LoadStrategy.LAZY;
final Scope scope = command.getScoping().acceptVisitor(new BindScoping.Visitor<Scope>() {
public Scope visitEagerSingleton() {
return Scopes.SINGLETON;
@@ -104,8 +106,8 @@
outstandingInjections.put(instance, null);
InternalFactory<? extends T> scopedFactory
= Scopes.scope(key, injector, factory, scope);
- createBinding(source, shouldPreload, new InstanceBindingImpl<T>(
- injector, key, source, scopedFactory, instance));
+ putBinding(new InstanceBindingImpl<T>(
+ injector, key, source, scopedFactory, instance));
return null;
}
@@ -115,8 +117,8 @@
outstandingInjections.put(provider, null);
InternalFactory<? extends T> scopedFactory
= Scopes.scope(key, injector, factory, scope);
- createBinding(source, shouldPreload, new ProviderInstanceBindingImpl<T>(
- injector, key, source, scopedFactory, scope, provider));
+ putBinding(new ProviderInstanceBindingImpl<T>(
+ injector, key, source, scopedFactory, scope, provider, loadStrategy));
return null;
}
@@ -126,8 +128,8 @@
creationListeners.add(boundProviderFactory);
InternalFactory<? extends T> scopedFactory = Scopes.scope(
key, injector, (InternalFactory<? extends T>) boundProviderFactory, scope);
- createBinding(source, shouldPreload, new LinkedProviderBindingImpl<T>(
- injector, key, source, scopedFactory, scope, providerKey));
+ putBinding(new LinkedProviderBindingImpl<T>(
+ injector, key, source, scopedFactory, scope, providerKey, loadStrategy));
return null;
}
@@ -140,8 +142,8 @@
creationListeners.add(factory);
InternalFactory<? extends T> scopedFactory
= Scopes.scope(key, injector, factory, scope);
- createBinding(source, shouldPreload, new LinkedBindingImpl<T>(
- injector, key, source, scopedFactory, scope, targetKey));
+ putBinding(new LinkedBindingImpl<T>(
+ injector, key, source, scopedFactory, scope, targetKey, loadStrategy));
return null;
}
@@ -154,7 +156,7 @@
// @ImplementedBy annotation or something.
if (key.hasAnnotationType() || !(type instanceof Class<?>)) {
addError(source, ErrorMessages.MISSING_IMPLEMENTATION);
- createBinding(source, shouldPreload, invalidBinding(injector, key, source));
+ putBinding(invalidBinding(injector, key, source));
return null;
}
@@ -163,11 +165,11 @@
Class<T> clazz = (Class<T>) type;
final BindingImpl<T> binding;
try {
- binding = injector.createUnitializedBinding(clazz, scope, source);
- createBinding(source, shouldPreload, binding);
+ binding = injector.createUnitializedBinding(clazz, scope, source, loadStrategy);
+ putBinding(binding);
} catch (ResolveFailedException e) {
injector.errorHandler.handle(source, e.getMessage());
- createBinding(source, shouldPreload, invalidBinding(injector, key, source));
+ putBinding(invalidBinding(injector, key, source));
return null;
}
@@ -224,31 +226,33 @@
return true;
}
- private <T> void createBinding(Object source, boolean shouldPreload,
- BindingImpl<T> binding) {
- putBinding(binding);
-
- // Register to preload if necessary.
- if (binding.getScope() == Scopes.SINGLETON) {
- if (stage == Stage.PRODUCTION || shouldPreload) {
- eagerSingletonCreators.add(new EagerSingletonCreator(binding.key, binding.internalFactory));
- }
- } else {
- if (shouldPreload) {
- addError(source, ErrorMessages.PRELOAD_NOT_ALLOWED);
- }
- }
- }
-
public void createUntargettedBindings() {
for (Runnable untargettedBinding : untargettedBindings) {
untargettedBinding.run();
}
}
- public void createEagerSingletons(InjectorImpl injector) {
- for (ContextualCallable<Void> preloader : eagerSingletonCreators) {
- injector.callInContext(preloader);
+ public void loadEagerSingletons(InjectorImpl injector) {
+ // load eager singletons, or all singletons if we're in Stage.PRODUCTION.
+ for (final BindingImpl<?> binding : bindings.values()) {
+ if (stage == Stage.PRODUCTION || binding.getLoadStrategy() == LoadStrategy.EAGER) {
+ injector.callInContext(new ContextualCallable<Void>() {
+ public Void call(InternalContext context) {
+ InjectionPoint<?> injectionPoint
+ = InjectionPoint.newInstance(binding.key, context.getInjector());
+ context.setInjectionPoint(injectionPoint);
+ try {
+ binding.internalFactory.get(context, injectionPoint);
+ return null;
+ } catch(ProvisionException provisionException) {
+ provisionException.addContext(injectionPoint);
+ throw provisionException;
+ } finally {
+ context.setInjectionPoint(null);
+ }
+ }
+ });
+ }
}
}
@@ -258,31 +262,6 @@
}
}
- private static class EagerSingletonCreator implements ContextualCallable<Void> {
- private final Key<?> key;
- private final InternalFactory<?> factory;
-
- public EagerSingletonCreator(Key<?> key, InternalFactory<?> factory) {
- this.key = key;
- this.factory = Objects.nonNull(factory, "factory");
- }
-
- public Void call(InternalContext context) {
- InjectionPoint<?> injectionPoint
- = InjectionPoint.newInstance(key, context.getInjector());
- context.setInjectionPoint(injectionPoint);
- try {
- factory.get(context, injectionPoint);
- return null;
- } catch(ProvisionException provisionException) {
- provisionException.addContext(injectionPoint);
- throw provisionException;
- } finally {
- context.setInjectionPoint(null);
- }
- }
- }
-
private void putBinding(BindingImpl<?> binding) {
Key<?> key = binding.getKey();
Binding<?> original = bindings.get(key);