Add ServletScopes.isRequestScoped.
Revision created by MOE tool push_codebase.
MOE_MIGRATION=4084
diff --git a/common.xml b/common.xml
index 6401b21..d3ab4ed 100644
--- a/common.xml
+++ b/common.xml
@@ -44,10 +44,6 @@
<property name="Export-Package" value="!${module}.internal.*,${module}.*;version=${api.version}"/>
- <condition property="Eclipse-ExtensibleAPI" value="true">
- <equals arg1="${module}" arg2="com.google.inject"/>
- </condition>
-
<condition property="Import-Package" value="!com.google.inject.*,*" else="!${module}.*,${imports},*">
<istrue value="${fragment}"/>
</condition>
diff --git a/core/pom.xml b/core/pom.xml
index 9ac81be..3df788b 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -98,11 +98,6 @@
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
- <configuration>
- <instructions>
- <Eclipse-ExtensibleAPI>true</Eclipse-ExtensibleAPI>
- </instructions>
- </configuration>
</plugin>
<!--
| Remove duplicate jarjar'd LICENSE and NOTICE
diff --git a/extensions/grapher/test/com/google/inject/grapher/AbstractInjectorGrapherTest.java b/extensions/grapher/test/com/google/inject/grapher/AbstractInjectorGrapherTest.java
index b5ee53f..8d90f4c 100644
--- a/extensions/grapher/test/com/google/inject/grapher/AbstractInjectorGrapherTest.java
+++ b/extensions/grapher/test/com/google/inject/grapher/AbstractInjectorGrapherTest.java
@@ -26,6 +26,7 @@
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.spi.InjectionPoint;
+import com.google.testing.testsize.MediumTest;
import junit.framework.TestCase;
@@ -40,6 +41,7 @@
*
* @author bojand@google.com (Bojan Djordjevic)
*/
+@MediumTest
public class AbstractInjectorGrapherTest extends TestCase {
private static final String TEST_STRING = "test";
diff --git a/extensions/servlet/src/com/google/inject/servlet/ServletScopes.java b/extensions/servlet/src/com/google/inject/servlet/ServletScopes.java
index acc7229..156e9c6 100644
--- a/extensions/servlet/src/com/google/inject/servlet/ServletScopes.java
+++ b/extensions/servlet/src/com/google/inject/servlet/ServletScopes.java
@@ -19,12 +19,18 @@
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
+import com.google.inject.Binding;
+import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.OutOfScopeException;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.Scopes;
+import com.google.inject.internal.LinkedBindingImpl;
+import com.google.inject.spi.BindingScopingVisitor;
+import com.google.inject.spi.ExposedBinding;
+import java.lang.annotation.Annotation;
import java.util.Map;
import java.util.concurrent.Callable;
@@ -47,6 +53,14 @@
Key.get(HttpServletResponse.class),
new Key<Map<String, String[]>>(RequestParameters.class) {});
+ /**
+ * A threadlocal scope map for non-http request scopes. The {@link #REQUEST}
+ * scope falls back to this scope map if no http request is available, and
+ * requires {@link #scopeRequest} to be called as an alertnative.
+ */
+ private static final ThreadLocal<Map<String, Object>> requestScopeContext
+ = new ThreadLocal<Map<String, Object>>();
+
/** A sentinel attribute value representing null. */
enum NullObject { INSTANCE }
@@ -233,12 +247,59 @@
}
/**
- * A threadlocal scope map for non-http request scopes. The {@link #REQUEST}
- * scope falls back to this scope map if no http request is available, and
- * requires {@link #scopeRequest} to be called as an alertnative.
+ * Returns true if {@code binding} is request-scoped. If the binding is a
+ * {@link com.google.inject.spi.LinkedKeyBinding linked key binding} and
+ * belongs to an injector (i. e. it was retrieved via
+ * {@link Injector#getBinding Injector.getBinding()}), then this method will
+ * also return true if the target binding is request-scoped.
*/
- private static final ThreadLocal<Map<String, Object>> requestScopeContext
- = new ThreadLocal<Map<String, Object>>();
+ public static boolean isRequestScoped(Binding<?> binding) {
+ do {
+ boolean requestScoped = binding.acceptScopingVisitor(new BindingScopingVisitor<Boolean>() {
+ @Override
+ public Boolean visitNoScoping() {
+ return false;
+ }
+
+ @Override
+ public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
+ return scopeAnnotation == RequestScoped.class;
+ }
+
+ @Override
+ public Boolean visitScope(Scope scope) {
+ return scope == ServletScopes.REQUEST;
+ }
+
+ @Override
+ public Boolean visitEagerSingleton() {
+ return false;
+ }
+ });
+
+ if (requestScoped) {
+ 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);
+ }
/**
* Scopes the given callable inside a request scope. This is not the same
diff --git a/extensions/servlet/test/com/google/inject/servlet/ServletScopesTest.java b/extensions/servlet/test/com/google/inject/servlet/ServletScopesTest.java
new file mode 100644
index 0000000..0ad40e3
--- /dev/null
+++ b/extensions/servlet/test/com/google/inject/servlet/ServletScopesTest.java
@@ -0,0 +1,203 @@
+/**
+ * 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 License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject.servlet;
+
+import static com.google.inject.name.Names.named;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.AbstractModule;
+import com.google.inject.Binding;
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
+import com.google.inject.Module;
+import com.google.inject.PrivateModule;
+import com.google.inject.Provides;
+import com.google.inject.ScopeAnnotation;
+import com.google.inject.Scopes;
+import com.google.inject.Singleton;
+import com.google.inject.name.Named;
+import com.google.inject.spi.Element;
+import com.google.inject.spi.Elements;
+import com.google.inject.spi.PrivateElements;
+import com.google.inject.util.Providers;
+
+import junit.framework.TestCase;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Tests for {@link ServletScopes}.
+ *
+ * @author forster@google.com (Mike Forster)
+ */
+public class ServletScopesTest extends TestCase {
+ public void testIsRequestScopedPositive() {
+ 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<Object> e = Key.get(Object.class, named("E"));
+ final Key<String> f = Key.get(String.class, named("F"));
+ final Key<String> g = Key.get(String.class, named("G"));
+
+ Module requestScopedBindings = new AbstractModule() {
+ @Override
+ protected void configure() {
+ bind(a).to(b);
+ bind(b).to(c);
+ bind(c).toProvider(Providers.of("c")).in(ServletScopes.REQUEST);
+ bind(d).toProvider(Providers.of("d")).in(RequestScoped.class);
+ bind(e).to(AnnotatedRequestScopedClass.class);
+ install(new PrivateModule() {
+ @Override
+ protected void configure() {
+ bind(f).toProvider(Providers.of("f")).in(RequestScoped.class);
+ expose(f);
+ }
+ });
+ }
+
+ @Provides
+ @Named("G")
+ @RequestScoped
+ String provideG() {
+ return "g";
+ }
+ };
+
+ @SuppressWarnings("unchecked") // we know the module contains only bindings
+ List<Element> moduleBindings = Elements.getElements(requestScopedBindings);
+ ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings);
+ // linked bindings are not followed by modules
+ assertFalse(ServletScopes.isRequestScoped(map.get(a)));
+ assertFalse(ServletScopes.isRequestScoped(map.get(b)));
+ assertTrue(ServletScopes.isRequestScoped(map.get(c)));
+ assertTrue(ServletScopes.isRequestScoped(map.get(d)));
+ // annotated classes are not followed by modules
+ assertFalse(ServletScopes.isRequestScoped(map.get(e)));
+ assertTrue(ServletScopes.isRequestScoped(map.get(f)));
+ assertTrue(ServletScopes.isRequestScoped(map.get(g)));
+
+ Injector injector = Guice.createInjector(requestScopedBindings, new ServletModule());
+ assertTrue(ServletScopes.isRequestScoped(injector.getBinding(a)));
+ assertTrue(ServletScopes.isRequestScoped(injector.getBinding(b)));
+ assertTrue(ServletScopes.isRequestScoped(injector.getBinding(c)));
+ assertTrue(ServletScopes.isRequestScoped(injector.getBinding(d)));
+ assertTrue(ServletScopes.isRequestScoped(injector.getBinding(e)));
+ assertTrue(ServletScopes.isRequestScoped(injector.getBinding(f)));
+ assertTrue(ServletScopes.isRequestScoped(injector.getBinding(g)));
+ }
+
+ public void testIsRequestScopedNegative() {
+ 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"));
+ final Key<String> i = Key.get(String.class, named("I"));
+ final Key<String> j = Key.get(String.class, named("J"));
+
+ Module requestScopedBindings = new AbstractModule() {
+ @Override
+ protected void configure() {
+ bind(a).to(b);
+ bind(b).to(c);
+ bind(c).toProvider(Providers.of("c")).in(Scopes.NO_SCOPE);
+ bind(d).toInstance("d");
+ bind(e).toProvider(Providers.of("e")).asEagerSingleton();
+ bind(f).toProvider(Providers.of("f")).in(Scopes.SINGLETON);
+ bind(g).toProvider(Providers.of("g")).in(Singleton.class);
+ bind(h).toProvider(Providers.of("h")).in(CustomScoped.class);
+ bindScope(CustomScoped.class, Scopes.NO_SCOPE);
+ install(new PrivateModule() {
+ @Override
+ protected void configure() {
+ bind(i).toProvider(Providers.of("i")).in(CustomScoped.class);
+ expose(i);
+ }
+ });
+ }
+
+ @Provides
+ @Named("J")
+ @CustomScoped
+ String provideJ() {
+ return "j";
+ }
+ };
+
+ @SuppressWarnings("unchecked") // we know the module contains only bindings
+ List<Element> moduleBindings = Elements.getElements(requestScopedBindings);
+ ImmutableMap<Key<?>, Binding<?>> map = indexBindings(moduleBindings);
+ assertFalse(ServletScopes.isRequestScoped(map.get(a)));
+ assertFalse(ServletScopes.isRequestScoped(map.get(b)));
+ assertFalse(ServletScopes.isRequestScoped(map.get(c)));
+ assertFalse(ServletScopes.isRequestScoped(map.get(d)));
+ assertFalse(ServletScopes.isRequestScoped(map.get(e)));
+ assertFalse(ServletScopes.isRequestScoped(map.get(f)));
+ assertFalse(ServletScopes.isRequestScoped(map.get(g)));
+ assertFalse(ServletScopes.isRequestScoped(map.get(h)));
+ assertFalse(ServletScopes.isRequestScoped(map.get(i)));
+ assertFalse(ServletScopes.isRequestScoped(map.get(j)));
+
+ Injector injector = Guice.createInjector(requestScopedBindings);
+ assertFalse(ServletScopes.isRequestScoped(injector.getBinding(a)));
+ assertFalse(ServletScopes.isRequestScoped(injector.getBinding(b)));
+ assertFalse(ServletScopes.isRequestScoped(injector.getBinding(c)));
+ assertFalse(ServletScopes.isRequestScoped(injector.getBinding(d)));
+ assertFalse(ServletScopes.isRequestScoped(injector.getBinding(e)));
+ assertFalse(ServletScopes.isRequestScoped(injector.getBinding(f)));
+ assertFalse(ServletScopes.isRequestScoped(injector.getBinding(g)));
+ assertFalse(ServletScopes.isRequestScoped(injector.getBinding(h)));
+ assertFalse(ServletScopes.isRequestScoped(injector.getBinding(i)));
+ assertFalse(ServletScopes.isRequestScoped(injector.getBinding(j)));
+ }
+
+ @RequestScoped
+ static class AnnotatedRequestScopedClass {}
+
+ @Target({ ElementType.TYPE, ElementType.METHOD })
+ @Retention(RUNTIME)
+ @ScopeAnnotation
+ private @interface CustomScoped {}
+
+ private ImmutableMap<Key<?>, Binding<?>> indexBindings(Iterable<Element> elements) {
+ ImmutableMap.Builder<Key<?>, Binding<?>> builder = ImmutableMap.builder();
+ for (Element element : elements) {
+ if (element instanceof Binding) {
+ Binding<?> binding = (Binding<?>) element;
+ builder.put(binding.getKey(), binding);
+ } else if (element instanceof PrivateElements) {
+ PrivateElements privateElements = (PrivateElements) element;
+ Map<Key<?>, Binding<?>> privateBindings = indexBindings(privateElements.getElements());
+ for (Key<?> exposed : privateElements.getExposedKeys()) {
+ builder.put(exposed, privateBindings.get(exposed));
+ }
+ }
+ }
+ return builder.build();
+ }
+}