Added code to automatically convert between primitive types and their wrapper types. Modified SingletonScope to use double checked locking which resulted in a noticable performance improvement.

git-svn-id: https://google-guice.googlecode.com/svn/trunk@24 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/guice.iws b/guice.iws
index db5ef13..6e17ec8 100644
--- a/guice.iws
+++ b/guice.iws
@@ -18,8 +18,13 @@
   </component>
   <component name="ChangeListManager">
     <list default="true" name="Default" comment="">
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/google/inject/ContainerImpl.java" afterPath="$PROJECT_DIR$/src/com/google/inject/ContainerImpl.java" />
       <change type="MODIFICATION" beforePath="$PROJECT_DIR$/guice.ipr" afterPath="$PROJECT_DIR$/guice.ipr" />
       <change type="MODIFICATION" beforePath="$PROJECT_DIR$/guice.iws" afterPath="$PROJECT_DIR$/guice.iws" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/google/inject/Key.java" afterPath="$PROJECT_DIR$/src/com/google/inject/Key.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/google/inject/ContainerBuilder.java" afterPath="$PROJECT_DIR$/src/com/google/inject/ContainerBuilder.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/test/com/google/inject/ContainerTest.java" afterPath="$PROJECT_DIR$/test/com/google/inject/ContainerTest.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/google/inject/SingletonScope.java" afterPath="$PROJECT_DIR$/src/com/google/inject/SingletonScope.java" />
       <change type="MODIFICATION" beforePath="$PROJECT_DIR$/test/com/google/inject/SpringPerformanceComparison.java" afterPath="$PROJECT_DIR$/test/com/google/inject/SpringPerformanceComparison.java" />
     </list>
   </component>
@@ -193,7 +198,25 @@
       <file leaf-file-name="ContainerImpl.java" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/src/com/google/inject/ContainerImpl.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="483" column="19" selection-start="16109" selection-end="16109" vertical-scroll-proportion="0.016236868">
+            <state line="82" column="0" selection-start="2710" selection-end="2710" vertical-scroll-proportion="0.21145976">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="ContainerBuilder.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/src/com/google/inject/ContainerBuilder.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="256" column="0" selection-start="7981" selection-end="7981" vertical-scroll-proportion="0.3328786">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="Key.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/src/com/google/inject/Key.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="188" column="9" selection-start="4748" selection-end="4748" vertical-scroll-proportion="0.941337">
               <folding />
             </state>
           </provider>
@@ -202,7 +225,7 @@
       <file leaf-file-name="FastClass.class" pinned="false" current="false" current-in-tab="false">
         <entry file="jar://$PROJECT_DIR$/lib/cglib-nodep-2.1_3.jar!/net/sf/cglib/reflect/FastClass.class">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="12" column="47" selection-start="386" selection-end="386" vertical-scroll-proportion="0.016472869">
+            <state line="12" column="47" selection-start="386" selection-end="386" vertical-scroll-proportion="0.02367688">
               <folding />
             </state>
           </provider>
@@ -211,16 +234,34 @@
       <file leaf-file-name="AllTests.java" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/test/com/google/inject/AllTests.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="28" column="3" selection-start="950" selection-end="950" vertical-scroll-proportion="0.12989494">
+            <state line="37" column="34" selection-start="1219" selection-end="1219" vertical-scroll-proportion="0.39427012">
               <folding />
             </state>
           </provider>
         </entry>
       </file>
-      <file leaf-file-name="SpringPerformanceComparison.java" pinned="false" current="true" current-in-tab="true">
+      <file leaf-file-name="SingletonScope.java" pinned="false" current="true" current-in-tab="true">
+        <entry file="file://$PROJECT_DIR$/src/com/google/inject/SingletonScope.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="42" column="0" selection-start="1160" selection-end="1160" vertical-scroll-proportion="0.9536153">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="ContainerTest.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/test/com/google/inject/ContainerTest.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="63" column="68" selection-start="1990" selection-end="1990" vertical-scroll-proportion="0.39427012">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="SpringPerformanceComparison.java" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/test/com/google/inject/SpringPerformanceComparison.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="33" column="36" selection-start="1297" selection-end="1297" vertical-scroll-proportion="0.1461318">
+            <state line="38" column="13" selection-start="1438" selection-end="1438" vertical-scroll-proportion="0.32469305">
               <folding />
             </state>
           </provider>
@@ -229,7 +270,7 @@
       <file leaf-file-name="Scoped.java" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/src/com/google/inject/Scoped.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="31" column="18" selection-start="1024" selection-end="1024" vertical-scroll-proportion="0.22731614">
