Revision: 1061
Author: limpbizkit
Date: Wed Aug 12 12:24:11 2009
Log: Isaac's patch to fix scoping for null values.
http://code.google.com/p/google-guice/source/detail?r=1061

Modified:
  /trunk/servlet/src/com/google/inject/servlet/ServletScopes.java
  /trunk/servlet/test/com/google/inject/servlet/ServletTest.java
  /trunk/src/com/google/inject/Scopes.java

=======================================
--- /trunk/servlet/src/com/google/inject/servlet/ServletScopes.java     Mon Jun 
 
22 20:16:48 2009
+++ /trunk/servlet/src/com/google/inject/servlet/ServletScopes.java     Wed Aug 
 
12 12:24:11 2009
@@ -19,6 +19,7 @@
  import com.google.inject.Key;
  import com.google.inject.Provider;
  import com.google.inject.Scope;
+
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpSession;

@@ -30,6 +31,9 @@
  public class ServletScopes {

    private ServletScopes() {}
+
+  /** A sentinel attribute value representing null. */
+  enum NullObject { INSTANCE }

    /**
     * HTTP servlet request scope.
@@ -41,11 +45,15 @@
          public T get() {
            HttpServletRequest request = GuiceFilter.getRequest();
            synchronized (request) {
+            Object obj = request.getAttribute(name);
+            if (NullObject.INSTANCE == obj) {
+              return null;
+            }
              @SuppressWarnings("unchecked")
-            T t = (T) request.getAttribute(name);
+            T t = (T) obj;
              if (t == null) {
                t = creator.get();
-              request.setAttribute(name, t);
+              request.setAttribute(name, (t != null) ? t :  
NullObject.INSTANCE);
              }
              return t;
            }
@@ -72,11 +80,15 @@
          public T get() {
            HttpSession session = GuiceFilter.getRequest().getSession();
            synchronized (session) {
+            Object obj = session.getAttribute(name);
+            if (NullObject.INSTANCE == obj) {
+              return null;
+            }
              @SuppressWarnings("unchecked")
-            T t = (T) session.getAttribute(name);
+            T t = (T) obj;
              if (t == null) {
                t = creator.get();
-              session.setAttribute(name, t);
+              session.setAttribute(name, (t != null) ? t :  
NullObject.INSTANCE);
              }
              return t;
            }
=======================================
--- /trunk/servlet/test/com/google/inject/servlet/ServletTest.java      Tue Jan 
  
6 04:48:44 2009
+++ /trunk/servlet/test/com/google/inject/servlet/ServletTest.java      Wed Aug 
 
12 12:24:11 2009
@@ -16,23 +16,35 @@

  package com.google.inject.servlet;

-
  import com.google.inject.AbstractModule;
+import static com.google.inject.Asserts.reserialize;
+import com.google.inject.BindingAnnotation;
  import com.google.inject.CreationException;
  import com.google.inject.Guice;
  import com.google.inject.Injector;
  import com.google.inject.Key;
-
-import junit.framework.TestCase;
-
+import com.google.inject.internal.Maps;
+import static com.google.inject.servlet.ServletScopes.NullObject;
+import com.google.inject.util.Providers;
  import java.io.IOException;
+import java.io.Serializable;
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.PARAMETER;
+import java.lang.annotation.Retention;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+import java.lang.annotation.Target;
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Map;
  import javax.servlet.FilterChain;
  import javax.servlet.ServletException;
  import javax.servlet.ServletRequest;
  import javax.servlet.ServletResponse;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpSession;
-
+import junit.framework.TestCase;
  import static org.easymock.EasyMock.createMock;
  import static org.easymock.EasyMock.eq;
  import static org.easymock.EasyMock.expect;
@@ -44,6 +56,10 @@
   * @author [email protected] (Bob Lee)
   */
  public class ServletTest extends TestCase {
+  private static final Key<InRequest> IN_REQUEST_KEY =  
Key.get(InRequest.class);
+  private static final Key<InRequest> IN_REQUEST_NULL_KEY =  
Key.get(InRequest.class, Null.class);
+  private static final Key<InSession> IN_SESSION_KEY =  
Key.get(InSession.class);
+  private static final Key<InSession> IN_SESSION_NULL_KEY =  
Key.get(InSession.class, Null.class);

    @Override
    public void setUp() {
@@ -59,9 +75,13 @@

      final HttpServletRequest request =  
createMock(HttpServletRequest.class);

-    String name = Key.get(InRequest.class).toString();
-    expect(request.getAttribute(name)).andReturn(null);
-    request.setAttribute(eq(name), isA(InRequest.class));
+    String inRequestKey = IN_REQUEST_KEY.toString();
+    expect(request.getAttribute(inRequestKey)).andReturn(null);
+    request.setAttribute(eq(inRequestKey), isA(InRequest.class));
+
+    String inRequestNullKey = IN_REQUEST_NULL_KEY.toString();
+    expect(request.getAttribute(inRequestNullKey)).andReturn(null);
+    request.setAttribute(eq(inRequestNullKey), eq(NullObject.INSTANCE));

      final boolean[] invoked = new boolean[1];
      FilterChain filterChain = new FilterChain() {
@@ -70,6 +90,7 @@
          invoked[0] = true;
  //        assertSame(request, servletRequest);
          assertNotNull(injector.getInstance(InRequest.class));
+        assertNull(injector.getInstance(IN_REQUEST_NULL_KEY));
        }
      };

@@ -90,8 +111,11 @@
      final HttpServletRequest request =  
createMock(HttpServletRequest.class);

      final InRequest inRequest = new InRequest();
-    String name = Key.get(InRequest.class).toString();
-    expect(request.getAttribute(name)).andReturn(inRequest).times(2);
+    String inRequestKey = IN_REQUEST_KEY.toString();
+     
expect(request.getAttribute(inRequestKey)).andReturn(inRequest).times(2);
+
+    String inRequestNullKey = IN_REQUEST_NULL_KEY.toString();
+     
expect(request.getAttribute(inRequestNullKey)).andReturn(NullObject.INSTANCE).times(2);

      final boolean[] invoked = new boolean[1];
      FilterChain filterChain = new FilterChain() {
@@ -101,6 +125,9 @@

          assertSame(inRequest, injector.getInstance(InRequest.class));
          assertSame(inRequest, injector.getInstance(InRequest.class));
+
+        assertNull(injector.getInstance(IN_REQUEST_NULL_KEY));
+        assertNull(injector.getInstance(IN_REQUEST_NULL_KEY));
        }
      };

@@ -121,11 +148,15 @@
      final HttpServletRequest request =  
createMock(HttpServletRequest.class);
      final HttpSession session = createMock(HttpSession.class);

-    String name = Key.get(InSession.class).toString();
-
-    expect(request.getSession()).andReturn(session);
-    expect(session.getAttribute(name)).andReturn(null);
-    session.setAttribute(eq(name), isA(InSession.class));
+    String inSessionKey = IN_SESSION_KEY.toString();
+    String inSessionNullKey = IN_SESSION_NULL_KEY.toString();
+
+    expect(request.getSession()).andReturn(session).times(2);
+    expect(session.getAttribute(inSessionKey)).andReturn(null);
+    session.setAttribute(eq(inSessionKey), isA(InSession.class));
+
+    expect(session.getAttribute(inSessionNullKey)).andReturn(null);
+    session.setAttribute(eq(inSessionNullKey), eq(NullObject.INSTANCE));

      final boolean[] invoked = new boolean[1];
      FilterChain filterChain = new FilterChain() {
@@ -134,6 +165,7 @@
          invoked[0] = true;
  //        assertSame(request, servletRequest);
          assertNotNull(injector.getInstance(InSession.class));
+        assertNull(injector.getInstance(IN_SESSION_NULL_KEY));
        }
      };

