Made TypeLiteral equals() and hashCode() much more robust.
git-svn-id: https://google-guice.googlecode.com/svn/trunk@156 d779f126-a31b-0410-b53b-1d3aecad763e
diff --git a/guice.ipr b/guice.ipr
index ccd1b86..653cae8 100644
--- a/guice.ipr
+++ b/guice.ipr
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<project version="4" relativePaths="true">
+<project version="4" relativePaths="false">
<component name="AntConfiguration">
<defaultAnt bundledAnt="true" />
<buildFile url="file://$PROJECT_DIR$/build.xml">
@@ -15,7 +15,7 @@
<class-settings class="com.google.devtools.intellig.configcheck.ProjectPathChecker" />
<class-settings class="com.google.devtools.intellig.configcheck.PythonSdkChecker" />
<class-settings class="com.google.devtools.intellig.configcheck.ProjectJdkChecker">
- <setting name="getProjectJdk" value="$PROJECT_DIR$/../../buildtools/java/jdk1.5.0_06" />
+ <setting name="getProjectJdk" value="/Users/crazybob/buildtools/java/jdk1.5.0_06" />
<setting name="getModuleJdks" value="rO0ABXNyABFqYXZhLnV0aWwuSGFzaFNldLpEhZWWuLc0AwAAeHB3DAAAABA/QAAAAAAAAHg=" />
</class-settings>
<class-settings class="com.google.devtools.intellig.configcheck.ClearOutputChecker" />
diff --git a/src/com/google/inject/TypeLiteral.java b/src/com/google/inject/TypeLiteral.java
index 3ae040f..5073117 100644
--- a/src/com/google/inject/TypeLiteral.java
+++ b/src/com/google/inject/TypeLiteral.java
@@ -19,6 +19,7 @@
import static com.google.inject.util.Objects.nonNull;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.util.Arrays;
/**
* Represents a generic type {@code T}. Java doesn't yet provide a way to
@@ -41,6 +42,7 @@
final Class<? super T> rawType;
final Type type;
+ final int hashCode;
/**
* Constructs a new type literal. Derives represented class from type
@@ -54,15 +56,17 @@
protected TypeLiteral() {
this.type = getSuperclassTypeParameter(getClass());
this.rawType = (Class<? super T>) getRawType(type);
+ this.hashCode = hashCode(type);
}
/**
* Unsafe. Constructs a type literal manually.
*/
@SuppressWarnings("unchecked")
- private TypeLiteral(Type type) {
+ TypeLiteral(Type type) {
this.rawType = (Class<? super T>) getRawType(nonNull(type, "type"));
this.type = type;
+ this.hashCode = hashCode(type);
}
/**
@@ -122,7 +126,7 @@
}
public int hashCode() {
- return type.hashCode();
+ return this.hashCode;
}
public boolean equals(Object o) {
@@ -132,8 +136,9 @@
if (!(o instanceof TypeLiteral<?>)) {
return false;
}
- TypeLiteral<?> t = (TypeLiteral<?>) o;
- return type.equals(t.type);
+ TypeLiteral<?> other = (TypeLiteral<?>) o;
+
+ return equals(type, other.type);
}
public String toString() {
@@ -168,4 +173,62 @@
super(type);
}
}
+
+ static int hashCode(Type type) {
+ if (type instanceof ParameterizedType) {
+ ParameterizedType p = (ParameterizedType) type;
+ int h = p.getRawType().hashCode();
+ for (Type argument : p.getActualTypeArguments()) {
+ h = h * 31 + hashCode(argument);
+ }
+ return h;
+ }
+
+ if (type instanceof Class) {
+ // Class specifies hashCode().
+ return type.hashCode();
+ }
+
+ // This isn't a type we support. Could be a generic array type, wildcard
+ // type, etc.
+ return type.hashCode();
+ }
+
+ static boolean equals(Type a, Type b) {
+ if (a instanceof Class) {
+ // Class already specifies equals().
+ return a.equals(b);
+ }
+
+ if (a instanceof ParameterizedType) {
+ if (!(b instanceof ParameterizedType)) {
+ return false;
+ }
+
+ ParameterizedType pa = (ParameterizedType) a;
+ ParameterizedType pb = (ParameterizedType) b;
+
+ if (!pa.getRawType().equals(pb.getRawType())) {
+ return false;
+ }
+
+ Type[] aa = pa.getActualTypeArguments();
+ Type[] ba = pb.getActualTypeArguments();
+ if (aa.length != ba.length) {
+ return false;
+ }
+
+ for (int i = 0; i < aa.length; i++) {
+ if (!equals(aa[i], ba[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ // This isn't a type we support. Could be a generic array type, wildcard
+ // type, etc.
+ return false;
+ }
}
diff --git a/src/com/google/inject/TypeWithArgument.java b/src/com/google/inject/TypeWithArgument.java
new file mode 100644
index 0000000..f38a559
--- /dev/null
+++ b/src/com/google/inject/TypeWithArgument.java
@@ -0,0 +1,43 @@
+/**
+ * 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 java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+
+class TypeWithArgument implements ParameterizedType {
+
+ final Type rawType;
+ final Type typeArgument;
+
+ TypeWithArgument(Type rawType, Type typeArgument) {
+ this.rawType = rawType;
+ this.typeArgument = typeArgument;
+ }
+
+ public Type[] getActualTypeArguments() {
+ return new Type[] { typeArgument };
+ }
+
+ public Type getRawType() {
+ return rawType;
+ }
+
+ public Type getOwnerType() {
+ return null;
+ }
+}
diff --git a/src/com/google/inject/name/Names.java b/src/com/google/inject/name/Names.java
index 81e8308..3a77722 100644
--- a/src/com/google/inject/name/Names.java
+++ b/src/com/google/inject/name/Names.java
@@ -40,7 +40,7 @@
}
/**
- * Binds a string constant for each property.
+ * Creates a constant binding to {@code @Named(key)} for each property.
*/
public static void bindProperties(ContainerBuilder builder,
Map<String, String> properties) {
@@ -53,7 +53,7 @@
}
/**
- * Binds a string constant for each property.
+ * Creates a constant binding to {@code @Named(key)} for each property.
*/
public static void bindProperties(ContainerBuilder builder,
Properties properties) {
diff --git a/test/com/google/inject/TypeLiteralTest.java b/test/com/google/inject/TypeLiteralTest.java
index 43f4553..08bd1ba 100644
--- a/test/com/google/inject/TypeLiteralTest.java
+++ b/test/com/google/inject/TypeLiteralTest.java
@@ -19,12 +19,20 @@
import junit.framework.TestCase;
import java.util.List;
+import java.lang.reflect.Type;
/**
* @author crazybob@google.com (Bob Lee)
*/
public class TypeLiteralTest extends TestCase {
+ public void testWithParameterizedTypeImpl() {
+ TypeLiteral<List<String>> a = new TypeLiteral<List<String>>() {};
+ TypeLiteral<List<String>> b = new TypeLiteral<List<String>>(
+ new TypeWithArgument(List.class, String.class)) {};
+ assertEquals(a, b);
+ }
+
public void testEquality() {
TypeLiteral<List<String>> t1 = new TypeLiteral<List<String>>() {};
TypeLiteral<List<String>> t2 = new TypeLiteral<List<String>>() {};