+            <state line="31" column="18" selection-start="1024" selection-end="1024" vertical-scroll-proportion="0.32469305">
               <folding />
             </state>
           </provider>
@@ -238,7 +279,7 @@
       <file leaf-file-name="FastMethod.class" pinned="false" current="false" current-in-tab="false">
         <entry file="jar://$PROJECT_DIR$/lib/cglib-nodep-2.1_3.jar!/net/sf/cglib/reflect/FastMethod.class">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="5" column="13" selection-start="158" selection-end="158" vertical-scroll-proportion="0.065891474">
+            <state line="5" column="13" selection-start="158" selection-end="158" vertical-scroll-proportion="0.09470752">
               <folding />
             </state>
           </provider>
@@ -690,7 +731,7 @@
       <window_info id="Palette" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="3" />
       <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.14623655" order="1" />
       <window_info id="Changes" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.3282876" order="8" />
-      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.29044464" order="2" />
+      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.29044464" order="2" />
       <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" order="2" />
       <window_info id="File View" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="6" />
       <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.39978448" order="0" />
@@ -783,40 +824,12 @@
   </component>
   <component name="com.intellij.openapi.roots.ui.configuration.projectRoot.ProjectRootMasterDetailsConfigurable" proportions="0.16666667" version="1">
     <option name="myPlainMode" value="false" />
-    <option name="myLastEditedConfigurable" value="cglib-nodep-2.1_3" />
+    <option name="myLastEditedConfigurable" value="1.5" />
   </component>
   <component name="com.intellij.profile.ui.ErrorOptionsConfigurable" proportions="0.16666667,0.60142857" version="1">
     <option name="myLastEditedConfigurable" value="Default" />
   </component>
   <component name="editorHistoryManager">
-    <entry file="file://$PROJECT_DIR$/src/com/google/inject/Scopes.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="19" column="16" selection-start="393" selection-end="393" vertical-scroll-proportion="0.43355703">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/src/com/google/inject/SingletonScope.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="21" column="15" selection-start="481" selection-end="481" vertical-scroll-proportion="0.47919464">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/src/com/google/inject/Container.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="88" column="0" selection-start="2454" selection-end="2454" vertical-scroll-proportion="1.224161">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/test/com/google/inject/FactoryInjectionTest.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="15" column="23" selection-start="364" selection-end="364" vertical-scroll-proportion="0.34228188">
-          <folding />
-        </state>
-      </provider>
-    </entry>
     <entry file="file://$PROJECT_DIR$/test/com/google/inject/GenericInjectionTest.java">
       <provider selected="true" editor-type-id="text-editor">
         <state line="12" column="13" selection-start="225" selection-end="225" vertical-scroll-proportion="0.20536913">
@@ -852,44 +865,72 @@
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/src/com/google/inject/ContainerImpl.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="483" column="19" selection-start="16109" selection-end="16109" vertical-scroll-proportion="0.016236868">
-          <folding />
-        </state>
-      </provider>
-    </entry>
     <entry file="jar://$PROJECT_DIR$/lib/cglib-nodep-2.1_3.jar!/net/sf/cglib/reflect/FastClass.class">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="12" column="47" selection-start="386" selection-end="386" vertical-scroll-proportion="0.016472869">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/test/com/google/inject/AllTests.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="28" column="3" selection-start="950" selection-end="950" vertical-scroll-proportion="0.12989494">
+        <state line="12" column="47" selection-start="386" selection-end="386" vertical-scroll-proportion="0.02367688">
           <folding />
         </state>
       </provider>
     </entry>
     <entry file="file://$PROJECT_DIR$/src/com/google/inject/Scoped.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="31" column="18" selection-start="1024" selection-end="1024" vertical-scroll-proportion="0.22731614">
+        <state line="31" column="18" selection-start="1024" selection-end="1024" vertical-scroll-proportion="0.32469305">
           <folding />
         </state>
       </provider>
     </entry>
     <entry file="jar://$PROJECT_DIR$/lib/cglib-nodep-2.1_3.jar!/net/sf/cglib/reflect/FastMethod.class">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="5" column="13" selection-start="158" selection-end="158" vertical-scroll-proportion="0.065891474">