@@ -154,11 +186,14 @@
      final HttpServletRequest request =  
createMock(HttpServletRequest.class);
      final HttpSession session = createMock(HttpSession.class);

-    String name = Key.get(InSession.class).toString();
+    String inSessionKey = IN_SESSION_KEY.toString();
+    String inSessionNullKey = IN_SESSION_NULL_KEY.toString();

      final InSession inSession = new InSession();
-    expect(request.getSession()).andReturn(session).times(2);
-    expect(session.getAttribute(name)).andReturn(inSession).times(2);
+    expect(request.getSession()).andReturn(session).times(4);
+     
expect(session.getAttribute(inSessionKey)).andReturn(inSession).times(2);
+
+     
expect(session.getAttribute(inSessionNullKey)).andReturn(NullObject.INSTANCE).times(2);

      final boolean[] invoked = new boolean[1];
      FilterChain filterChain = new FilterChain() {
@@ -169,6 +204,9 @@

          assertSame(inSession, injector.getInstance(InSession.class));
          assertSame(inSession, injector.getInstance(InSession.class));
+
+        assertNull(injector.getInstance(IN_SESSION_NULL_KEY));
+        assertNull(injector.getInstance(IN_SESSION_NULL_KEY));
        }
      };

@@ -179,6 +217,67 @@
      verify(request, session);
      assertTrue(invoked[0]);
    }
