Added TypeToken. Refactored Key to use it. Goodbye, raw types!

git-svn-id: https://google-guice.googlecode.com/svn/trunk@10 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/guice.iws b/guice.iws
index 771aff2..7393cff 100644
--- a/guice.iws
+++ b/guice.iws
@@ -18,14 +18,16 @@
   </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$/src/com/google/inject/ConstantConversionException.java" afterPath="$PROJECT_DIR$/src/com/google/inject/ConstantConversionException.java" />
-      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/google/inject/BindingBuilder.java" afterPath="$PROJECT_DIR$/src/com/google/inject/BindingBuilder.java" />
-      <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$/guice.iws" afterPath="$PROJECT_DIR$/guice.iws" />
-      <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$/src/com/google/inject/ExternalContext.java" afterPath="$PROJECT_DIR$/src/com/google/inject/ExternalContext.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/google/inject/Key.java" afterPath="$PROJECT_DIR$/src/com/google/inject/Key.java" />
+      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/src/com/google/inject/TypeToken.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/google/inject/Container.java" afterPath="$PROJECT_DIR$/src/com/google/inject/Container.java" />
       <change type="MODIFICATION" beforePath="$PROJECT_DIR$/test/com/google/inject/KeyTest.java" afterPath="$PROJECT_DIR$/test/com/google/inject/KeyTest.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/test/com/google/inject/FactoryTest.java" afterPath="$PROJECT_DIR$/test/com/google/inject/FactoryTest.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/test/com/google/inject/AllTests.java" afterPath="$PROJECT_DIR$/test/com/google/inject/AllTests.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/google/inject/ContainerImpl.java" afterPath="$PROJECT_DIR$/src/com/google/inject/ContainerImpl.java" />
+      <change type="NEW" beforePath="" afterPath="$PROJECT_DIR$/test/com/google/inject/TypeTokenTest.java" />
+      <change type="MODIFICATION" beforePath="$PROJECT_DIR$/src/com/google/inject/ContainerBuilder.java" afterPath="$PROJECT_DIR$/src/com/google/inject/ContainerBuilder.java" />
     </list>
   </component>
   <component name="ChangeListSynchronizer" />
@@ -181,7 +183,16 @@
       <file leaf-file-name="BindingBuilder.java" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/src/com/google/inject/BindingBuilder.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="27" column="13" selection-start="893" selection-end="893" vertical-scroll-proportion="0.017561983">
+            <state line="143" column="51" selection-start="3844" selection-end="3844" vertical-scroll-proportion="1.1169014">
+              <folding />
+            </state>
+          </provider>
+        </entry>
+      </file>
+      <file leaf-file-name="ExternalContext.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/src/com/google/inject/ExternalContext.java">
+          <provider selected="true" editor-type-id="text-editor">
+            <state line="40" column="14" selection-start="1164" selection-end="1164" vertical-scroll-proportion="0.51830983">
               <folding />
             </state>
           </provider>
@@ -190,7 +201,7 @@
       <file leaf-file-name="Factory.java" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/src/com/google/inject/Factory.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="32" column="4" selection-start="954" selection-end="954" vertical-scroll-proportion="0.3161157">
+            <state line="32" column="4" selection-start="954" selection-end="954" vertical-scroll-proportion="0.43098593">
               <folding />
             </state>
           </provider>
@@ -199,7 +210,7 @@
       <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="475" column="21" selection-start="15782" selection-end="15782" vertical-scroll-proportion="0.017561983">
+            <state line="72" column="23" selection-start="2310" selection-end="2310" vertical-scroll-proportion="0.7450704">
               <folding />
             </state>
           </provider>
@@ -208,7 +219,7 @@
       <file leaf-file-name="Binding.java" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/src/com/google/inject/Binding.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="23" column="13" selection-start="755" selection-end="755" vertical-scroll-proportion="0.15805785">
+            <state line="23" column="13" selection-start="755" selection-end="755" vertical-scroll-proportion="0.21549296">
               <folding />
             </state>
           </provider>
@@ -217,7 +228,7 @@
       <file leaf-file-name="Scope2.java" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/src/com/google/inject/Scope2.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="21" column="17" selection-start="691" selection-end="691" vertical-scroll-proportion="0.12293389">
+            <state line="21" column="17" selection-start="691" selection-end="691" vertical-scroll-proportion="0.16760564">
               <folding />
             </state>
           </provider>
@@ -226,52 +237,47 @@
       <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="404" column="0" selection-start="12666" selection-end="12666" vertical-scroll-proportion="0.017561983">
+            <state line="404" column="0" selection-start="12618" selection-end="12618" vertical-scroll-proportion="0.023943663">
               <folding />
             </state>
           </provider>
         </entry>
       </file>
-      <file leaf-file-name="Key.java" pinned="false" current="true" current-in-tab="true">
+      <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="53" column="38" selection-start="1608" selection-end="1608" vertical-scroll-proportion="0.6322314">
+            <state line="37" column="22" selection-start="1090" selection-end="1090" vertical-scroll-proportion="0.33239436">
               <folding />
             </state>
           </provider>
         </entry>
       </file>
-      <file leaf-file-name="ParameterizedType.class" pinned="false" current="false" current-in-tab="false">
-        <entry file="jar:///usr/local/buildtools/java/jdk1.5.0_06/jre/lib/rt.jar!/java/lang/reflect/ParameterizedType.class">
+      <file leaf-file-name="TypeToken.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/src/com/google/inject/TypeToken.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="5" column="17" selection-start="159" selection-end="159" vertical-scroll-proportion="0.07024793">
-              <folding />
+            <state line="113" column="14" selection-start="3421" selection-end="3421" vertical-scroll-proportion="0.33239436">
+              <folding>
+                <element signature="imports" expanded="true" />
+              </folding>
             </state>
           </provider>
         </entry>
       </file>
