Author: limpbizkit
Date: Fri Nov 14 00:43:40 2008
New Revision: 663

Added:
    trunk/test/com/google/inject/TypeLiteralTypeResolutionTest.java
       - copied, changed from r653,  
/trunk/test/com/google/inject/internal/TypeResolverTest.java
Removed:
    trunk/src/com/google/inject/internal/TypeResolver.java
Modified:
    trunk/src/com/google/inject/TypeLiteral.java
    trunk/src/com/google/inject/internal/MoreTypes.java
    trunk/src/com/google/inject/internal/ProviderMethodsModule.java
    trunk/src/com/google/inject/spi/InjectionPoint.java
    trunk/test/com/google/inject/AllTests.java
    trunk/test/com/google/inject/spi/InjectionPointTest.java

Log:
Made type resolution way fast. We no longer build any collections --  
instead we just do everything on demand. A very naive benchmark showed this  
to be much faster (50s vs 3s).

Also merged TypeResolver with TypeLiteral. This exposes a bunch of new APIs  
for types - such as getting the generic parameter types of a method. I'm  
not convinced that we should be exposing all of this, but it's nice for  
extensions. For example, @Provides methods need type resolution.

Modified: trunk/src/com/google/inject/TypeLiteral.java
==============================================================================
--- trunk/src/com/google/inject/TypeLiteral.java        (original)
+++ trunk/src/com/google/inject/TypeLiteral.java        Fri Nov 14 00:43:40 2008
@@ -16,12 +16,21 @@

  package com.google.inject;

+import static com.google.common.base.Preconditions.checkArgument;
  import static com.google.common.base.Preconditions.checkNotNull;
+import com.google.common.collect.ImmutableList;
  import com.google.inject.internal.MoreTypes;
  import static com.google.inject.internal.MoreTypes.canonicalize;
  import com.google.inject.util.Types;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
  import java.lang.reflect.ParameterizedType;
  import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
+import java.util.List;

  /**
   * Represents a generic type [EMAIL PROTECTED] T}. Java doesn't yet provide a 
way to
@@ -140,5 +149,152 @@
     */
    public static <T> TypeLiteral<T> get(Class<T> type) {
      return new TypeLiteral<T>(type);
+  }
+
+
+  /** Returns an immutable list of the resolved types. */
+  private List<Type> resolveAll(Type[] types) {
+    Type[] result = new Type[types.length];
+    for (int t = 0; t < types.length; t++) {
+      result[t] = resolve(types[t]);
+    }
+    return ImmutableList.of(result);
+  }
+
+  /**
+   * Resolves known type parameters in [EMAIL PROTECTED] toResolve} and 
returns the  
result.
+   */
+  Type resolve(Type toResolve) {
+    while (true) {
+      if (toResolve instanceof TypeVariable) {
+        TypeVariable original = (TypeVariable) toResolve;
+        toResolve = MoreTypes.resolveTypeVariable(type, rawType, original);
+        if (toResolve == original) {
+          return toResolve;
+        }
+
+      } else if (toResolve instanceof GenericArrayType) {
+        GenericArrayType original = (GenericArrayType) toResolve;
+        Type componentType = original.getGenericComponentType();
+        Type newComponentType = resolve(componentType);
+        return componentType == newComponentType
+            ? original
+            : Types.arrayOf(newComponentType);
+
+      } else if (toResolve instanceof ParameterizedType) {
+        ParameterizedType original = (ParameterizedType) toResolve;
+        Type ownerType = original.getOwnerType();
+        Type newOwnerType = resolve(ownerType);
+        boolean changed = newOwnerType != ownerType;
+
+        Type[] args = original.getActualTypeArguments();
+        for (int t = 0, length = args.length; t < length; t++) {
+          Type resolvedTypeArgument = resolve(args[t]);
+          if (resolvedTypeArgument != args[t]) {
+            if (!changed) {
+              args = args.clone();
+              changed = true;
+            }
+            args[t] = resolvedTypeArgument;
+          }
+        }
+
+        return changed
+            ? Types.newParameterizedTypeWithOwner(newOwnerType,  
original.getRawType(), args)
+            : original;
+
+      } else {
+        return toResolve;
+      }
+    }
+  }
+
+  /**
+   * Returns the generic form of [EMAIL PROTECTED] supertype}. For example, if 
this  
is [EMAIL PROTECTED]
+   * ArrayList<String>}, this returns [EMAIL PROTECTED] Iterable<String>} 
given the  
input [EMAIL PROTECTED]
+   * Iterable.class}.
+   *
+   * @param supertype a superclass of, or interface implemented by, this.
+   */
+  public Type getSupertype(Class<?> supertype) {
+    checkArgument(supertype.isAssignableFrom(rawType),
+        "%s is not a supertype of %s", supertype, this.type);
+    return resolve(MoreTypes.getGenericSupertype(type, rawType,  
supertype));
+  }
+
+  /**
+   * Returns the resolved generic type of [EMAIL PROTECTED] field}.
+   *
+   * @param field a field defined by this or any superclass.
+   */
+  public Type getFieldType(Field field) {
+    checkArgument(field.getDeclaringClass().isAssignableFrom(rawType),
+        "%s is not defined by a supertype of %s", field, type);
+    return resolve(field.getGenericType());
+  }
+
+  /**
+   * Returns the resolved generic parameter types of [EMAIL PROTECTED]  
methodOrConstructor}.
+   *
+   * @param methodOrConstructor a method or constructor defined by this or  
any supertype.
+   */
+  public List<Type> getParameterTypes(Member methodOrConstructor) {
+    Type[] genericParameterTypes;
+
+    if (methodOrConstructor instanceof Method) {
+      Method method = (Method) methodOrConstructor;
+      checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
+          "%s is not defined by a supertype of %s", method, type);
+      genericParameterTypes = method.getGenericParameterTypes();
+
+    } else if (methodOrConstructor instanceof Constructor) {
+      Constructor constructor = (Constructor) methodOrConstructor;
+       
checkArgument(constructor.getDeclaringClass().isAssignableFrom(rawType),
+          "%s does not construct a supertype of %s", constructor, type);
+      genericParameterTypes = constructor.getGenericParameterTypes();
+
+    } else {
+      throw new IllegalArgumentException("Not a method or a constructor: "  
+ methodOrConstructor);
+    }
+
+    return resolveAll(genericParameterTypes);
+  }
+
+  /**
+   * Returns the resolved generic exception types thrown by [EMAIL PROTECTED]  
constructor}.
+   *
+   * @param methodOrConstructor a method or constructor defined by this or  
any supertype.
+   */
+  public List<Type> getExceptionTypes(Member methodOrConstructor) {
+    Type[] genericExceptionTypes;
+
+    if (methodOrConstructor instanceof Method) {
+      Method method = (Method) methodOrConstructor;
+      checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
+          "%s is not defined by a supertype of %s", method, type);
+      genericExceptionTypes = method.getGenericExceptionTypes();
+
+    } else if (methodOrConstructor instanceof Constructor) {
+      Constructor<?> constructor = (Constructor<?>) methodOrConstructor;
+       
checkArgument(constructor.getDeclaringClass().isAssignableFrom(rawType),
+          "%s does not construct a supertype of %s", constructor, type);
+      genericExceptionTypes = constructor.getGenericExceptionTypes();
+
+    } else {
+      throw new IllegalArgumentException("Not a method or a constructor: "  
+ methodOrConstructor);
+    }
+
+    return resolveAll(genericExceptionTypes);
+  }
+
+  /**
+   * Returns the resolved generic return type of [EMAIL PROTECTED] method}.
+   *
+   * @param method a method defined by this or any supertype.
+   */
+  public Type getReturnType(Method method) {
+    checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
+        "%s is not defined by a supertype of %s", method, type);
+    return resolve(method.getGenericReturnType());
    }
  }

