Fixing issue 142.

git-svn-id: https://google-guice.googlecode.com/svn/trunk@513 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/src/com/google/inject/internal/Types.java b/src/com/google/inject/internal/Types.java
deleted file mode 100644
index 9ca7a6b..0000000
--- a/src/com/google/inject/internal/Types.java
+++ /dev/null
@@ -1,305 +0,0 @@
-/**
- * Copyright (C) 2008 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.internal;
-
-import com.google.common.base.Objects;
-import com.google.common.collect.ImmutableMap;
-import com.google.inject.TypeLiteral;
-import java.io.Serializable;
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.Arrays;
-import java.util.Map;
-
-/**
- * @author crazybob@google.com (Bob Lee)
- */
-public class Types {
-  private Types() {}
-
-  private static final Map<TypeLiteral<?>, TypeLiteral<?>> PRIMITIVE_TO_WRAPPER
-      = new ImmutableMap.Builder<TypeLiteral<?>, TypeLiteral<?>>()
-          .put(TypeLiteral.get(boolean.class), TypeLiteral.get(Boolean.class))
-          .put(TypeLiteral.get(byte.class), TypeLiteral.get(Byte.class))
-          .put(TypeLiteral.get(short.class), TypeLiteral.get(Short.class))
-          .put(TypeLiteral.get(int.class), TypeLiteral.get(Integer.class))
-          .put(TypeLiteral.get(long.class), TypeLiteral.get(Long.class))
-          .put(TypeLiteral.get(float.class), TypeLiteral.get(Float.class))
-          .put(TypeLiteral.get(double.class), TypeLiteral.get(Double.class))
-          .put(TypeLiteral.get(char.class), TypeLiteral.get(Character.class))
-          .put(TypeLiteral.get(void.class), TypeLiteral.get(Void.class))
-          .build();
-
-  /**
-   * Returns an equivalent (but not necessarily equal) type literal that is
-   * free of primitive types. Type literals of primitives will return the
-   * corresponding wrapper types.
-   */
-  public static <T> TypeLiteral<T> wrapPrimitives(TypeLiteral<T> typeLiteral) {
-    @SuppressWarnings("unchecked")
-    TypeLiteral<T> wrappedPrimitives = (TypeLiteral<T>) PRIMITIVE_TO_WRAPPER.get(typeLiteral);
-    return wrappedPrimitives != null
-        ? wrappedPrimitives
-        : typeLiteral;
-  }
-
-  /**
-   * Returns a type that is functionally equal but not necessarily equal
-   * according to {@link Object#equals(Object) Object.equals()}. The returned
-   * type is {@link Serializable}.
-   */
-  public static Type canonicalize(Type type) {
-    if (type instanceof ParameterizedTypeImpl
-        || type instanceof GenericArrayTypeImpl) {
-      return type;
-
-    } else if (type instanceof ParameterizedType) {
-      ParameterizedType p = (ParameterizedType) type;
-      return newParameterizedType(p.getOwnerType(),
-          p.getRawType(), p.getActualTypeArguments());
-
-    } else if (type instanceof GenericArrayType) {
-      GenericArrayType g = (GenericArrayType) type;
-      return newGenericArrayType(g.getGenericComponentType());
-
-    } else if (type instanceof Class<?> && ((Class<?>) type).isArray()) {
-      Class<?> c = (Class<?>) type;
-      return newGenericArrayType(c.getComponentType());
-
-    } else {
-      // type is either serializable as-is or unsupported
-      return type;
-    }
-  }
-
-  public static ParameterizedType newTypeWithArgument(Type rawType, Type... typeArguments) {
-    return newParameterizedType(null, rawType, typeArguments);
-  }
-
-  public static ParameterizedType newParameterizedType(
-      Type ownerType, Type rawType, Type... typeArguments) {
-    return new ParameterizedTypeImpl(ownerType, rawType, typeArguments);
-  }
-
-  public static GenericArrayType newGenericArrayType(Type componentType) {
-    return new GenericArrayTypeImpl(componentType);
-  }
-
-  public static Class<?> getRawType(Type type) {
-    if (type instanceof Class<?>) {
-      // type is a normal class.
-      return (Class<?>) type;
-
-    } else if (type instanceof ParameterizedType) {
-      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<?>)) {
-        throw unexpectedType(rawType, Class.class);
-      }
-      return (Class<?>) rawType;
-
-    } else if (type instanceof GenericArrayType) {
-      // TODO: Is this sufficient?
-      return Object[].class;
-
-    } else {
-      // type is a parameterized type.
-      throw unexpectedType(type, ParameterizedType.class);
-    }
-  }
-
-  private static AssertionError unexpectedType(Type type, Class<?> expected) {
-    return new AssertionError(
-        "Unexpected type. Expected: " + expected.getName()
-        + ", got: " + type.getClass().getName()
-        + ", for type literal: " + type.toString() + ".");
-  }
-
-  /**
-   * Returns true if {@code a} and {@code b} are equal.
-   */
-  public static boolean equals(Type a, Type b) {
-    if (a == b) {
-      // also handles (a == null && b == null)
-      return true;
-
-    } else if (a instanceof Class) {
-      // Class already specifies equals().
-      return a.equals(b);
-
-    } else if (a instanceof ParameterizedType) {
-      if (!(b instanceof ParameterizedType)) {
-        return false;
-      }
-
-      ParameterizedType pa = (ParameterizedType) a;
-      ParameterizedType pb = (ParameterizedType) b;
-      return Objects.equal(pa.getOwnerType(), pb.getOwnerType())
-          && pa.getRawType().equals(pb.getRawType())
-          && Arrays.equals(pa.getActualTypeArguments(), pb.getActualTypeArguments());
-
-    } else if (a instanceof GenericArrayType) {
-      if (!(b instanceof GenericArrayType)) {
-        return false;
-      }
-
-      GenericArrayType ga = (GenericArrayType) a;
-      GenericArrayType gb = (GenericArrayType) b;
-      return equals(ga.getGenericComponentType(), gb.getGenericComponentType());
-
-    } else {
-      // This isn't a type we support. Could be a generic array type, wildcard
-      // type, etc.
-      return false;
-    }
-  }
-
-  /**
-   * Returns the hashCode of {@code type}.
-   */
-  public static int hashCode(Type type) {
-    if (type instanceof Class) {
-      // Class specifies hashCode().
-      return type.hashCode();
-
-    } else if (type instanceof ParameterizedType) {
-      ParameterizedType p = (ParameterizedType) type;
-      return Arrays.hashCode(p.getActualTypeArguments())
-          ^ p.getRawType().hashCode()
-          ^ hashCodeOrZero(p.getOwnerType());
-
-    } else if (type instanceof GenericArrayType) {
-      return hashCode(((GenericArrayType) type).getGenericComponentType());
-
-    } else {
-      // This isn't a type we support. Could be a generic array type, wildcard type, etc.
-      return hashCodeOrZero(type);
-    }
-  }
-
-  private static int hashCodeOrZero(Object o) {
-    return o != null ? o.hashCode() : 0;
-  }
-
-  public static String toString(Type type) {
-    if (type instanceof Class<?>) {
-      return ((Class) type).getName();
-
-    } else if (type instanceof ParameterizedType) {
-      ParameterizedType parameterizedType = (ParameterizedType) type;
-      Type[] arguments = parameterizedType.getActualTypeArguments();
-      Type ownerType = parameterizedType.getOwnerType();
-      StringBuilder stringBuilder = new StringBuilder();
-      if (ownerType != null) {
-        stringBuilder.append(toString(ownerType)).append(".");
-      }
-      stringBuilder.append(toString(parameterizedType.getRawType()))
-          .append("<")
-          .append(toString(arguments[0]));
-      for (int i = 1; i < arguments.length; i++) {
-        stringBuilder.append(", ").append(toString(arguments[i]));
-      }
-      return stringBuilder.append(">").toString();
-
-    } else if (type instanceof GenericArrayType) {
-      return toString(((GenericArrayType) type).getGenericComponentType()) + "[]";
-
-    } else {
-      return type.toString();
-    }
-  }
-
-  private static class ParameterizedTypeImpl implements ParameterizedType, Serializable {
-    private final Type ownerType;
-    private final Type rawType;
-    private final Type[] typeArguments;
-
-    private ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) {
-      this.ownerType = ownerType == null ? null : canonicalize(ownerType);
-      this.rawType = canonicalize(rawType);
-      this.typeArguments = typeArguments.clone();
-      for (int t = 0; t < this.typeArguments.length; t++) {
-        if (this.typeArguments[t] instanceof Class<?>
-            && ((Class) this.typeArguments[t]).isPrimitive()) {
-          throw new IllegalArgumentException(
-              "Parameterized types may not have primitive arguments: " + this.typeArguments[t]);
-        }
-        this.typeArguments[t] = canonicalize(this.typeArguments[t]);
-      }
-    }
-
-    public Type[] getActualTypeArguments() {
-      return typeArguments.clone();
-    }
-
-    public Type getRawType() {
-      return rawType;
-    }
-
-    public Type getOwnerType() {
-      return ownerType;
-    }
-
-    @Override public boolean equals(Object other) {
-      return other instanceof ParameterizedType
-          && Types.equals(this, (ParameterizedType) other);
-    }
-
-    @Override public int hashCode() {
-      return Types.hashCode(this);
-    }
-
-    @Override public String toString() {
-      return Types.toString(this);
-    }
-
-    private static final long serialVersionUID = 0;
-  }
-
-  private static class GenericArrayTypeImpl implements GenericArrayType, Serializable {
-    private final Type componentType;
-
-    private GenericArrayTypeImpl(Type componentType) {
-      this.componentType = canonicalize(componentType);
-    }
-
-    public Type getGenericComponentType() {
-      return componentType;
-    }
-
-    @Override public boolean equals(Object o) {
-      return o instanceof GenericArrayType
-          && Types.equals(this, (GenericArrayType) o);
-    }
-
-    @Override public int hashCode() {
-      return Types.hashCode(this);
-    }
-
-    @Override public String toString() {
-      return Types.toString(this);
-    }
-
-    private static final long serialVersionUID = 0;
-  }
-}
diff --git a/src/com/google/inject/name/Names.java b/src/com/google/inject/name/Names.java
index 758538e..f68117e 100644
--- a/src/com/google/inject/name/Names.java
+++ b/src/com/google/inject/name/Names.java
@@ -19,7 +19,7 @@
 import com.google.inject.Binder;
 import com.google.inject.Key;
 import com.google.inject.spi.SourceProviders;