-      <file leaf-file-name="Type.class" pinned="false" current="false" current-in-tab="false">
-        <entry file="jar:///usr/local/buildtools/java/jdk1.5.0_06/jre/lib/rt.jar!/java/lang/reflect/Type.class">
+      <file leaf-file-name="TypeTokenTest.java" pinned="false" current="false" current-in-tab="false">
+        <entry file="file://$PROJECT_DIR$/test/com/google/inject/TypeTokenTest.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="5" column="17" selection-start="159" selection-end="159" vertical-scroll-proportion="0.07024793">
-              <folding />
+            <state line="42" column="55" selection-start="1307" selection-end="1307" vertical-scroll-proportion="0.67042255">
+              <folding>
+                <element signature="imports" expanded="true" />
+              </folding>
             </state>
           </provider>
         </entry>
       </file>
-      <file leaf-file-name="KeyTest.java" pinned="false" current="false" current-in-tab="false">
-        <entry file="file://$PROJECT_DIR$/test/com/google/inject/KeyTest.java">
+      <file leaf-file-name="ClassRepository.class" pinned="false" current="false" current-in-tab="false">
+        <entry file="jar:///System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/classes.jar!/sun/reflect/generics/repository/ClassRepository.class">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="21" column="24" selection-start="573" selection-end="573" vertical-scroll-proportion="0.2985537">
-              <folding />
-            </state>
-          </provider>
-        </entry>
-      </file>
-      <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="34" column="30" selection-start="1077" selection-end="1077" vertical-scroll-proportion="0.24586777">
+            <state line="15" column="26" selection-start="851" selection-end="851" vertical-scroll-proportion="0.34244603">
               <folding />
             </state>
           </provider>
@@ -280,25 +286,25 @@
       <file leaf-file-name="Objects.java" pinned="false" current="false" current-in-tab="false">
         <entry file="file://$PROJECT_DIR$/src/com/google/inject/util/Objects.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="23" column="13" selection-start="716" selection-end="716" vertical-scroll-proportion="0.15805785">
+            <state line="23" column="13" selection-start="716" selection-end="716" vertical-scroll-proportion="0.21549296">
               <folding />
             </state>
           </provider>
         </entry>
       </file>
-      <file leaf-file-name="DependencyException.java" pinned="false" current="false" current-in-tab="false">
-        <entry file="file://$PROJECT_DIR$/src/com/google/inject/DependencyException.java">
+      <file leaf-file-name="KeyTest.java" pinned="false" current="true" current-in-tab="true">
+        <entry file="file://$PROJECT_DIR$/test/com/google/inject/KeyTest.java">
           <provider selected="true" editor-type-id="text-editor">
-            <state line="23" column="13" selection-start="736" selection-end="736" vertical-scroll-proportion="0.15805785">
+            <state line="14" column="0" selection-start="291" selection-end="291" vertical-scroll-proportion="0.23943663">
               <folding />
             </state>
           </provider>
         </entry>
       </file>
-      <file leaf-file-name="ConstructionContext.java" pinned="false" current="false" current-in-tab="false">
-        <entry file="file://$PROJECT_DIR$/src/com/google/inject/ConstructionContext.java">
+      <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="35" column="19" selection-start="1065" selection-end="1065" vertical-scroll-proportion="0.017561983">
+            <state line="34" column="36" selection-start="1083" selection-end="1083" vertical-scroll-proportion="0.33521128">
               <folding />
             </state>
           </provider>
@@ -439,11 +445,11 @@
           <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
         </PATH_ELEMENT>
         <PATH_ELEMENT>
-          <option name="myItemId" value="PsiDirectory:$PROJECT_DIR$/src" />
+          <option name="myItemId" value="PsiDirectory:$PROJECT_DIR$/test" />
           <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
         </PATH_ELEMENT>
         <PATH_ELEMENT>
-          <option name="myItemId" value="PsiDirectory:$PROJECT_DIR$/src/com/google/inject" />
+          <option name="myItemId" value="PsiDirectory:$PROJECT_DIR$/test/com/google/inject" />
           <option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
         </PATH_ELEMENT>
       </PATH>
@@ -460,7 +466,7 @@
       <showLibraryContents PackagesPane="false" />
       <hideEmptyPackages />
       <abbreviatePackageNames />
-      <showStructure PackagesPane="false" ProjectPane="false" Scope="false" Favorites="false" />
+      <showStructure Scope="false" ProjectPane="false" PackagesPane="false" Favorites="false" />
       <autoscrollToSource />
       <autoscrollFromSource />
       <sortByType />
@@ -500,21 +506,24 @@
     <key name="MoveMembersDialog.RECENTS_KEY">
       <recent name="com.google.inject.Key" />
     </key>
+    <key name="CopyClassDialog.RECENTS_KEY">
+      <recent name="" />
+    </key>
     <key name="MoveClassesOrPackagesDialog.RECENTS_KEY">
       <recent name="com.google.inject.util" />
     </key>
   </component>
   <component name="RestoreUpdateTree" />
