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) {
+ }
+ }
}