Add isEagerSingleton.
Revision created by MOE tool push_codebase.
MOE_MIGRATION=4085
diff --git a/core/src/com/google/inject/Scopes.java b/core/src/com/google/inject/Scopes.java
index 5d025aa..e3242dd 100644
--- a/core/src/com/google/inject/Scopes.java
+++ b/core/src/com/google/inject/Scopes.java
@@ -172,7 +172,63 @@
return false;
} while (true);
}
-
+
+ /**
+
+ * 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
+ * also true if the target binding has the given scope.
+ *
+ * @param binding binding to check
+ * @param scope scope implementation instance
+ * @param scopeAnnotation scope annotation class
+ */
+ 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;
+ }
+ });
+
+ if (matches) {
+ return true;
+ }
+
+ if (binding instanceof LinkedBindingImpl) {
+ LinkedBindingImpl<?> linkedBinding = (LinkedBindingImpl) binding;
+ Injector injector = linkedBinding.getInjector();
+ if (injector != null) {
+ binding = injector.getBinding(linkedBinding.getLinkedKey());
+ continue;
+ }
+ } else if(binding instanceof ExposedBinding) {
+ ExposedBinding<?> exposedBinding = (ExposedBinding)binding;
+ Injector injector = exposedBinding.getPrivateElements().getInjector();
+ if (injector != null) {
+ binding = injector.getBinding(exposedBinding.getKey());
+ continue;
+ }
+ }
+
+ return false;
+ } while (true);
+ }
+
/**
* Returns true if the object is a proxy for a circular dependency,
* constructed by Guice because it encountered a circular dependency. Scope
diff --git a/core/test/com/google/inject/ScopesTest.java b/core/test/com/google/inject/ScopesTest.java
index c2b8a7a..7fd328a 100644
--- a/core/test/com/google/inject/ScopesTest.java
+++ b/core/test/com/google/inject/ScopesTest.java
@@ -361,10 +361,19 @@
@ScopeAnnotation
public @interface CustomScoped {}
+ static final Scope CUSTOM_SCOPE = new Scope() {
+ public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
+ return Scopes.SINGLETON.scope(key, unscoped);
+ }
+ };
+
@Target({ ElementType.TYPE, ElementType.METHOD })
@ScopeAnnotation
public @interface NotRuntimeRetainedScoped {}
+ @CustomScoped
+ static class AnnotatedCustomScoped {}
+
@Singleton
static class AnnotatedSingleton {
static int nextInstanceId;
@@ -561,6 +570,117 @@
assertFalse(Scopes.isSingleton(injector.getBinding(f)));
}
+ public void testIsScopedPositive() {
+ final Key<String> a = Key.get(String.class, named("A"));
+ final Key<String> b = Key.get(String.class, named("B"));
+ final Key<String> c = Key.get(String.class, named("C"));
+ final Key<String> d = Key.get(String.class, named("D"));
+ final Key<String> e = Key.get(String.class, named("E"));
+ final Key<Object> f = Key.get(Object.class, named("F"));
+ final Key<String> g = Key.get(String.class, named("G"));
+
+ Module customBindings = new AbstractModule() {
+ protected void configure() {
+ bindScope(CustomScoped.class, CUSTOM_SCOPE);
+ bind(a).to(b);
+ bind(b).to(c);
+ bind(c).toProvider(Providers.of("c")).in(CUSTOM_SCOPE);
+ bind(d).toProvider(Providers.of("d")).in(CustomScoped.class);
+ bind(f).to(AnnotatedCustomScoped.class);
+ install(new PrivateModule() {
+ @Override
+ protected void configure() {
+ bind(g).toProvider(Providers.of("g")).in(CustomScoped.class);
+ expose(g);
+ }
+ });
+ }
+
+ @Provides @Named("E") @CustomScoped String provideE() {
+ return "e";
+ }
+ };
+
+ @SuppressWarnings("unchecked") // we know the module contains only bindings
+ List<Element> moduleBindings = Elements.getElements(customBindings);
+ ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings);
+ assertFalse(isCustomScoped(map.get(a))); // linked bindings are not followed by modules
+ assertFalse(isCustomScoped(map.get(b)));
+ assertTrue(isCustomScoped(map.get(c)));
+ assertTrue(isCustomScoped(map.get(d)));
+ assertTrue(isCustomScoped(map.get(e)));
+ assertFalse(isCustomScoped(map.get(f))); // annotated classes are not followed by modules
+ assertTrue(isCustomScoped(map.get(g)));
+
+ Injector injector = Guice.createInjector(customBindings);
+ assertTrue(isCustomScoped(injector.getBinding(a)));
+ assertTrue(isCustomScoped(injector.getBinding(b)));
+ assertTrue(isCustomScoped(injector.getBinding(c)));
+ assertTrue(isCustomScoped(injector.getBinding(d)));
+ assertTrue(isCustomScoped(injector.getBinding(e)));
+ assertTrue(isCustomScoped(injector.getBinding(f)));
+ assertTrue(isCustomScoped(injector.getBinding(g)));
+ }
+
+ public void testIsScopedNegative() {
+ final Key<String> a = Key.get(String.class, named("A"));
+ final Key<String> b = Key.get(String.class, named("B"));
+ final Key<String> c = Key.get(String.class, named("C"));
+ final Key<String> d = Key.get(String.class, named("D"));
+ final Key<String> e = Key.get(String.class, named("E"));
+ final Key<String> f = Key.get(String.class, named("F"));
+ final Key<String> g = Key.get(String.class, named("G"));
+ final Key<String> h = Key.get(String.class, named("H"));
+
+ Module customBindings = new AbstractModule() {
+ protected void configure() {
+ bind(a).to(b);
+ bind(b).to(c);
+ bind(c).toProvider(Providers.of("c")).in(Scopes.NO_SCOPE);
+ bind(d).toProvider(Providers.of("d")).in(Singleton.class);
+ install(new PrivateModule() {
+ @Override
+ protected void configure() {
+ bind(f).toProvider(Providers.of("f")).in(Singleton.class);
+ expose(f);
+ }
+ });
+ bind(g).toInstance("g");
+ bind(h).toProvider(Providers.of("h")).asEagerSingleton();
+ }
+
+ @Provides @Named("E") @Singleton String provideE() {
+ return "e";
+ }
+ };
+
+ @SuppressWarnings("unchecked") // we know the module contains only bindings
+ List<Element> moduleBindings = Elements.getElements(customBindings);
+ ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings);
+ assertFalse(isCustomScoped(map.get(a)));
+ assertFalse(isCustomScoped(map.get(b)));
+ assertFalse(isCustomScoped(map.get(c)));
+ assertFalse(isCustomScoped(map.get(d)));
+ assertFalse(isCustomScoped(map.get(e)));
+ assertFalse(isCustomScoped(map.get(f)));
+ assertFalse(isCustomScoped(map.get(g)));
+ assertFalse(isCustomScoped(map.get(h)));
+
+ Injector injector = Guice.createInjector(customBindings);
+ assertFalse(isCustomScoped(injector.getBinding(a)));
+ assertFalse(isCustomScoped(injector.getBinding(b)));
+ assertFalse(isCustomScoped(injector.getBinding(c)));
+ assertFalse(isCustomScoped(injector.getBinding(d)));
+ assertFalse(isCustomScoped(injector.getBinding(e)));
+ assertFalse(isCustomScoped(injector.getBinding(f)));
+ assertFalse(isCustomScoped(injector.getBinding(g)));
+ assertFalse(isCustomScoped(injector.getBinding(h)));
+ }
+
+ private boolean isCustomScoped(Binding<?> binding) {
+ return Scopes.isScoped(binding, CUSTOM_SCOPE, CustomScoped.class);
+ }
+
ImmutableMap<Key<?>, Binding<?>> indexBindings(Iterable<Element> elements) {
ImmutableMap.Builder<Key<?>, Binding<?>> builder = ImmutableMap.builder();
for (Element element : elements) {