-  <component name="RunManager" selected="JUnit.KeyTest.testEquality">
-    <tempConfiguration default="false" name="KeyTest.testEquality" type="JUnit" factoryName="JUnit" enabled="false" merge="false">
+  <component name="RunManager" selected="JUnit.AllTests">
+    <tempConfiguration default="false" name="AllTests" type="JUnit" factoryName="JUnit" enabled="false" merge="false">
       <pattern value="com.google.inject.*" />
       <module name="guice" />
       <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
       <option name="ALTERNATIVE_JRE_PATH" />
       <option name="PACKAGE_NAME" value="com.google.inject" />
-      <option name="MAIN_CLASS_NAME" value="com.google.inject.KeyTest" />
-      <option name="METHOD_NAME" value="testEquality" />
-      <option name="TEST_OBJECT" value="method" />
+      <option name="MAIN_CLASS_NAME" value="com.google.inject.AllTests" />
+      <option name="METHOD_NAME" />
+      <option name="TEST_OBJECT" value="class" />
       <option name="VM_PARAMETERS" />
       <option name="PARAMETERS" />
       <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
@@ -528,25 +537,6 @@
         <option name="Make" value="true" />
       </method>
     </tempConfiguration>
-    <configuration default="true" type="JUnit" factoryName="JUnit" enabled="false" merge="false">
-      <module name="" />
-      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
-      <option name="ALTERNATIVE_JRE_PATH" />
-      <option name="PACKAGE_NAME" />
-      <option name="MAIN_CLASS_NAME" />
-      <option name="METHOD_NAME" />
-      <option name="TEST_OBJECT" value="class" />
-      <option name="VM_PARAMETERS" />
-      <option name="PARAMETERS" />
-      <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
-      <option name="ADDITIONAL_CLASS_PATH" />
-      <option name="TEST_SEARCH_SCOPE">
-        <value defaultName="wholeProject" />
-      </option>
-      <method>
-        <option name="Make" value="true" />
-      </method>
-    </configuration>
     <configuration default="true" type="Applet" factoryName="Applet">
       <module name="" />
       <option name="MAIN_CLASS_NAME" />
@@ -576,6 +566,25 @@
       <option name="ENABLE_SWING_INSPECTOR" value="false" />
       <module name="" />
     </configuration>
+    <configuration default="true" type="JUnit" factoryName="JUnit" enabled="false" merge="false">
+      <module name="" />
+      <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
+      <option name="ALTERNATIVE_JRE_PATH" />
+      <option name="PACKAGE_NAME" />
+      <option name="MAIN_CLASS_NAME" />
+      <option name="METHOD_NAME" />
+      <option name="TEST_OBJECT" value="class" />
+      <option name="VM_PARAMETERS" />
+      <option name="PARAMETERS" />
+      <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
+      <option name="ADDITIONAL_CLASS_PATH" />
+      <option name="TEST_SEARCH_SCOPE">
+        <value defaultName="wholeProject" />
+      </option>
+      <method>
+        <option name="Make" value="true" />
+      </method>
+    </configuration>
   </component>
   <component name="ScopeViewComponent">
     <subPane subId="Project">
@@ -637,9 +646,8 @@
     <option name="UPDATE_RUN_STATUS" value="false" />
     <option name="UPDATE_RECURSIVELY" value="true" />
     <option name="MERGE_DRY_RUN" value="false" />
-    <configuration useDefault="true">/home/crazybob/.subversion</configuration>
+    <configuration useDefault="true">/Users/crazybob/.subversion</configuration>
     <remoteStatus />
-    <upgradeMode>auto</upgradeMode>
   </component>
   <component name="TodoView" selected-index="0">
     <todo-panel id="selected-file">
@@ -656,38 +664,38 @@
     </todo-panel>
   </component>
   <component name="ToolWindowManager">
-    <frame x="0" y="25" width="1916" height="1106" extended-state="0" />
+    <frame x="1" y="22" width="1916" height="1178" extended-state="0" />
     <editor active="false" />
     <layout>
       <window_info id="UI Designer" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="3" />
       <window_info id="CVS" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="8" />
       <window_info id="IDEtalk" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="3" />
-      <window_info id="Mach" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32919848" order="9" />
       <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="7" />
-      <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.15885837" order="0" />
-      <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.29580152" order="1" />
+      <window_info id="Project" active="true" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.15854311" order="0" />
+      <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.29509714" order="1" />
       <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.16236559" order="1" />
-      <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.28053436" order="10" />
+      <window_info id="Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.28029603" order="10" />
       <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.4" order="6" />
-      <window_info id="Profile" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32911393" order="13" />
       <window_info id="Module Dependencies" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="3" />
       <window_info id="Dependency Viewer" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="11" />
       <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.32919848" order="8" />
-      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.29103053" order="2" />
+      <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" weight="0.2904718" 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" />
       <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.3265306" order="4" />
+      <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.39978448" order="0" />
       <window_info id="IDEtalk Messages" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="8" />
       <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.34541985" order="12" />
+      <window_info id="Mach" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32919848" order="9" />
       <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="0" />
       <window_info id="Favorites" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="4" />
       <window_info id="Dependencies" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.33" order="5" />
       <window_info id="Compare Directories" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32977018" order="3" />
       <window_info id="Web" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" order="2" />
       <window_info id="EJB" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" order="3" />
+      <window_info id="Profile" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.32911393" order="13" />
       <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" weight="0.25" order="5" />
     </layout>
   </component>
@@ -772,107 +780,111 @@
     <option name="myLastEditedConfigurable" value="Default" />
   </component>
   <component name="editorHistoryManager">