+        <state line="5" column="13" selection-start="158" selection-end="158" vertical-scroll-proportion="0.09470752">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/src/com/google/inject/Key.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="188" column="9" selection-start="4748" selection-end="4748" vertical-scroll-proportion="0.941337">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/src/com/google/inject/ContainerBuilder.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="256" column="0" selection-start="7981" selection-end="7981" vertical-scroll-proportion="0.3328786">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/src/com/google/inject/ContainerImpl.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="82" column="0" selection-start="2710" selection-end="2710" vertical-scroll-proportion="0.21145976">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/test/com/google/inject/ContainerTest.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="63" column="68" selection-start="1990" selection-end="1990" vertical-scroll-proportion="0.39427012">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/test/com/google/inject/AllTests.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="37" column="34" selection-start="1219" selection-end="1219" vertical-scroll-proportion="0.39427012">
           <folding />
         </state>
       </provider>
     </entry>
     <entry file="file://$PROJECT_DIR$/test/com/google/inject/SpringPerformanceComparison.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="33" column="36" selection-start="1297" selection-end="1297" vertical-scroll-proportion="0.1461318">
+        <state line="38" column="13" selection-start="1438" selection-end="1438" vertical-scroll-proportion="0.32469305">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/src/com/google/inject/SingletonScope.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="42" column="0" selection-start="1160" selection-end="1160" vertical-scroll-proportion="0.9536153">
           <folding />
         </state>
       </provider>