+
+  public void testHttpSessionIsSerializable()
+      throws IOException, ClassNotFoundException, ServletException {
+    final Injector injector = createInjector();
+
+    GuiceFilter filter = new GuiceFilter();
+
+    final HttpServletRequest request =  
createMock(HttpServletRequest.class);
+    final HttpSession session = newFakeHttpSession();
+
+    String inSessionKey = IN_SESSION_KEY.toString();
+    String inSessionNullKey = IN_SESSION_NULL_KEY.toString();
+
+    expect(request.getSession()).andReturn(session).times(2);
+
+    final boolean[] invoked = new boolean[1];
+    FilterChain filterChain = new FilterChain() {
+      public void doFilter(ServletRequest servletRequest,
+          ServletResponse servletResponse) {
+        invoked[0] = true;
+        assertNotNull(injector.getInstance(InSession.class));
+        assertNull(injector.getInstance(IN_SESSION_NULL_KEY));
+      }
+    };
+
+    replay(request);
+
+    filter.doFilter(request, null, filterChain);
+
+    verify(request);
+    assertTrue(invoked[0]);
+
+    HttpSession deserializedSession = reserialize(session);
+
+    assertTrue(deserializedSession.getAttribute(inSessionKey) instanceof  
InSession);
+    assertEquals(NullObject.INSTANCE,  
deserializedSession.getAttribute(inSessionNullKey));
+  }
+
+  private static class FakeHttpSessionHandler implements  
InvocationHandler, Serializable {
+    final Map<String, Object> attributes = Maps.newHashMap();
+
+    public Object invoke(Object proxy, Method method, Object[] args)  
throws Throwable {
+      String name = method.getName();
+      if ("setAttribute".equals(name)) {
+        attributes.put((String) args[0], args[1]);
+        return null;
+      } else if ("getAttribute".equals(name)) {
+        return attributes.get(args[0]);
+      } else {
+        throw new UnsupportedOperationException();
+      }
+    }
+  }
+
+  /**
+   * Returns a fake, serializable HttpSession which stores attributes in a  
HashMap.
+   */
+  private HttpSession newFakeHttpSession() {
+    return (HttpSession)  
Proxy.newProxyInstance(HttpSession.class.getClassLoader(),
+        new Class[] { HttpSession.class }, new FakeHttpSessionHandler());
+  }

    private Injector createInjector() throws CreationException {

@@ -188,14 +287,19 @@
        protected void configure() {
          install(new ServletModule());
          bind(InSession.class);
+         
bind(IN_SESSION_NULL_KEY).toProvider(Providers.<InSession>of(null)).in(SessionScoped.class);
          bind(InRequest.class);
+         
bind(IN_REQUEST_NULL_KEY).toProvider(Providers.<InRequest>of(null)).in(RequestScoped.class);
        }
      });
    }

    @SessionScoped
-  static class InSession {}
+  static class InSession implements Serializable {}

    @RequestScoped
    static class InRequest {}
-}
+
+  @BindingAnnotation @Retention(RUNTIME) @Target({PARAMETER, METHOD,  
FIELD})
+  @interface Null {}
+}
=======================================
--- /trunk/src/com/google/inject/Scopes.java    Mon Jun 22 20:16:48 2009
+++ /trunk/src/com/google/inject/Scopes.java    Wed Aug 12 12:24:11 2009
@@ -19,6 +19,7 @@
  import com.google.inject.internal.InjectorBuilder;
  import com.google.inject.internal.LinkedBindingImpl;
  import com.google.inject.spi.BindingScopingVisitor;
+
  import java.lang.annotation.Annotation;

  /**
@@ -29,6 +30,9 @@
  public class Scopes {

    private Scopes() {}
+
+  /** A sentinel value representing null. */
+  private static final Object NULL = new Object();

    /**
     * One instance per {...@link Injector}. Also see {...@code @}...@link  
Singleton}.
@@ -36,8 +40,11 @@
    public static final Scope SINGLETON = new Scope() {
      public <T> Provider<T> scope(Key<T> key, final Provider<T> creator) {
        return new Provider<T>() {
-
-        private volatile T instance;
+        /*
+         * The lazily initialized singleton instance. Once set, this will  
either have type T or will
+         * be equal to NULL.
+         */
+        private volatile Object instance;

          // DCL on a volatile is safe as of Java 5, which we obviously  
require.
          @SuppressWarnings("DoubleCheckedLocking")
@@ -51,11 +58,16 @@
               */
              synchronized (InjectorBuilder.class) {
                if (instance == null) {
-                instance = creator.get();
+                T nullableInstance = creator.get();
+                instance = (nullableInstance != null) ? nullableInstance :  
NULL;
                }
              }
            }
-          return instance;
+          Object localInstance = instance;
+          // This is safe because instance has type T or is equal to NULL
+          @SuppressWarnings("unchecked")
+          T returnedInstance = (localInstance != NULL) ? (T)  
localInstance : null;
+          return returnedInstance;
          }

          public String toString() {

--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"google-guice-dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/google-guice-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to