-    <entry file="jar:///usr/local/buildtools/java/jdk1.5.0_06/jre/lib/rt.jar!/java/util/Arrays.class">
+    <entry file="file://$PROJECT_DIR$/src/com/google/inject/ContainerImpl.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="216" column="41" selection-start="9391" selection-end="9399" vertical-scroll-proportion="0.33333334">
+        <state line="72" column="23" selection-start="2310" selection-end="2310" vertical-scroll-proportion="0.7450704">
           <folding />
         </state>
       </provider>
     </entry>
     <entry file="file://$PROJECT_DIR$/src/com/google/inject/BindingBuilder.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="27" column="13" selection-start="893" selection-end="893" vertical-scroll-proportion="0.017561983">
+        <state line="143" column="51" selection-start="3844" selection-end="3844" vertical-scroll-proportion="1.1169014">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="file://$PROJECT_DIR$/src/com/google/inject/Factory.java">
+    <entry file="file://$PROJECT_DIR$/src/com/google/inject/ExternalContext.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="32" column="4" selection-start="954" selection-end="954" vertical-scroll-proportion="0.3161157">
-          <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="475" column="21" selection-start="15782" selection-end="15782" vertical-scroll-proportion="0.017561983">
+        <state line="40" column="14" selection-start="1164" selection-end="1164" vertical-scroll-proportion="0.51830983">
           <folding />
         </state>
       </provider>
     </entry>
     <entry file="file://$PROJECT_DIR$/src/com/google/inject/Binding.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="23" column="13" selection-start="755" selection-end="755" vertical-scroll-proportion="0.15805785">
+        <state line="23" column="13" selection-start="755" selection-end="755" vertical-scroll-proportion="0.21549296">
           <folding />
         </state>
       </provider>
     </entry>
     <entry file="file://$PROJECT_DIR$/src/com/google/inject/Scope2.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="21" column="17" selection-start="691" selection-end="691" vertical-scroll-proportion="0.12293389">
+        <state line="21" column="17" selection-start="691" selection-end="691" vertical-scroll-proportion="0.16760564">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="jar:///Users/crazybob/src.zip!/java/lang/ClassLoader.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="2022" column="0" selection-start="70824" selection-end="70824" vertical-scroll-proportion="0.85531914">
           <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="404" column="0" selection-start="12666" selection-end="12666" vertical-scroll-proportion="0.017561983">
+        <state line="404" column="0" selection-start="12618" selection-end="12618" vertical-scroll-proportion="0.023943663">
           <folding />
         </state>
       </provider>
     </entry>
-    <entry file="jar:///usr/local/buildtools/java/jdk1.5.0_06/jre/lib/rt.jar!/java/lang/reflect/ParameterizedType.class">
+    <entry file="jar:///Users/crazybob/src.zip!/java/lang/Class.java">
       <provider selected="true" editor-type-id="text-editor">
-        <state line="5" column="17" selection-start="159" selection-end="159" vertical-scroll-proportion="0.07024793">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="jar:///usr/local/buildtools/java/jdk1.5.0_06/jre/lib/rt.jar!/java/lang/reflect/Type.class">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="5" column="17" selection-start="159" selection-end="159" vertical-scroll-proportion="0.07024793">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/test/com/google/inject/KeyTest.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="21" column="24" selection-start="573" selection-end="573" vertical-scroll-proportion="0.2985537">
+        <state line="2489" column="9" selection-start="99816" selection-end="99816" vertical-scroll-proportion="0.59859157">
           <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="34" column="30" selection-start="1077" selection-end="1077" vertical-scroll-proportion="0.24586777">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/src/com/google/inject/util/Objects.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="23" column="13" selection-start="716" selection-end="716" vertical-scroll-proportion="0.15805785">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/src/com/google/inject/DependencyException.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="23" column="13" selection-start="736" selection-end="736" vertical-scroll-proportion="0.15805785">
-          <folding />
-        </state>
-      </provider>
-    </entry>
-    <entry file="file://$PROJECT_DIR$/src/com/google/inject/ConstructionContext.java">
-      <provider selected="true" editor-type-id="text-editor">
-        <state line="35" column="19" selection-start="1065" selection-end="1065" vertical-scroll-proportion="0.017561983">
+        <state line="34" column="36" selection-start="1083" selection-end="1083" vertical-scroll-proportion="0.33521128">
           <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="53" column="38" selection-start="1608" selection-end="1608" vertical-scroll-proportion="0.6322314">
+        <state line="37" column="22" selection-start="1090" selection-end="1090" vertical-scroll-proportion="0.33239436">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/src/com/google/inject/TypeToken.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="113" column="14" selection-start="3421" selection-end="3421" vertical-scroll-proportion="0.33239436">
+          <folding>
+            <element signature="imports" expanded="true" />
+          </folding>
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/test/com/google/inject/TypeTokenTest.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="42" column="55" selection-start="1307" selection-end="1307" vertical-scroll-proportion="0.67042255">
+          <folding>
+            <element signature="imports" expanded="true" />
+          </folding>
+        </state>
+      </provider>
+    </entry>
+    <entry file="jar:///System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Classes/classes.jar!/sun/reflect/generics/repository/ClassRepository.class">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="15" column="26" selection-start="851" selection-end="851" vertical-scroll-proportion="0.34244603">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/src/com/google/inject/util/Objects.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="23" column="13" selection-start="716" selection-end="716" vertical-scroll-proportion="0.21549296">
+          <folding />
+        </state>
+      </provider>
+    </entry>
+    <entry file="file://$PROJECT_DIR$/test/com/google/inject/KeyTest.java">
+      <provider selected="true" editor-type-id="text-editor">
+        <state line="14" column="0" selection-start="291" selection-end="291" vertical-scroll-proportion="0.23943663">
           <folding />
         </state>
       </provider>