Modified: trunk/src/com/google/inject/internal/MoreTypes.java
==============================================================================
--- trunk/src/com/google/inject/internal/MoreTypes.java (original)
+++ trunk/src/com/google/inject/internal/MoreTypes.java Fri Nov 14 00:43:40  
2008
@@ -26,13 +26,16 @@
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Field;
  import java.lang.reflect.GenericArrayType;
+import java.lang.reflect.GenericDeclaration;
  import java.lang.reflect.Member;
  import java.lang.reflect.Method;
  import java.lang.reflect.ParameterizedType;
  import java.lang.reflect.Type;
+import java.lang.reflect.TypeVariable;
  import java.lang.reflect.WildcardType;
  import java.util.Arrays;
  import java.util.Map;
+import java.util.NoSuchElementException;

  /**
   * Static methods for working with types that we aren't publishing in the
@@ -337,6 +340,82 @@
        throw new IllegalArgumentException(
            "Unsupported implementation class for Member, " +  
member.getClass());
      }
+  }
+
+  /**
+   * Returns the generic supertype for [EMAIL PROTECTED] supertype}. For 
example,  
given a class [EMAIL PROTECTED]
+   * IntegerSet}, the result for when supertype is [EMAIL PROTECTED] 
Set.class} is  
[EMAIL PROTECTED] Set<Integer>} and the
+   * result when the supertype is [EMAIL PROTECTED] Collection.class} is 
[EMAIL PROTECTED]  
Collection<Integer>}.
+   */
+  public static Type getGenericSupertype(Type type, Class<?> rawType,  
Class<?> toResolve) {
+    if (toResolve == rawType) {
+      return type;
+    }
+
+    // we skip searching through interfaces if unknown is an interface
+    if (toResolve.isInterface()) {
+      Class[] interfaces = rawType.getInterfaces();
+      for (int i = 0, length = interfaces.length; i < length; i++) {
+        if (interfaces[i] == toResolve) {
+          return rawType.getGenericInterfaces()[i];
+        } else if (toResolve.isAssignableFrom(interfaces[i])) {
+          return getGenericSupertype(rawType.getGenericInterfaces()[i],  
interfaces[i], toResolve);
+        }
+      }
+    }
+
+    // check our supertypes
+    if (!rawType.isInterface()) {
+      while (rawType != Object.class) {
+        Class<?> rawSupertype = rawType.getSuperclass();
+        if (rawSupertype == toResolve) {
+          return rawType.getGenericSuperclass();
+        } else if (toResolve.isAssignableFrom(rawSupertype)) {
+          return getGenericSupertype(rawType.getGenericSuperclass(),  
rawSupertype, toResolve);
+        }
+        rawType = rawSupertype;
+      }
+    }
+
+    // we can't resolve this further
+    return toResolve;
+  }
+
+  public static Type resolveTypeVariable(Type type, Class<?> rawType,  
TypeVariable unknown) {
+    Class<?> declaredByRaw = declaringClassOf(unknown);
+
+    // we can't reduce this further
+    if (declaredByRaw == null) {
+      return unknown;
+    }
+
+    Type declaredBy = getGenericSupertype(type, rawType, declaredByRaw);
+    if (declaredBy instanceof ParameterizedType) {
+      int index = indexOf(declaredByRaw.getTypeParameters(), unknown);
+      return ((ParameterizedType)  
declaredBy).getActualTypeArguments()[index];
+    }
+
+    return unknown;
+  }
+
+  private static int indexOf(Object[] array, Object toFind) {
+    for (int i = 0; i < array.length; i++) {
+      if (toFind.equals(array[i])) {
+        return i;
+      }
+    }
+    throw new NoSuchElementException();
+  }
+
+  /**
+   * Returns the declaring class of [EMAIL PROTECTED] typeVariable}, or [EMAIL 
PROTECTED] null}  
if it was not declared by
+   * a class.
+   */
+  private static Class<?> declaringClassOf(TypeVariable typeVariable) {
+    GenericDeclaration genericDeclaration =  
typeVariable.getGenericDeclaration();
+    return genericDeclaration instanceof Class
+        ? (Class<?>) genericDeclaration
+        : null;
    }

    public static class ParameterizedTypeImpl implements ParameterizedType,  
