Revision: 1424
Author: sberlin
Date: Wed Nov 24 06:52:33 2010
Log: allow scopeRequest/continueRequest to seed with a null value, and also
type-check the values immediately.
http://code.google.com/p/google-guice/source/detail?r=1424
Modified:
/trunk/extensions/servlet/src/com/google/inject/servlet/ServletScopes.java
/trunk/extensions/servlet/test/com/google/inject/servlet/ScopeRequestIntegrationTest.java
=======================================
---
/trunk/extensions/servlet/src/com/google/inject/servlet/ServletScopes.java
Sun Oct 31 11:38:24 2010
+++
/trunk/extensions/servlet/src/com/google/inject/servlet/ServletScopes.java
Wed Nov 24 06:52:33 2010
@@ -156,6 +156,9 @@
*
* @param callable code to be executed in another thread, which depends
on
* the request scope.
+ * @param seedMap the initial set of scoped instances for Guice to seed
the
+ * request scope with. To seed with null, use either a null
+ * value or a value of {...@link #nullObject()}.
* @return a callable that will invoke the given callable, making the
request
* context available to it.
* @throws OutOfScopeException if this method is called from a
non-request
@@ -172,7 +175,8 @@
final ContinuingHttpServletRequest continuingRequest =
new ContinuingHttpServletRequest(GuiceFilter.getRequest());
for (Map.Entry<Key<?>, Object> entry : seedMap.entrySet()) {
- continuingRequest.setAttribute(entry.getKey().toString(),
entry.getValue());
+ Object value = validateAndCanonicalizeValue(entry.getKey(),
entry.getValue());
+ continuingRequest.setAttribute(entry.getKey().toString(), value);
}
return new Callable<T>() {
@@ -216,7 +220,8 @@
* @param callable code to be executed which depends on the request
scope.
* Typically in another thread, but not necessarily so.
* @param seedMap the initial set of scoped instances for Guice to seed
the
- * request scope with.
+ * request scope with. To seed with null, use either a null
+ * value or a value of {...@link #nullObject()}.
* @return a callable that when called will run inside the a request
scope
* that exposes the instances in the {...@code seedMap} as scoped keys.
* @since 3.0
@@ -229,7 +234,8 @@
// Copy the seed values into our local scope map.
final Map<String, Object> scopeMap = Maps.newHashMap();
for (Map.Entry<Key<?>, Object> entry : seedMap.entrySet()) {
- scopeMap.put(entry.getKey().toString(), entry.getValue());
+ Object value = validateAndCanonicalizeValue(entry.getKey(),
entry.getValue());
+ scopeMap.put(entry.getKey().toString(), value);
}
return new Callable<T>() {
@@ -249,4 +255,32 @@
}
};
}
-}
+
+ /**
+ * Returns an object that may be used in the seedMap of
+ * {...@link #continueRequest} and {...@link #scopeRequest} to indicate the
value
+ * should remain null and not attempt to be created.
+ *
+ * @since 3.0
+ */
+ public static Object nullObject() {
+ return NullObject.INSTANCE;
+ }
+
+ /**
+ * Validates the key and object, ensuring the value matches the key
type, and
+ * canonicalizing null objects to the null sentinel.
+ */
+ private static Object validateAndCanonicalizeValue(Key<?> key, Object
object) {
+ if (object == null || object == NullObject.INSTANCE) {
+ return NullObject.INSTANCE;
+ }
+
+ if (!key.getTypeLiteral().getRawType().isInstance(object)) {
+ throw new IllegalArgumentException("Value[" + object + "] of type["
+ + object.getClass().getName() + "] is not compatible with key["
+ key + "]");
+ }
+
+ return object;
+ }
+}
=======================================
---
/trunk/extensions/servlet/test/com/google/inject/servlet/ScopeRequestIntegrationTest.java
Mon Sep 20 11:25:29 2010
+++
/trunk/extensions/servlet/test/com/google/inject/servlet/ScopeRequestIntegrationTest.java
Wed Nov 24 06:52:33 2010
@@ -20,12 +20,17 @@
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
+import com.google.inject.OutOfScopeException;
import com.google.inject.Provider;
+import com.google.inject.ProvisionException;
import com.google.inject.Singleton;
import com.google.inject.internal.util.ImmutableMap;
+import com.google.inject.internal.util.Maps;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
+
import java.io.IOException;
+import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
@@ -80,6 +85,52 @@
executor.shutdown();
executor.awaitTermination(2, TimeUnit.SECONDS);
}
+
+ public final void testWrongValueClasses() throws Exception {
+ Injector injector = Guice.createInjector(new ServletModule() {
+ @Override protected void configureServlets() {
+
bindConstant().annotatedWith(Names.named(SomeObject.INVALID)).to(SHOULDNEVERBESEEN);
+ bind(SomeObject.class).in(RequestScoped.class);
+ }
+ });
+
+ OffRequestCallable offRequestCallable =
injector.getInstance(OffRequestCallable.class);
+ try {
+ ServletScopes.scopeRequest(offRequestCallable,
+ ImmutableMap.<Key<?>,
Object>of(Key.get(SomeObject.class), "Boo!"));
+ fail();
+ } catch(IllegalArgumentException iae) {
+ assertEquals("Value[Boo!] of type[java.lang.String] is not
compatible with key[" + Key.get(SomeObject.class) + "]", iae.getMessage());
+ }
+ }
+
+ public final void testNullReplacement() throws Exception {
+ Injector injector = Guice.createInjector(new ServletModule() {
+ @Override protected void configureServlets() {
+
bindConstant().annotatedWith(Names.named(SomeObject.INVALID)).to(SHOULDNEVERBESEEN);
+ bind(SomeObject.class).in(RequestScoped.class);
+ }
+ });
+
+ Callable<SomeObject> callable = injector.getInstance(Caller.class);
+ try {
+ assertNotNull(callable.call());
+ fail();
+ } catch(ProvisionException pe) {
+ assertTrue(pe.getCause() instanceof OutOfScopeException);
+ }
+
+ // First validate that an actual null entry gets replaced with the
null sentinel.
+ Map<Key<?>, Object> map = Maps.newHashMap();
+ map.put(Key.get(SomeObject.class), null);
+ callable =
ServletScopes.scopeRequest(injector.getInstance(Caller.class), map);
+ assertNull(callable.call());
+
+ // Then validate that our nullObject entry also gets replaced.
+ callable =
ServletScopes.scopeRequest(injector.getInstance(Caller.class),
+ ImmutableMap.<Key<?>, Object>of(Key.get(SomeObject.class),
ServletScopes.nullObject()));
+ assertNull(callable.call());
+ }
@RequestScoped
public static class SomeObject {
@@ -108,4 +159,12 @@
return value;
}
}
-}
+
+ private static class Caller implements Callable<SomeObject> {
+ @Inject Provider<SomeObject> someObject;
+
+ public SomeObject call() throws Exception {
+ return someObject.get();
+ }
+ }
+}
--
You received this message because you are subscribed to the Google Groups
"google-guice-dev" group.
To post to this group, send email to google-guice-...@googlegroups.com.
To unsubscribe from this group, send email to
google-guice-dev+unsubscr...@googlegroups.com.
For more options, visit this group at
http://groups.google.com/group/google-guice-dev?hl=en.