diff --git a/src/com/google/inject/Container.java b/src/com/google/inject/Container.java
index 24a4d48..3fe50a5 100644
--- a/src/com/google/inject/Container.java
+++ b/src/com/google/inject/Container.java
@@ -81,7 +81,7 @@
   <T> T getInstance(Class<T> type, String name);
 
   /**
-   * Convenience method.&nbsp;Equivalent to {@code getInstance(type,
+   * Convenience method.&nbsp;Equivalent to {@code get(type,
    * DEFAULT_NAME)}.
    */
   <T> T getInstance(Class<T> type);
diff --git a/src/com/google/inject/ContainerBuilder.java b/src/com/google/inject/ContainerBuilder.java
index db3f156..bfd5fea 100644
--- a/src/com/google/inject/ContainerBuilder.java
+++ b/src/com/google/inject/ContainerBuilder.java
@@ -73,11 +73,11 @@
    */
   public ContainerBuilder() {
     // In the current container as the default Container implementation.
-    factories.put(Key.newInstance(Container.class, Key.DEFAULT_NAME),
+    factories.put(Key.get(Container.class, Key.DEFAULT_NAME),
         CONTAINER_FACTORY);
 
     // Inject the logger for the injected member's declaring class.
-    factories.put(Key.newInstance(Logger.class, Key.DEFAULT_NAME),
+    factories.put(Key.get(Logger.class, Key.DEFAULT_NAME),
         LOGGER_FACTORY);
   }
 
@@ -150,7 +150,7 @@
           }
         };
 
-    return factory(Key.newInstance(type, name), internalFactory, scope);
+    return factory(Key.get(type, name), internalFactory, scope);
   }
 
   /**
@@ -224,7 +224,7 @@
       }
     };
 
-    return factory(Key.newInstance(type, name), factory, scope);
+    return factory(Key.get(type, name), factory, scope);
   }
 
   /**
@@ -347,7 +347,7 @@
    * @return this builder
    */
   public <T> ContainerBuilder alias(Class<T> type, String name, String alias) {
-    return alias(Key.newInstance(type, name), Key.newInstance(type, alias));
+    return alias(Key.get(type, name), Key.get(type, alias));
   }
 
   /**
@@ -446,7 +446,7 @@
   public <T> ContainerBuilder constant(final Class<T> type, final String name,
       final T value) {
     InternalFactory<T> factory = new ConstantFactory<T>(value);
-    return factory(Key.newInstance(type, name), factory, Scope.DEFAULT);
+    return factory(Key.get(type, name), factory, Scope.DEFAULT);
   }
 
   /**
@@ -465,7 +465,7 @@
    * name.
    */
   public boolean contains(Class<?> type, String name) {
-    return factories.containsKey(Key.newInstance(type, name));
+    return factories.containsKey(Key.get(type, name));
   }
 
   /**
diff --git a/src/com/google/inject/ContainerImpl.java b/src/com/google/inject/ContainerImpl.java
index b80bd77..873fc30 100644
--- a/src/com/google/inject/ContainerImpl.java
+++ b/src/com/google/inject/ContainerImpl.java
@@ -64,7 +64,7 @@
     // Do we have a constant String factory of the same name?
     InternalFactory<String> stringFactory =
         (InternalFactory<String>) factories.get(
-            Key.newInstance(String.class, key.getName()));
+            Key.get(String.class, key.getName()));
     if (stringFactory == null
         || !(stringFactory instanceof ConstantFactory)) {
       return null;
@@ -219,7 +219,7 @@
       this.field = field;
       field.setAccessible(true);
 
-      Key<?> key = Key.newInstance(field.getType(), name);
+      Key<?> key = Key.get(field.getType(), name);
       factory = container.getFactory(field, key);
       if (factory == null) {
         throw new MissingDependencyException(
@@ -262,7 +262,7 @@
     for (Class<?> parameterType : parameterTypes) {
       Inject annotation = findInject(annotationsIterator.next());
       String name = annotation == null ? defaultName : annotation.value();
-      Key<?> key = Key.newInstance(parameterType, name);
+      Key<?> key = Key.get(parameterType, name);
       parameterInjectors.add(createParameterInjector(key, member));
     }
 
@@ -506,7 +506,7 @@
   @SuppressWarnings("unchecked")
   <T> T getInstance(Class<T> type, String name, InternalContext context) {
     ExternalContext<?> previous = context.getExternalContext();
-    Key<T> key = Key.newInstance(type, name);
+    Key<T> key = Key.get(type, name);
     context.setExternalContext(ExternalContext.newInstance(null, key, this));
     try {
       InternalFactory<? extends T> factory = getFactory(null, key);
diff --git a/src/com/google/inject/Key.java b/src/com/google/inject/Key.java
index 385a120..af1d489 100644
--- a/src/com/google/inject/Key.java
+++ b/src/com/google/inject/Key.java
@@ -19,10 +19,19 @@
 import static com.google.inject.util.Objects.nonNull;
 
 import java.lang.reflect.Type;
-import java.lang.reflect.ParameterizedType;
 
 /**
- * Binding key. Composed of the type to be injected and a name.
+ * Binding key. A type token and a name. Matches the type and name ({@link
+ * Inject#value()}) at a point of injection.
+ *
+ * <p>For example, {@code new Key<List<String>>("names") {}} will match:
+ *
+ * <pre>
+ *   @Inject("names")
+ *   public void setList(List<String> list) {
+ *     ...
+ *   }
+ * </pre>
  *
  * @author crazybob@google.com (Bob Lee)
  */