Serializable {

Modified: trunk/src/com/google/inject/internal/ProviderMethodsModule.java
==============================================================================
--- trunk/src/com/google/inject/internal/ProviderMethodsModule.java      
(original)
+++ trunk/src/com/google/inject/internal/ProviderMethodsModule.java     Fri Nov 
 
14 00:43:40 2008
@@ -16,9 +16,8 @@

  package com.google.inject.internal;

-import com.google.common.base.Preconditions;
-import static com.google.common.base.Preconditions.checkNotNull;
  import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
  import com.google.common.collect.Lists;
  import com.google.inject.Binder;
  import com.google.inject.Key;
@@ -43,11 +42,11 @@
   */
  public final class ProviderMethodsModule implements Module {
    private final Module delegate;
-  private final TypeResolver typeResolver;
+  private final TypeLiteral<?> typeLiteral;

    private ProviderMethodsModule(Module delegate) {
      this.delegate = checkNotNull(delegate, "delegate");
-    this.typeResolver = new TypeResolver(this.delegate.getClass());
+    this.typeLiteral = TypeLiteral.get(this.delegate.getClass());
    }

    /**
@@ -108,7 +107,7 @@

      // prepare the parameter providers
      List<Provider<?>> parameterProviders = Lists.newArrayList();
-    List<Type> parameterTypes = typeResolver.getParameterTypes(method);
+    List<Type> parameterTypes = typeLiteral.getParameterTypes(method);
      Annotation[][] parameterAnnotations = method.getParameterAnnotations();
      for (int i = 0; i < parameterTypes.size(); i++) {
        Key<?> key = getKey(errors, TypeLiteral.get(parameterTypes.get(i)),
@@ -118,7 +117,7 @@

      // Define T as the method's return type.
      @SuppressWarnings("unchecked") TypeLiteral<T> returnType
-        = (TypeLiteral<T>)  
TypeLiteral.get(typeResolver.getReturnType(method));
+        = (TypeLiteral<T>)  
TypeLiteral.get(typeLiteral.getReturnType(method));

      Key<T> key = getKey(errors, returnType, method,  
method.getAnnotations());
      Class<? extends Annotation> scopeAnnotation

Modified: trunk/src/com/google/inject/spi/InjectionPoint.java
==============================================================================
--- trunk/src/com/google/inject/spi/InjectionPoint.java (original)
+++ trunk/src/com/google/inject/spi/InjectionPoint.java Fri Nov 14 00:43:40  
2008
@@ -21,12 +21,12 @@
  import com.google.inject.ConfigurationException;
  import com.google.inject.Inject;
  import com.google.inject.Key;
+import com.google.inject.TypeLiteral;
  import com.google.inject.internal.Annotations;
  import com.google.inject.internal.Errors;
  import com.google.inject.internal.ErrorsException;
  import com.google.inject.internal.MoreTypes;
  import com.google.inject.internal.Nullability;
-import com.google.inject.internal.TypeResolver;
  import java.io.ObjectStreamException;
  import java.io.Serializable;
  import java.lang.annotation.Annotation;
@@ -62,22 +62,22 @@
      this.optional = optional;
    }

-  InjectionPoint(TypeResolver typeResolver, Method method) {
+  InjectionPoint(TypeLiteral<?> type, Method method) {
      this.member = method;

      Inject inject = method.getAnnotation(Inject.class);
      this.optional = inject.optional();

-    this.dependencies = forMember(method, typeResolver,  
method.getParameterAnnotations());
+    this.dependencies = forMember(method, type,  
method.getParameterAnnotations());
    }

-  InjectionPoint(TypeResolver typeResolver, Constructor<?> constructor) {
+  InjectionPoint(TypeLiteral<?> type, Constructor<?> constructor) {
      this.member = constructor;
      this.optional = false;
-    this.dependencies = forMember(constructor, typeResolver,  
constructor.getParameterAnnotations());
+    this.dependencies = forMember(constructor, type,  
constructor.getParameterAnnotations());
    }

-  InjectionPoint(TypeResolver typeResolver, Field field) {
+  InjectionPoint(TypeLiteral<?> type, Field field) {
      this.member = field;

      Inject inject = field.getAnnotation(Inject.class);
@@ -88,7 +88,7 @@
      Errors errors = new Errors(field);
      Key<?> key = null;
      try {
-      key = Annotations.getKey(typeResolver.getFieldType(field), field,  
annotations, errors);
+      key = Annotations.getKey(type.getFieldType(field), field,  
annotations, errors);
      } catch (ErrorsException e) {
        errors.merge(e.getErrors());
      }
@@ -98,7 +98,7 @@
          newDependency(key, Nullability.allowsNull(annotations), -1));
    }

-  private ImmutableList<Dependency<?>> forMember(Member member,  
TypeResolver typeResolver,
+  private ImmutableList<Dependency<?>> forMember(Member member,  
TypeLiteral<?> type,
        Annotation[][] paramterAnnotations) {
      Errors errors = new Errors(member);
      Iterator<Annotation[]> annotationsIterator =  
Arrays.asList(paramterAnnotations).iterator();
@@ -106,7 +106,7 @@
      List<Dependency<?>> dependencies = Lists.newArrayList();
      int index = 0;

-    for (Type parameterType : typeResolver.getParameterTypes(member)) {
+    for (Type parameterType : type.getParameterTypes(member)) {
        try {
          Annotation[] parameterAnnotations = annotationsIterator.next();
          Key<?> key = Annotations.getKey(parameterType, member,  
parameterAnnotations, errors);
@@ -183,8 +183,8 @@
     */
    public static InjectionPoint forConstructorOf(Type type) {
      Errors errors = new Errors(type);
-    TypeResolver typeResolver = new TypeResolver(type);
-    Class<?> rawType = typeResolver.getRawType();
+    TypeLiteral<?> typeLiteral = TypeLiteral.get(type);
+    Class<?> rawType = MoreTypes.getRawType(type);

      Constructor<?> injectableConstructor = null;
      for (Constructor<?> constructor : rawType.getDeclaredConstructors()) {
@@ -206,7 +206,7 @@
      errors.throwConfigurationExceptionIfErrorsExist();

      if (injectableConstructor != null) {
-      return new InjectionPoint(typeResolver, injectableConstructor);
+      return new InjectionPoint(typeLiteral, injectableConstructor);
      }

      // If no annotated constructor is found, look for a no-arg constructor  
instead.
@@ -221,7 +221,7 @@
        }

        checkForMisplacedBindingAnnotations(noArgConstructor, errors);
-      return new InjectionPoint(typeResolver, noArgConstructor);
+      return new InjectionPoint(typeLiteral, noArgConstructor);
      } catch (NoSuchMethodException e) {
        errors.missingConstructor(rawType);
        throw new ConfigurationException(errors.getMessages());
@@ -239,8 +239,9 @@
     */
    public static void addForStaticMethodsAndFields(Type type,  
Collection<InjectionPoint> sink) {
      Errors errors = new Errors();
-    addInjectionPoints(type, Factory.FIELDS, true, sink, errors);
-    addInjectionPoints(type, Factory.METHODS, true, sink, errors);
+    TypeLiteral<?> typeLiteral = TypeLiteral.get(type);
+    addInjectionPoints(typeLiteral, Factory.FIELDS, true, sink, errors);
+    addInjectionPoints(typeLiteral, Factory.METHODS, true, sink, errors);
      errors.throwConfigurationExceptionIfErrorsExist();
    }

@@ -256,8 +257,9 @@
    public static void addForInstanceMethodsAndFields(Type type,  
Collection<InjectionPoint> sink) {
      // TODO (crazybob): Filter out overridden members.
      Errors errors = new Errors();
-    addInjectionPoints(type, Factory.FIELDS, false, sink, errors);
-    addInjectionPoints(type, Factory.METHODS, false, sink, errors);
+    TypeLiteral<?> typeLiteral = TypeLiteral.get(type);
+    addInjectionPoints(typeLiteral, Factory.FIELDS, false, sink, errors);
+    addInjectionPoints(typeLiteral, Factory.METHODS, false, sink, errors);
      errors.throwConfigurationExceptionIfErrorsExist();
    }

@@ -269,27 +271,25 @@
      }
    }

-  private static <M extends Member & AnnotatedElement> void  
addInjectionPoints(Type type,
+  private static <M extends Member & AnnotatedElement> void  
addInjectionPoints(TypeLiteral<?> type,
        Factory<M> factory, boolean statics, Collection<InjectionPoint>  
injectionPoints,
        Errors errors) {
-    if (type == Object.class) {
+    if (type.getType() == Object.class) {
        return;
      }

-    TypeResolver typeResolver = new TypeResolver(type);
-
      // Add injectors for superclass first.
-    Type superType =  
typeResolver.getSupertype(MoreTypes.getRawType(type).getSuperclass());
-    addInjectionPoints(superType, factory, statics, injectionPoints,  
errors);
+    Type superType =  
type.getSupertype(MoreTypes.getRawType(type.getType()).getSuperclass());
+    addInjectionPoints(TypeLiteral.get(superType), factory, statics,  
injectionPoints, errors);

      // Add injectors for all members next
-    addInjectorsForMembers(typeResolver, factory, statics,  
injectionPoints, errors);
+    addInjectorsForMembers(type, factory, statics, injectionPoints,  
errors);
    }

    private static <M extends Member & AnnotatedElement> void  
addInjectorsForMembers(
-      TypeResolver typeResolver, Factory<M> factory, boolean statics,
+      TypeLiteral<?> typeResolver, Factory<M> factory, boolean statics,
        Collection<InjectionPoint> injectionPoints, Errors errors) {
-    for (M member : factory.getMembers(typeResolver.getRawType())) {
+    for (M member :  
factory.getMembers(MoreTypes.getRawType(typeResolver.getType()))) {
        if (isStatic(member) != statics) {
          continue;
        }
@@ -318,7 +318,7 @@
        public Field[] getMembers(Class<?> type) {
          return type.getDeclaredFields();
        }
-      public InjectionPoint create(TypeResolver typeResolver, Field  
member, Errors errors) {
+      public InjectionPoint create(TypeLiteral<?> typeResolver, Field  
member, Errors errors) {
          return new InjectionPoint(typeResolver, member);
        }
      };
@@ -327,14 +327,14 @@
        public Method[] getMembers(Class<?> type) {
          return type.getDeclaredMethods();
        }
-      public InjectionPoint create(TypeResolver typeResolver, Method  
member, Errors errors) {
+      public InjectionPoint create(TypeLiteral<?> typeResolver, Method  
member, Errors errors) {
          checkForMisplacedBindingAnnotations(member, errors);
          return new InjectionPoint(typeResolver, member);
        }
      };

      M[] getMembers(Class<?> type);
-    InjectionPoint create(TypeResolver typeResolver, M member, Errors  
errors);
+    InjectionPoint create(TypeLiteral<?> typeResolver, M member, Errors  
errors);
    }

    private static final long serialVersionUID = 0;

Modified: trunk/test/com/google/inject/AllTests.java
==============================================================================
--- trunk/test/com/google/inject/AllTests.java  (original)
+++ trunk/test/com/google/inject/AllTests.java  Fri Nov 14 00:43:40 2008
@@ -77,6 +77,7 @@
      suite.addTestSuite(RequestInjectionTest.class);
      suite.addTestSuite(SuperclassTest.class);
      suite.addTestSuite(TypeLiteralTest.class);
+    suite.addTestSuite(TypeLiteralTypeResolutionTest.class);

      // commands
      suite.addTestSuite(ElementsTest.class);

Copied: trunk/test/com/google/inject/TypeLiteralTypeResolutionTest.java  
(from r653, /trunk/test/com/google/inject/internal/TypeResolverTest.java)
==============================================================================
--- /trunk/test/com/google/inject/internal/TypeResolverTest.java        
(original)
+++ trunk/test/com/google/inject/TypeLiteralTypeResolutionTest.java     Fri Nov 
 
14 00:43:40 2008
@@ -14,11 +14,12 @@
   * limitations under the License.
   */

-package com.google.inject.internal;
+package com.google.inject;

  import com.google.common.collect.ImmutableList;
  import static com.google.inject.Asserts.assertEqualsBothWays;
  import static com.google.inject.Asserts.assertNotSerializable;
+import com.google.inject.util.Types;
  import static com.google.inject.util.Types.arrayOf;
  import static com.google.inject.util.Types.listOf;
  import static com.google.inject.util.Types.newParameterizedType;
@@ -29,28 +30,41 @@
  import java.lang.reflect.Field;
  import java.lang.reflect.Method;
  import java.lang.reflect.Type;
+import java.util.AbstractCollection;
  import java.util.AbstractList;
  import java.util.ArrayList;
+import java.util.Arrays;
  import java.util.Collection;
+import java.util.HashMap;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import junit.framework.TestCase;

-public class TypeResolverTest extends TestCase {
+/**
+ * This test checks that TypeLiteral can perform type resolution on its  
members.
+ *
+ * @author [EMAIL PROTECTED] (Jesse Wilson)
+ */
+public class TypeLiteralTypeResolutionTest extends TestCase {
    Type arrayListOfString = newParameterizedType(ArrayList.class,  
String.class);
    Type hasGenericFieldsOfShort = newParameterizedTypeWithOwner(
        getClass(), HasGenericFields.class, Short.class);
    Type hasGenericConstructorOfShort = newParameterizedTypeWithOwner(
-      getClass(), HasGenericConstructor.class, Short.class);
+      getClass(), GenericConstructor.class, Short.class);
    Type throwerOfNpe = newParameterizedTypeWithOwner(
        getClass(), Thrower.class, NullPointerException.class);
    Type hasArrayOfShort = newParameterizedTypeWithOwner(getClass(),  
HasArray.class, Short.class);
    Type hasRelatedOfString = newParameterizedTypeWithOwner(
        getClass(), HasRelated.class, String.class, String.class);
+  Type mapK = Map.class.getTypeParameters()[0];
+  Type hashMapK = HashMap.class.getTypeParameters()[0];
+  Type setEntryKV;
+  Type entryStringInteger = setOf(newParameterizedTypeWithOwner(
+      Map.class, Map.Entry.class, String.class, Integer.class));
    Field list;
    Field instance;
-  Constructor<HasGenericConstructor> newHasGenericConstructor;
+  Constructor<GenericConstructor> newHasGenericConstructor;
    Constructor<Thrower> newThrower;
    Constructor newString;
    Method stringIndexOf;
@@ -60,12 +74,12 @@
    Method echo;
    Method throwS;

-  protected void setUp() throws Exception {
+  @Override protected void setUp() throws Exception {
      super.setUp();

      list = HasGenericFields.class.getField("list");
      instance = HasGenericFields.class.getField("instance");
-    newHasGenericConstructor =  
HasGenericConstructor.class.getConstructor(Object.class, Object.class);
+    newHasGenericConstructor =  
GenericConstructor.class.getConstructor(Object.class, Object.class);
      newThrower = Thrower.class.getConstructor();
      stringIndexOf = String.class.getMethod("indexOf", String.class);
      newString = String.class.getConstructor(String.class);
@@ -74,10 +88,11 @@
      getSetOfArray = HasArray.class.getMethod("getSetOfArray");
      echo = HasRelated.class.getMethod("echo", Object.class);
      throwS = Thrower.class.getMethod("throwS");
+    setEntryKV =  
HashMap.class.getMethod("entrySet").getGenericReturnType();
    }

    public void testDirectInheritance() throws NoSuchMethodException {
-    TypeResolver resolver = new TypeResolver(arrayListOfString);
+    TypeLiteral<?> resolver = TypeLiteral.get(arrayListOfString);
      assertEquals(listOf(String.class),
          resolver.getReturnType(List.class.getMethod("subList", int.class,  
int.class)));
      assertEquals(ImmutableList.<Type>of(String.class),
@@ -85,7 +100,7 @@
    }

    public void testGenericSupertype() {
-    TypeResolver resolver = new TypeResolver(arrayListOfString);
+    TypeLiteral<?> resolver = TypeLiteral.get(arrayListOfString);
      assertEquals(newParameterizedType(Collection.class, String.class),
          resolver.getSupertype(Collection.class));
      assertEquals(newParameterizedType(Iterable.class, String.class),
@@ -96,7 +111,7 @@
    }

    public void testRecursiveTypeVariable() {
-    TypeResolver resolver = new TypeResolver(MyInteger.class);
+    TypeLiteral<?> resolver = TypeLiteral.get(MyInteger.class);
      assertEquals(MyInteger.class,  
resolver.getParameterTypes(comparableCompareTo).get(0));
    }

@@ -110,7 +125,7 @@
    }

    public void testFields() {
-    TypeResolver resolver = new TypeResolver(hasGenericFieldsOfShort);
+    TypeLiteral<?> resolver = TypeLiteral.get(hasGenericFieldsOfShort);
      assertEquals(listOf(Short.class), resolver.getFieldType(list));
      assertEquals(Short.class, resolver.getFieldType(instance));
    }
@@ -121,17 +136,17 @@
    }

    public void testGenericConstructor() throws NoSuchMethodException {
-    TypeResolver resolver = new TypeResolver(hasGenericConstructorOfShort);
+    TypeLiteral<?> resolver =  
TypeLiteral.get(hasGenericConstructorOfShort);
      assertEquals(Short.class,  
resolver.getParameterTypes(newHasGenericConstructor).get(0));
    }

-  static class HasGenericConstructor<S> {
+  static class GenericConstructor<S> {
      @SuppressWarnings("UnusedDeclaration")
-    public <T> HasGenericConstructor(S s, T t) {}
+    public <T> GenericConstructor(S s, T t) {}
    }

    public void testThrowsExceptions() {
-    TypeResolver resolver = new TypeResolver(throwerOfNpe);
+    TypeLiteral<?> resolver = TypeLiteral.get(throwerOfNpe);
      assertEquals(NullPointerException.class,  
resolver.getExceptionTypes(newThrower).get(0));
      assertEquals(NullPointerException.class,  
resolver.getExceptionTypes(throwS).get(0));
    }
@@ -142,7 +157,7 @@
    }

    public void testArrays() {
-    TypeResolver resolver = new TypeResolver(hasArrayOfShort);
+    TypeLiteral<?> resolver = TypeLiteral.get(hasArrayOfShort);
      assertEquals(arrayOf(Short.class), resolver.getReturnType(getArray));
      assertEquals(setOf(arrayOf(Short.class)),  
resolver.getReturnType(getSetOfArray));
    }
@@ -153,7 +168,7 @@
    }

    public void testRelatedTypeVariables() {
-    TypeResolver resolver = new TypeResolver(hasRelatedOfString);
+    TypeLiteral<?> resolver = TypeLiteral.get(hasRelatedOfString);
      assertEquals(String.class, resolver.getParameterTypes(echo).get(0));
      assertEquals(String.class, resolver.getReturnType(echo));
    }
@@ -164,7 +179,7 @@

    /** Ensure the cache doesn't cache too much */
    public void testCachingAndReindexing() throws NoSuchMethodException {
-    TypeResolver resolver = new TypeResolver(
+    TypeLiteral<?> resolver = TypeLiteral.get(
          newParameterizedTypeWithOwner(getClass(), HasLists.class,  
String.class, Short.class));
      assertEquals(listOf(String.class),
          resolver.getReturnType(HasLists.class.getMethod("listS")));
@@ -179,53 +194,114 @@
    }

    public void testUnsupportedQueries() throws NoSuchMethodException {
-    TypeResolver resolver = new TypeResolver(arrayListOfString);
+    TypeLiteral<?> resolver = TypeLiteral.get(arrayListOfString);

      try {
        resolver.getExceptionTypes(stringIndexOf);
+      fail();
      } catch (IllegalArgumentException e) {
        assertEquals("public int java.lang.String.indexOf(java.lang.String)  
is not defined by a "
            + "supertype of java.util.ArrayList<java.lang.String>",  
e.getMessage());
      }
      try {
        resolver.getParameterTypes(stringIndexOf);
+      fail();
      } catch (Exception e) {
        assertEquals("public int java.lang.String.indexOf(java.lang.String)  
is not defined by a "
            + "supertype of java.util.ArrayList<java.lang.String>",  
e.getMessage());
      }
      try {
        resolver.getReturnType(stringIndexOf);
+      fail();
      } catch (Exception e) {
        assertEquals("public int java.lang.String.indexOf(java.lang.String)  
is not defined by a "
            + "supertype of java.util.ArrayList<java.lang.String>",  
e.getMessage());
      }
      try {
        resolver.getSupertype(String.class);
+      fail();
      } catch (Exception e) {
        assertEquals("class java.lang.String is not a supertype of "
            + "java.util.ArrayList<java.lang.String>", e.getMessage());
      }
      try {
        resolver.getExceptionTypes(newString);
+      fail();
      } catch (Exception e) {
        assertEquals("public java.lang.String(java.lang.String) does not  
construct "
            + "a supertype of java.util.ArrayList<java.lang.String>",  
e.getMessage());
      }
      try {
        resolver.getParameterTypes(newString);
+      fail();
      } catch (Exception e) {
        assertEquals("public java.lang.String(java.lang.String) does not  
construct "
            + "a supertype of java.util.ArrayList<java.lang.String>",  
e.getMessage());
      }
    }

+  public void testResolve() {
+    TypeLiteral<?> typeResolver = TypeLiteral.get(StringIntegerMap.class);
+    assertEquals(String.class, typeResolver.resolve(mapK));
+
+    typeResolver = new TypeLiteral<Map<String, Integer>>() {};
+    assertEquals(String.class, typeResolver.resolve(mapK));
+    assertEquals(Types.mapOf(String.class, Integer.class),  
typeResolver.getSupertype(Map.class));
+
+    typeResolver = new TypeLiteral<BetterMap<String, Integer>>() {};
+    assertEquals(String.class, typeResolver.resolve(mapK));
+
+    typeResolver = new TypeLiteral<BestMap<String, Integer>>() {};
+    assertEquals(String.class, typeResolver.resolve(mapK));
+
+    typeResolver = TypeLiteral.get(StringIntegerHashMap.class);
+    assertEquals(String.class, typeResolver.resolve(mapK));
+    assertEquals(String.class, typeResolver.resolve(hashMapK));
+    assertEquals(entryStringInteger, typeResolver.resolve(setEntryKV));
+    assertEquals(Object.class, typeResolver.getSupertype(Object.class));
+  }
+
+  public void testOnObject() {
+    TypeLiteral<?> typeResolver = TypeLiteral.get(Object.class);
+    assertEquals(Object.class, typeResolver.getSupertype(Object.class));
+    assertEquals(Object.class, typeResolver.getRawType());
+
+    // interfaces also resolve Object
+    typeResolver = TypeLiteral.get(Types.setOf(Integer.class));
+    assertEquals(Object.class, typeResolver.getSupertype(Object.class));
+  }
+
+  interface StringIntegerMap extends Map<String, Integer> {}
+  interface BetterMap<K1, V1> extends Map<K1, V1> {}
+  interface BestMap<K2, V2> extends BetterMap<K2, V2> {}
+  static class StringIntegerHashMap extends HashMap<String, Integer> {}
+
+  public void testGetSupertype() {
+    TypeLiteral<AbstractList<String>> listOfString = new  
TypeLiteral<AbstractList<String>>() {};
+    assertEquals(Types.newParameterizedType(AbstractCollection.class,  
String.class),
+        listOfString.getSupertype(AbstractCollection.class));
+
+    TypeLiteral arrayListOfE = TypeLiteral.get(newParameterizedType(
+        ArrayList.class, ArrayList.class.getTypeParameters()));
+    assertEquals(newParameterizedType(AbstractCollection.class,
+        ArrayList.class.getTypeParameters()),  
arrayListOfE.getSupertype(AbstractCollection.class));
+  }
+
+  public void testGetSupertypeForArraysAsList() {
+    Class<? extends List> arraysAsListClass = Arrays.asList().getClass();
+    Type anotherE = arraysAsListClass.getTypeParameters()[0];
+    TypeLiteral type =  
TypeLiteral.get(newParameterizedType(AbstractList.class, anotherE));
+    assertEquals(newParameterizedType(AbstractCollection.class, anotherE),
+        type.getSupertype(AbstractCollection.class));
+  }
+
    // TODO(jessewilson): tests for tricky bounded types like <T extends  
Collection, Serializable>
    // TODO(jessewilson): tests for wildcard types

    public void testEqualsAndHashCode() throws IOException {
-    TypeResolver a1 = new TypeResolver(arrayListOfString);
-    TypeResolver a2 = new TypeResolver(arrayListOfString);
-    TypeResolver b = new TypeResolver(listOf(String.class));
+    TypeLiteral<?> a1 = TypeLiteral.get(arrayListOfString);
+    TypeLiteral<?> a2 = TypeLiteral.get(arrayListOfString);
+    TypeLiteral<?> b = TypeLiteral.get(listOf(String.class));
      assertEqualsBothWays(a1, a2);
      assertNotSerializable(a1);
      assertFalse(a1.equals(b));

Modified: trunk/test/com/google/inject/spi/InjectionPointTest.java
==============================================================================
--- trunk/test/com/google/inject/spi/InjectionPointTest.java    (original)
+++ trunk/test/com/google/inject/spi/InjectionPointTest.java    Fri Nov 14  
00:43:40 2008
@@ -25,7 +25,6 @@
  import com.google.inject.Key;
  import com.google.inject.TypeLiteral;
  import com.google.inject.internal.ErrorsException;
-import com.google.inject.internal.TypeResolver;
  import com.google.inject.name.Named;
  import static com.google.inject.name.Names.named;
  import java.io.IOException;
@@ -51,14 +50,14 @@
    }

    public void testFieldInjectionPoint() throws NoSuchFieldException,  
IOException, ErrorsException {
-    TypeResolver typeResolver = new TypeResolver(getClass());
+    TypeLiteral<?> typeLiteral = TypeLiteral.get(getClass());
      Field fooField = getClass().getField("foo");

-    InjectionPoint injectionPoint = new InjectionPoint(typeResolver,  
fooField);
+    InjectionPoint injectionPoint = new InjectionPoint(typeLiteral,  
fooField);
      assertSame(fooField, injectionPoint.getMember());
      assertFalse(injectionPoint.isOptional());
      assertEquals(getClass().getName() + ".foo", injectionPoint.toString());
-    assertEqualsBothWays(injectionPoint, new InjectionPoint(typeResolver,  
fooField));
+    assertEqualsBothWays(injectionPoint, new InjectionPoint(typeLiteral,  
fooField));
      assertSimilarWhenReserialized(injectionPoint);

      Dependency<?> dependency =  
getOnlyElement(injectionPoint.getDependencies());
@@ -70,18 +69,18 @@
      assertEquals(false, dependency.isNullable());
      assertSimilarWhenReserialized(dependency);
      assertEqualsBothWays(dependency,
-        getOnlyElement(new InjectionPoint(typeResolver,  
fooField).getDependencies()));
+        getOnlyElement(new InjectionPoint(typeLiteral,  
fooField).getDependencies()));
    }

    public void testMethodInjectionPoint() throws Exception {
-    TypeResolver typeResolver = new TypeResolver(getClass());
+    TypeLiteral<?> typeLiteral = TypeLiteral.get(getClass());

      Method barMethod = getClass().getMethod("bar", String.class);
-    InjectionPoint injectionPoint = new InjectionPoint(typeResolver,  
barMethod);
+    InjectionPoint injectionPoint = new InjectionPoint(typeLiteral,  
barMethod);
      assertSame(barMethod, injectionPoint.getMember());
      assertFalse(injectionPoint.isOptional());
      assertEquals(getClass().getName() + ".bar()",  
injectionPoint.toString());
-    assertEqualsBothWays(injectionPoint, new InjectionPoint(typeResolver,  
barMethod));
+    assertEqualsBothWays(injectionPoint, new InjectionPoint(typeLiteral,  
barMethod));
      assertSimilarWhenReserialized(injectionPoint);

      Dependency<?> dependency =  
getOnlyElement(injectionPoint.getDependencies());
@@ -93,19 +92,19 @@
      assertEquals(false, dependency.isNullable());
      assertSimilarWhenReserialized(dependency);
      assertEqualsBothWays(dependency,
-        getOnlyElement(new InjectionPoint(typeResolver,  
barMethod).getDependencies()));
+        getOnlyElement(new InjectionPoint(typeLiteral,  
barMethod).getDependencies()));
    }

    public void testConstructorInjectionPoint() throws  
NoSuchMethodException, IOException,
        ErrorsException {
-    TypeResolver typeResolver = new TypeResolver(Constructable.class);
+    TypeLiteral<?> typeLiteral = TypeLiteral.get(Constructable.class);

      Constructor<?> constructor =  
Constructable.class.getConstructor(String.class);
-    InjectionPoint injectionPoint = new InjectionPoint(typeResolver,  
constructor);
+    InjectionPoint injectionPoint = new InjectionPoint(typeLiteral,  
constructor);
      assertSame(constructor, injectionPoint.getMember());
      assertFalse(injectionPoint.isOptional());
      assertEquals(Constructable.class.getName() + ".<init>()",  
injectionPoint.toString());
-    assertEqualsBothWays(injectionPoint, new InjectionPoint(typeResolver,  
constructor));
+    assertEqualsBothWays(injectionPoint, new InjectionPoint(typeLiteral,  
constructor));
      assertSimilarWhenReserialized(injectionPoint);

      Dependency<?> dependency =  
getOnlyElement(injectionPoint.getDependencies());
@@ -117,7 +116,7 @@
      assertEquals(false, dependency.isNullable());
      assertSimilarWhenReserialized(dependency);
      assertEqualsBothWays(dependency,
-        getOnlyElement(new InjectionPoint(typeResolver,  
constructor).getDependencies()));
+        getOnlyElement(new InjectionPoint(typeLiteral,  
constructor).getDependencies()));
    }

    public void testUnattachedDependency() throws IOException {
@@ -144,8 +143,8 @@
      Set<InjectionPoint> sink = Sets.newHashSet();
      InjectionPoint.addForInstanceMethodsAndFields(HasInjections.class,  
sink);
      assertEquals(ImmutableSet.of(
-        new InjectionPoint(new TypeResolver(HasInjections.class),  
instanceMethod),
-        new InjectionPoint(new TypeResolver(HasInjections.class),  
instanceField)),
+        new InjectionPoint(TypeLiteral.get(HasInjections.class),  
instanceMethod),
+        new InjectionPoint(TypeLiteral.get(HasInjections.class),  
instanceField)),
          sink);
    }

@@ -156,8 +155,8 @@
      Set<InjectionPoint> sink = Sets.newHashSet();
      InjectionPoint.addForStaticMethodsAndFields(HasInjections.class, sink);
      assertEquals(ImmutableSet.of(
-        new InjectionPoint(new TypeResolver(HasInjections.class),  
staticMethod),
-        new InjectionPoint(new TypeResolver(HasInjections.class),  
staticField)),
+        new InjectionPoint(TypeLiteral.get(HasInjections.class),  
staticMethod),
+        new InjectionPoint(TypeLiteral.get(HasInjections.class),  
staticField)),
          sink);
    }


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"google-guice-dev" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/google-guice-dev?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to