-
+import java.util.Enumeration;
 import java.util.Map;
 import java.util.Properties;
 
@@ -44,7 +44,8 @@
   }
 
   /**
-   * Creates a constant binding to {@code @Named(key)} for each property.
+   * Creates a constant binding to {@code @Named(key)} for each entry in
+   * {@code properties}.
    */
   public static void bindProperties(final Binder binder,
       final Map<String, String> properties) {
@@ -62,7 +63,9 @@
   }
 
   /**
-   * Creates a constant binding to {@code @Named(key)} for each property.
+   * Creates a constant binding to {@code @Named(key)} for each property. This
+   * method binds all properties including those inherited from 
+   * {@link Properties#defaults defaults}.
    */
   public static void bindProperties(final Binder binder,
       final Properties properties) {
@@ -70,10 +73,11 @@
         SourceProviders.defaultSource(),
         new Runnable() {
           public void run() {
-            for (Map.Entry<Object, Object> entry : properties.entrySet()) {
-              String key = (String) entry.getKey();
-              String value = (String) entry.getValue();
-              binder.bind(Key.get(String.class, new NamedImpl(key))).toInstance(value);
+            // use enumeration to include the default properties
+            for (Enumeration<?> e = properties.propertyNames(); e.hasMoreElements(); ) {
+              String propertyName = (String) e.nextElement();
+              String value = properties.getProperty(propertyName);
+              binder.bind(Key.get(String.class, new NamedImpl(propertyName))).toInstance(value);
             }
           }
         });
diff --git a/test/com/google/inject/internal/TypesTest.java b/test/com/google/inject/internal/TypesTest.java
deleted file mode 100644
index 3d89809..0000000
--- a/test/com/google/inject/internal/TypesTest.java
+++ /dev/null
@@ -1,105 +0,0 @@
-/**
- * Copyright (C) 2008 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.internal;
-
-import static com.google.inject.Asserts.assertEqualsBothWays;
-import com.google.inject.Asserts;
-import junit.framework.TestCase;
-
-import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.List;
-import java.util.Map;
-
-/**
- * @author jessewilson@google.com (Jesse Wilson)
- */
-public class TypesTest extends TestCase {
-
-  // generic types for comparison
-  Map<String, Integer> map;
-  Inner<Float, Double> inner;
-  List<String[][]> list;
-
-  private ParameterizedType mapStringInteger;
-  private ParameterizedType innerFloatDouble;
-  private ParameterizedType listStringArray;
-  private GenericArrayType stringArray;
-
-  protected void setUp() throws Exception {
-    super.setUp();
-    mapStringInteger = (ParameterizedType) getClass().getDeclaredField("map").getGenericType();
-    innerFloatDouble = (ParameterizedType) getClass().getDeclaredField("inner").getGenericType();
-    listStringArray = (ParameterizedType) getClass().getDeclaredField("list").getGenericType();
-    stringArray = (GenericArrayType) listStringArray.getActualTypeArguments()[0];
-  }
-
-  public void testDefensiveCopies() {
-    Type[] arguments = new Type[] { String.class, Integer.class };
-    ParameterizedType parameterizedType = Types.newTypeWithArgument(Map.class, arguments);
-    arguments[0] = null;
-    assertEquals(String.class, parameterizedType.getActualTypeArguments()[0]);
-    parameterizedType.getActualTypeArguments()[1] = null;
-    assertEquals(Integer.class, parameterizedType.getActualTypeArguments()[1]);
-  }
-
-  public void testTypeWithOwnerType() {
-    ParameterizedType actual = Types.newParameterizedType(
-        TypesTest.class, Inner.class, Float.class, Double.class);
-    assertEquals(TypesTest.class, actual.getOwnerType());
-    assertEqualsBothWays(innerFloatDouble, actual);
-    assertEquals(innerFloatDouble.toString(), actual.toString());
-  }
-
-  public void testTypeParametersMustNotBePrimitives() {
-    try {
-      Types.newTypeWithArgument(Map.class, String.class, int.class);
-      fail();
-    } catch (IllegalArgumentException expected) {
-      Asserts.assertContains(expected.getMessage(),
-          "Parameterized types may not have primitive arguments: int");
-    }
-  }
-
-  public void testEqualsAndHashcode() {
-    ParameterizedType parameterizedType
-        = Types.newTypeWithArgument(Map.class, String.class, Integer.class);
-    assertEqualsBothWays(mapStringInteger, parameterizedType);
-    assertEquals(mapStringInteger.toString(), parameterizedType.toString());
-
-    GenericArrayType genericArrayType = Types.newGenericArrayType(
-        Types.newGenericArrayType(String.class));
-    assertEqualsBothWays(stringArray, genericArrayType);
-    assertEquals(stringArray.toString(), genericArrayType.toString());
-  }
-
-  public void testToString() {
-    assertEquals("java.lang.String", Types.toString(String.class));
-    assertEquals("java.lang.String[][]", Types.toString(stringArray));
-    assertEquals("java.util.Map<java.lang.String, java.lang.Integer>",
-        Types.toString(mapStringInteger));
-    assertEquals("java.util.List<java.lang.String[][]>",
-        Types.toString(listStringArray));
-    assertEquals(innerFloatDouble.toString(),
-        Types.toString(innerFloatDouble));
-  }
-
-  @SuppressWarnings("UnusedDeclaration")
-  class Inner<T1, T2> {}
-}
diff --git a/test/com/google/inject/name/NamesTest.java b/test/com/google/inject/name/NamesTest.java
index 113ae49..ad49065 100644
--- a/test/com/google/inject/name/NamesTest.java
+++ b/test/com/google/inject/name/NamesTest.java
@@ -17,11 +17,17 @@
 
 package com.google.inject.name;
 
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.AbstractModule;
 import static com.google.inject.Asserts.assertEqualWhenReserialized;
 import static com.google.inject.Asserts.assertEqualsBothWays;
-import junit.framework.TestCase;
-
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import com.google.inject.Key;
 import java.io.IOException;
+import java.util.Map;
+import java.util.Properties;
+import junit.framework.TestCase;
 
 /**
  * @author jessewilson@google.com (Jesse Wilson)
@@ -45,4 +51,59 @@
   public void testNamedIsSerializable() throws IOException {
     assertEqualWhenReserialized(Names.named("foo"));
   }
+
+  public void testBindPropertiesUsingProperties() {
+    final Properties teams = new Properties();
+    teams.setProperty("SanJose", "Sharks");
+    teams.setProperty("Edmonton", "Oilers");
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      protected void configure() {
+        Names.bindProperties(binder(), teams);
+      }
+    });
+
+    assertEquals("Sharks", injector.getInstance(Key.get(String.class, Names.named("SanJose"))));
+    assertEquals("Oilers", injector.getInstance(Key.get(String.class, Names.named("Edmonton"))));
+  }
+
+  public void testBindPropertiesUsingMap() {
+    final Map<String, String> properties = ImmutableMap.of(
+        "SanJose", "Sharks", "Edmonton", "Oilers");
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      protected void configure() {
+        Names.bindProperties(binder(), properties);
+      }
+    });
+
+    assertEquals("Sharks", injector.getInstance(Key.get(String.class, Names.named("SanJose"))));
+    assertEquals("Oilers", injector.getInstance(Key.get(String.class, Names.named("Edmonton"))));
+  }
+
+  public void testBindPropertiesIncludesInheritedProperties() {
+    Properties defaults = new Properties();
+    defaults.setProperty("Edmonton", "Eskimos");
+    defaults.setProperty("Regina", "Pats");
+
+    final Properties teams = new Properties(defaults);
+    teams.setProperty("SanJose", "Sharks");
+    teams.setProperty("Edmonton", "Oilers");
+
+    Injector injector = Guice.createInjector(new AbstractModule() {
+      protected void configure() {
+        Names.bindProperties(binder(), teams);
+      }
+    });
+
+    assertEquals("Pats", injector.getInstance(Key.get(String.class, Names.named("Regina"))));
+    assertEquals("Oilers", injector.getInstance(Key.get(String.class, Names.named("Edmonton"))));
+    assertEquals("Sharks", injector.getInstance(Key.get(String.class, Names.named("SanJose"))));
+
+    try {
+      injector.getInstance(Key.get(String.class, Names.named("Calgary")));
+      fail();
+    } catch (RuntimeException expected) {
+    }
+  }
 }