@@ -33,30 +42,26 @@
    */
   public static final String DEFAULT_NAME = "default";
 
-  final Class<T> rawType;
   final String name;
-  final String typeString;
-  final Type type;
+  final TypeToken<T> typeToken;
+  final int hashCode;
 
   /**
    * Constructs a new key. Derives the type from this class's type parameter.
-   * Requires client to create an empty anonymous class.
+   *
+   * <p>Clients create an empty anonymous subclass. Doing so embeds the type
+   * parameter in the anonymous class's type hierarchy so we can reconstitute
+   * it at runtime despite erasure.
    *
    * <p>Example usage for a binding of type {@code Foo} named "bar":
    * {@code new Key<Foo>("bar") {}}.
-   *
-   * <p>The curly braces in the example serve to create an empty anonymous
-   * class.
    */
+  @SuppressWarnings({"unchecked"})
   protected Key(String name) {
     this.name = nonNull(name, "name");
-    Type superclass = getClass().getGenericSuperclass();
-    if (superclass instanceof Class) {
-      throw new RuntimeException("Missing type parameter.");
-    }
-    this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
-    this.rawType = getRawType(type);
-    this.typeString = toString(type);
+    this.typeToken =
+        (TypeToken<T>) TypeToken.fromSuperclassTypeParameter(getClass());
+    this.hashCode = computeHashCode();
   }
 
   /**
@@ -67,58 +72,34 @@
     this(DEFAULT_NAME);
   }
 
+  /**
+   * Unsafe. Constructs a key from a manually specified type.
+   */
+  @SuppressWarnings({"unchecked"})
   private Key(Type type, String name) {
     this.name = nonNull(name, "name");
-    this.type = nonNull(type, "type");
-    this.rawType = getRawType(nonNull(type, "type"));
-    this.typeString = toString(type);
+    this.typeToken = (TypeToken<T>) TypeToken.get(type);
+    this.hashCode = computeHashCode();
   }
 
   /**
-   * Calls {@code getName()} on {@code Class}es and {@code toString()} on other
-   * {@code Type}s.
+   * Constructs a key from a manually specified type token.
    */