diff --git a/src/com/google/inject/ContainerBuilder.java b/src/com/google/inject/ContainerBuilder.java
index 5245a3d..0cbbe5d 100644
--- a/src/com/google/inject/ContainerBuilder.java
+++ b/src/com/google/inject/ContainerBuilder.java
@@ -258,7 +258,9 @@
 
     for (ConstantBindingBuilder builder : constantBindingBuilders) {
       if (builder.hasValue()) {
-        factories.put(builder.getKey(), builder.getInternalFactory());
+        Key<?> key = builder.getKey();
+        InternalFactory<?> factory = builder.getInternalFactory();
+        factories.put(key, factory);
       } else {
         add(new ErrorMessage(builder.getSource(),
             "Constant value isn't set."));
diff --git a/src/com/google/inject/ContainerImpl.java b/src/com/google/inject/ContainerImpl.java
index a96021b..530dff0 100644
--- a/src/com/google/inject/ContainerImpl.java
+++ b/src/com/google/inject/ContainerImpl.java
@@ -40,6 +40,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
+import java.util.Collections;
 
 /**
  * Default {@link Container} implementation.
@@ -49,6 +50,34 @@
  */
 class ContainerImpl implements Container {
 
+  /**
+   * Maps between primitive types and their wrappers and vice versa.
+   */
+  private static final Map<Class<?>, Class<?>> PRIMITIVE_COUNTERPARTS;
+  static {
+    Map<Class<?>, Class<?>> primitiveToWrapper =
+        new HashMap<Class<?>, Class<?>>() {{
+          put(int.class, Integer.class);
+          put(long.class, Long.class);
+          put(boolean.class, Boolean.class);
+          put(byte.class, Byte.class);
+          put(short.class, Short.class);
+          put(float.class, Float.class);
+          put(double.class, Double.class);
+          put(char.class, Character.class);
+        }};
+
+    Map<Class<?>, Class<?>> counterparts = new HashMap<Class<?>, Class<?>>();
+    for (Map.Entry<Class<?>, Class<?>> entry : primitiveToWrapper.entrySet()) {
+      Class<?> key = entry.getKey();
+      Class<?> value = entry.getValue();
+      counterparts.put(key, value);
+      counterparts.put(value, key);
+    }
+
+    PRIMITIVE_COUNTERPARTS = Collections.unmodifiableMap(counterparts);
+  }
+
   private static final Map<Class<?>, Converter<?>> PRIMITIVE_CONVERTERS =
       new PrimitiveConverters();
 
@@ -86,6 +115,17 @@
       };
     }
 
+    // Auto[un]box primitives.
+    Class<?> primitiveCounterpart =
+        PRIMITIVE_COUNTERPARTS.get(key.getTypeToken().getRawType());
+    if (primitiveCounterpart != null) {
+      internalFactory = (InternalFactory<T>) factories.get(
+          Key.get(primitiveCounterpart, key.getName()));
+      if (internalFactory != null) {
+        return internalFactory;
+      }
+    }
+
     // Do we have a constant String factory of the same name?
     InternalFactory<String> stringFactory =
         (InternalFactory<String>) factories.get(
@@ -654,13 +694,13 @@
   static class PrimitiveConverters extends HashMap<Class<?>, Converter<?>> {
 
     PrimitiveConverters() {
-      putParser(Integer.class, int.class);
-      putParser(Long.class, long.class);
-      putParser(Boolean.class, boolean.class);
-      putParser(Byte.class, byte.class);
-      putParser(Short.class, short.class);
-      putParser(Float.class, float.class);
-      putParser(Double.class, double.class);
+      putParser(int.class);
+      putParser(long.class);
+      putParser(boolean.class);
+      putParser(byte.class);
+      putParser(short.class);
+      putParser(float.class);
+      putParser(double.class);
 
       // Character doesn't follow the same pattern.
       Converter<Character> characterConverter = new Converter<Character>() {
@@ -678,8 +718,9 @@
       put(Character.class, characterConverter);
     }
 
-    <T> void putParser(Class<T> wrapper, final Class<T> primitive) {
+    <T> void putParser(final Class<T> primitive) {
       try {
+        Class<?> wrapper = PRIMITIVE_COUNTERPARTS.get(primitive);
         final Method parser = wrapper.getMethod("parse" +
             Strings.capitalize(primitive.getName()), String.class);
         Converter<T> converter = new Converter<T>() {
diff --git a/src/com/google/inject/Key.java b/src/com/google/inject/Key.java
index 2f9217f..ae1404e 100644
--- a/src/com/google/inject/Key.java
+++ b/src/com/google/inject/Key.java
@@ -105,7 +105,7 @@
   /**
    * Returns a new key with the same type as this key and the given name,
    */
-  public Key<T> named(String name) {
+  Key<T> named(String name) {
     return new SimpleKey<T>(this.typeToken, name);    
   }
 
@@ -158,7 +158,7 @@
   /**
    * Gets a key for a {@code Class} and a name.
    */
-  static <T> Key<T> get(Class<T> type, String name) {
+  public static <T> Key<T> get(Class<T> type, String name) {
     return new SimpleKey<T>(type, name);
   }
 
@@ -172,7 +172,7 @@
   /**
    * Gets a key for a type and a name.
    */
-  static Key<?> get(Type type, String name) {
+  public static Key<?> get(Type type, String name) {
     return new SimpleKey<Object>(type, name);
   }
 
@@ -186,7 +186,7 @@
   /**
    * Gets key for a type token and a name.
    */
-  static <T> Key<T> get(TypeToken<T> typeToken, String name) {
+  public static <T> Key<T> get(TypeToken<T> typeToken, String name) {
     return new SimpleKey<T>(typeToken, name);
   }
 
diff --git a/src/com/google/inject/SingletonScope.java b/src/com/google/inject/SingletonScope.java
index bb327bd..8b2853f 100644
--- a/src/com/google/inject/SingletonScope.java
+++ b/src/com/google/inject/SingletonScope.java
@@ -16,19 +16,22 @@
   public <T> Factory<T> scope(Key<T> key, final Factory<T> creator) {
     return new Factory<T>() {
 
-      T instance;
+      private volatile T instance;
 
       public T get() {
-        // Use a pretty coarse lock. We don't want to run into deadlocks when
-        // two threads try to load circularly-dependent singletons.
-        // Maybe one of these days we will identify independent graphs of
-        // singletons and offer to load them in parallel.
-        synchronized (Container.class) {
-          if (instance == null) {
-            instance = creator.get();
+        // Double checked locking improves performance and is safe as of Java 5.
+        if (instance == null) {
+          // Use a pretty coarse lock. We don't want to run into deadlocks when
+          // two threads try to load circularly-dependent singletons.
+          // Maybe one of these days we will identify independent graphs of
+          // singletons and offer to load them in parallel.
+          synchronized (Container.class) {
+            if (instance == null) {
+              instance = creator.get();
+            }
           }
-          return instance;
         }
+        return instance;
       }
 
       public String toString() {
diff --git a/test/com/google/inject/ContainerTest.java b/test/com/google/inject/ContainerTest.java
index 6fe5506..7a5a164 100644
--- a/test/com/google/inject/ContainerTest.java
+++ b/test/com/google/inject/ContainerTest.java
@@ -57,6 +57,18 @@
     assertEquals(5, bar.getI());
   }
 
+  public void testIntAndIntegerAreInterchangeable() {
+    ContainerBuilder builder = new ContainerBuilder();
+    builder.bind("i").to(5);
+    Container container = builder.create(false);
+    IntegerWrapper iw = container.newInstance(IntegerWrapper.class);
+    assertEquals(5, (int) iw.i);
+  }
+
+  static class IntegerWrapper {
+    @Inject("i") Integer i;
+  }
+
   static class Foo {
 
     @Inject Bar bar;