-  private static String toString(Type type) {
-    return type instanceof Class<?>
-        ? ((Class<?>) type).getName()
-        : type.toString();
+  private Key(TypeToken<T> typeToken, String name) {
+    this.name = nonNull(name, "name");
+    this.typeToken = typeToken;
+    this.hashCode = computeHashCode();
   }
 
-  @SuppressWarnings({"unchecked"})
-  private static <T> Class<T> getRawType(Type type) {
-    if (type instanceof Class<?>) {
-      // type is a normal class.
-      return (Class<T>) type;
-    } else {
-      // type is a parameterized type.
-      if (!(type instanceof ParameterizedType)) {
-        unexpectedType(type, ParameterizedType.class);
-      }
-      ParameterizedType parameterizedType = (ParameterizedType) type;
-
-      // I'm not exactly sure why getRawType() returns Type instead of Class.
-      // Neal isn't either but suspects some pathological case related
-      // to nested classes exists.
-      Type rawType = parameterizedType.getRawType();
-      if (!(rawType instanceof Class<?>)) {
-        unexpectedType(rawType, Class.class);
-      }
-      return (Class<T>) rawType;
-    }
-  }
-
-  static void unexpectedType(Type token, Class<?> expected) {
-    throw new AssertionError(
-        "Unexpected type. Expected: " + expected.getName()
-        + ", got: " + token.getClass().getName()
-        + ", for type token: " + token.toString() + ".");
+  private int computeHashCode() {
+    return typeToken.hashCode() * 31 + name.hashCode();
   }
 
   /**
-   * Gets the raw type of this binding.
+   * Gets token representing the type to be injected.
    */
-  public Class<T> getRawType() {
-    return rawType;
+  public TypeToken<T> getTypeToken() {
+    return typeToken;
   }
 
   /**
@@ -128,71 +109,81 @@
     return name;
   }
 
-  /**
-   * Gets the type of this binding.
-   */
-  public Type getType() {
-    return type;
-  }
-
   public int hashCode() {
-    return typeString.hashCode();
+    return this.hashCode;
   }
 
-  /**
-   * Gets the key corresponding the raw type.
-   */
-  public Key<?> rawKey() {
-    return Key.newInstance(rawType, name);
+  @Deprecated
+  Class<T> getRawType() {
+    return (Class<T>) typeToken.getRawType();
   }
 
-  /**
-   * Compares the binding name and type. Uses {@code String} representations
-   * to compare types as the reflection API doesn't give us a lot of options
-   * when it comes to comparing parameterized types.
-   *
-   * @inheritDoc
-   */
   public boolean equals(Object o) {
     if (o == this) {
       return true;
     }
-    if (!(o instanceof Key)) {
+    if (!(o instanceof Key<?>)) {
       return false;
     }
-    Key other = (Key) o;
-    return name.equals(other.name) && typeString.equals(other.typeString);
+    Key<?> other = (Key<?>) o;
+    return name.equals(other.name) && typeToken.equals(other.typeToken);
   }
 
   public String toString() {
-    return "Key[type=" + typeString + ", name='" + name + "']";
+    return Key.class.getSimpleName()
+        + "[type=" + typeToken + ", name='" + name + "']";
   }
 
   /**
-   * Constructs a key from a raw type.
+   * Gets a key for a {@code Class}. Defaults name to {@link #DEFAULT_NAME}.
    */
-  public static <T> Key<T> newInstance(Class<T> type) {
-    return new Key<T>(type, DEFAULT_NAME) {};
+  public static <T> Key<T> get(Class<T> type) {
+    return new ManualKey<T>(type, DEFAULT_NAME);
   }
 
   /**
-   * Constructs a key from a raw type and a name.
+   * Gets a key for a {@code Class} and a name.
    */
-  public static <T> Key<T> newInstance(Class<T> type, String name) {
-    return new Key<T>(type, name) {};
+  public static <T> Key<T> get(Class<T> type, String name) {
+    return new ManualKey<T>(type, name);
   }
 
   /**
-   * Constructs a key from a type.
+   * Gets a key for a type. Defaults name to {@link #DEFAULT_NAME}.
    */
-  public static Key<?> newInstance(Type type) {
-    return new Key<Object>(type, DEFAULT_NAME) {};
+  public static Key<?> get(Type type) {
+    return new ManualKey<Object>(type, DEFAULT_NAME);
   }
 
   /**
-   * Constructs a key from a type and a name.
+   * Gets a key for a type and a name.
    */
-  public static Key<?> newInstance(Type type, String name) {
-    return new Key<Object>(type, name) {};
+  public static Key<?> get(Type type, String name) {
+    return new ManualKey<Object>(type, name);
+  }
+
+  /**
+   * Gets a key for a type token. Defaults name to {@link #DEFAULT_NAME}.
+   */
+  public static <T> Key<T> get(TypeToken<T> typeToken) {
+    return new ManualKey<T>(typeToken, DEFAULT_NAME);
+  }
+
+  /**
+   * Gets key for a type token and a name.
+   */
+  public static <T> Key<T> get(TypeToken<T> typeToken, String name) {
+    return new ManualKey<T>(typeToken, name);
+  }
+
+  private static class ManualKey<T> extends Key<T> {
+
+    private ManualKey(Type type, String name) {
+      super(type, name);
+    }
+
+    private ManualKey(TypeToken<T> typeToken, String name) {
+      super(typeToken, name);
+    }
   }
 }
diff --git a/src/com/google/inject/TypeToken.java b/src/com/google/inject/TypeToken.java
new file mode 100644
index 0000000..67a1c43
--- /dev/null
+++ b/src/com/google/inject/TypeToken.java
@@ -0,0 +1,165 @@
+/**
+ * Copyright (C) 2006 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;
+
+import static com.google.inject.util.Objects.nonNull;
+
+import java.lang.reflect.Type;
+import java.lang.reflect.ParameterizedType;
+
+/**
+ * Represents a generic type {@code T}.
+ *
+ * <p>Assumes {@code Type} implements {@code equals()} and {@code hashCode()}
+ * as a value (as opposed to identity) comparison.
+ *
+ * @author crazybob@google.com (Bob Lee)
+ */
+public abstract class TypeToken<T> {
+
+  final Class<? super T> rawType;
+  final Type type;
+
+  /**
+   * Constructs a new type token. Derives represented class from type
+   * parameter.
+   *
+   * <p>Clients create an empty anonymous subclass. Doing so embeds the type
+   * parameter in the anonymous class's type hierarchy so we can reconstitute
+   * it at runtime despite erasure.
+   *
+   * <p>For example: {@code TypeToken<List<String>> t = new
+   * TypeToken<List<String>>() {};}
+   */
+  @SuppressWarnings({"unchecked"})
+  protected TypeToken() {
+    this.type = getSuperclassTypeParameter(getClass());
+    this.rawType = (Class<? super T>) getRawType(type);
+  }
+
+  /**
+   * Unsafe. Constructs a type token manually.
+   */
+  @SuppressWarnings({"unchecked"})
+  private TypeToken(Type type) {
+    this.rawType = (Class<? super T>) getRawType(nonNull(type, "type"));
+    this.type = type;
+  }
+
+  /**
+   * Gets type from super class's type parameter.
+   */
+  static Type getSuperclassTypeParameter(Class<?> subclass) {
+    Type superclass = subclass.getGenericSuperclass();
+    if (superclass instanceof Class) {
+      throw new RuntimeException("Missing type parameter.");
+    }
+    return ((ParameterizedType) superclass).getActualTypeArguments()[0];
+  }
+
+  /**
+   * Gets type token from super class's type parameter.
+   */
+  static TypeToken<?> fromSuperclassTypeParameter(Class<?> subclass) {
+    return new ManualTypeToken<Object>(getSuperclassTypeParameter(subclass));
+  }
+
+  @SuppressWarnings({"unchecked"})
+  private static Class<?> getRawType(Type type) {
+    if (type instanceof Class<?>) {
+      // type is a normal class.
+      return (Class<?>) type;
+    } else {
+      // type is a parameterized type.
+      if (!(type instanceof ParameterizedType)) {
+        unexpectedType(type, ParameterizedType.class);
+      }
+      ParameterizedType parameterizedType = (ParameterizedType) type;
+
+      // I'm not exactly sure why getRawType() returns Type instead of Class.
+      // Neal isn't either but suspects some pathological case related
+      // to nested classes exists.
+      Type rawType = parameterizedType.getRawType();
+      if (!(rawType instanceof Class<?>)) {
+        unexpectedType(rawType, Class.class);
+      }
+      return (Class<?>) rawType;
+    }
+  }
+
+  /**
+   * Gets the raw type.
+   */
+  Class<? super T> getRawType() {
+    return rawType;
+  }
+
+  /**
+   * Gets underlying {@code Type} instance.
+   */
+  public Type getType() {
+    return type;
+  }
+
+  public int hashCode() {
+    return type.hashCode();
+  }
+
+  public boolean equals(Object o) {
+    if (o == this) {
+      return true;
+    }
+    if (!(o instanceof TypeToken<?>)) {
+      return false;
+    }
+    TypeToken<?> t = (TypeToken<?>) o;
+    return type.equals(t.type);
+  }
+
+  public String toString() {
+    return type instanceof Class<?>
+          ? ((Class<?>) type).getName()
+          : type.toString();
+  }
+
+  static void unexpectedType(Type token, Class<?> expected) {
+    throw new AssertionError(
+        "Unexpected type. Expected: " + expected.getName()
+        + ", got: " + token.getClass().getName()
+        + ", for type token: " + token.toString() + ".");
+  }
+
+  /**
+   * Gets type token for the given {@code Type} instance.
+   */
+  public static TypeToken<?> get(Type type) {
+    return new ManualTypeToken<Object>(type);
+  }
+
+  /**
+   * Gets type token for the given {@code Class} instance.
+   */
+  public static <T> TypeToken<T> get(Class<T> type) {
+    return new ManualTypeToken<T>(type);
+  }
+
+  private static class ManualTypeToken<T> extends TypeToken<T> {
+    public ManualTypeToken(Type type) {
+      super(type);
+    }
+  }
+}
diff --git a/test/com/google/inject/AllTests.java b/test/com/google/inject/AllTests.java
index 0e5123f..c70c8f5 100644
--- a/test/com/google/inject/AllTests.java
+++ b/test/com/google/inject/AllTests.java
@@ -32,6 +32,7 @@
   public static Test suite() {
     TestSuite suite = new TestSuite();
 
+    suite.addTestSuite(TypeTokenTest.class);
     suite.addTestSuite(KeyTest.class);
     suite.addTestSuite(ConstantConversionTest.class);
     suite.addTestSuite(ContainerTest.class);
diff --git a/test/com/google/inject/FactoryTest.java b/test/com/google/inject/FactoryTest.java
index 7356fd6..a6e7d59 100644
--- a/test/com/google/inject/FactoryTest.java
+++ b/test/com/google/inject/FactoryTest.java
@@ -29,7 +29,7 @@
   public void testInjection() throws Exception {
     ContainerBuilder cb = new ContainerBuilder();
 
-    // Called from getInstance().
+    // Called from get().
     cb.factory(Foo.class, createFactory(Foo.class, "default", null));
 
     // Called during singleton loading.
diff --git a/test/com/google/inject/KeyTest.java b/test/com/google/inject/KeyTest.java
index 5985d2b..90571e3 100644
--- a/test/com/google/inject/KeyTest.java
+++ b/test/com/google/inject/KeyTest.java
@@ -15,12 +15,20 @@
 
   public void foo(List<String> a, List<String> b) {}
 
-  public void testEquality() throws Exception {
+  public void testEquality() {
+    assertEquals(
+      new Key<List<String>>("foo") {},
+      Key.get(new TypeToken<List<String>>() {}, "foo")
+    );
+  }
+
+  public void testTypeEquality() throws Exception {
     Method m = getClass().getMethod("foo", List.class, List.class);
     Type[] types = m.getGenericParameterTypes();
     assertEquals(types[0], types[1]);
     Key<List<String>> k = new Key<List<String>>() {};
-    assertEquals(types[0], k.getType());
-    assertFalse(types[0].equals(new Key<List<Integer>>() {}.getType()));
+    assertEquals(types[0], k.getTypeToken().getType());
+    assertFalse(types[0].equals(
+        new Key<List<Integer>>() {}.getTypeToken().getType()));
   }
 }
diff --git a/test/com/google/inject/TypeTokenTest.java b/test/com/google/inject/TypeTokenTest.java
new file mode 100644
index 0000000..2af282a
--- /dev/null
+++ b/test/com/google/inject/TypeTokenTest.java
@@ -0,0 +1,53 @@
+/**
+ * Copyright (C) 2006 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;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+
+/**
+ * @author crazybob@google.com (Bob Lee)
+ */
+public class TypeTokenTest extends TestCase {
+
+  public void testEquality() {
+    TypeToken<List<String>> t1 = new TypeToken<List<String>>() {};
+    TypeToken<List<String>> t2 = new TypeToken<List<String>>() {};
+    TypeToken<List<Integer>> t3 = new TypeToken<List<Integer>>() {};
+    TypeToken<String> t4 = new TypeToken<String>() {};
+
+    assertEquals(t1, t2);
+    assertEquals(t2, t1);
+
+    assertFalse(t2.equals(t3));
+    assertFalse(t3.equals(t2));
+
+    assertFalse(t2.equals(t4));
+    assertFalse(t4.equals(t2));
+
+    TypeToken<String> t5 = TypeToken.get(String.class);
+    assertEquals(t4, t5);
+  }
+
+  public void testMissingTypeParameter() {
+    try {
+      new TypeToken() {};
+      fail();
+    } catch (RuntimeException e) { /* expected */ }
+  }
+}