Author: limpbizkit
Date: Mon Nov  3 18:52:54 2008
New Revision: 660

Modified:
    trunk/src/com/google/inject/BindingProcessor.java
    trunk/src/com/google/inject/ClassBindingImpl.java
    trunk/src/com/google/inject/ConstructorInjector.java
    trunk/src/com/google/inject/Initializer.java
    trunk/src/com/google/inject/InjectorImpl.java
    trunk/src/com/google/inject/internal/TypeResolver.java
    trunk/src/com/google/inject/spi/InjectionPoint.java
    trunk/test/com/google/inject/GenericInjectionTest.java
    trunk/test/com/google/inject/ScopesTest.java
    trunk/test/com/google/inject/TypeLiteralTest.java
    trunk/test/com/google/inject/spi/InjectionPointTest.java

Log:
This change is big, and it makes Guice slower. I'll need to follow-up with  
some optimizations that make TypeResolver quicker.

Suppose you have a parameterized class:

class Foo<T> {
   @Inject Set<T> tees;
}

This change makes it so that as long as you have the required dependencies,  
parameterized injection points will be resolved. For example:
   Injector injector = Guice.createInjector(new AbstractModule() {
     protected void configure() {
       bind(new TypeLiteral<Set<String>>() {})
           .toInstance(ImmutableSet.of("A", "B", "C"));
       }
   });
   Foo<String> foo = injector.getInstance(new TypeLiteral<Foo<String>>() {});
   assertEquals(ImmutableSet.of("A", "B", "C"), foo.tees);

This builds on my earlier work for TypeResolver. That class is currently  
pretty slow (it builds a ton of HashMaps eagerly), but it shouldn't be too  
hard to make it lazy - that way everything will work nice and fast if  
you're not leveraging this feature.

Modified: trunk/src/com/google/inject/BindingProcessor.java
==============================================================================
--- trunk/src/com/google/inject/BindingProcessor.java   (original)
+++ trunk/src/com/google/inject/BindingProcessor.java   Mon Nov  3 18:52:54  
2008
@@ -175,19 +175,16 @@
          // Example: bind(Date.class).annotatedWith(Red.class);
          // We can't assume abstract types aren't injectable. They may have  
an
          // @ImplementedBy annotation or something.
-        if (key.hasAnnotationType() || !(type instanceof Class<?>)) {
+        if (key.hasAnnotationType()) {
            errors.missingImplementation(key);
            putBinding(invalidBinding(injector, key, source));
            return null;
          }

          // This cast is safe after the preceeding check.
-        @SuppressWarnings("unchecked")
-        Class<T> clazz = (Class<T>) type;
          final BindingImpl<T> binding;
          try {
-          binding = injector.createUnitializedBinding(
-              key, clazz, scope, source, loadStrategy, errors);
+          binding = injector.createUnitializedBinding(key, scope, source,  
loadStrategy, errors);
            putBinding(binding);
          } catch (ErrorsException e) {
            errors.merge(e.getErrors());

Modified: trunk/src/com/google/inject/ClassBindingImpl.java
==============================================================================
--- trunk/src/com/google/inject/ClassBindingImpl.java   (original)
+++ trunk/src/com/google/inject/ClassBindingImpl.java   Mon Nov  3 18:52:54  
2008
@@ -43,7 +43,7 @@
    }

    @Override void initialize(InjectorImpl injector, Errors errors) throws  
ErrorsException {
-    lateBoundConstructor.bind(injector, getBoundClass(), errors);
+    lateBoundConstructor.bind(injector, getKey().getTypeLiteral(), errors);
      injectionPoints =  
lateBoundConstructor.constructorInjector.getInjectionPoints();
    }

@@ -52,15 +52,9 @@
      return visitor.visitConstructor(lateBoundConstructor.getConstructor(),  
injectionPoints);
    }

-  @SuppressWarnings("unchecked")
-  public Class<T> getBoundClass() {
-    // T should always be the class itself.
-    return (Class<T>) key.getRawType();
-  }
-
    @Override public String toString() {
      return new ToStringBuilder(Binding.class)
-        .add("class", getBoundClass())
+        .add("type", getKey().getTypeLiteral())
          .add("scope", scope)
          .add("source", source)
          .toString();

Modified: trunk/src/com/google/inject/ConstructorInjector.java
==============================================================================
--- trunk/src/com/google/inject/ConstructorInjector.java        (original)
+++ trunk/src/com/google/inject/ConstructorInjector.java        Mon Nov  3  
18:52:54 2008
@@ -31,18 +31,18 @@
   */
  class ConstructorInjector<T> {

-  final Class<T> implementation;
+  final TypeLiteral<T> implementation;
    final InjectionPoint injectionPoint;
    final ImmutableList<SingleMemberInjector> memberInjectors;
    final ImmutableList<SingleParameterInjector<?>> parameterInjectors;
    final ConstructionProxy<T> constructionProxy;

-  ConstructorInjector(Errors errors, InjectorImpl injector, Class<T>  
implementation)
+  ConstructorInjector(Errors errors, InjectorImpl injector, TypeLiteral<T>  
implementation)
        throws ErrorsException {
      this.implementation = implementation;

      try {
-      this.injectionPoint =  
InjectionPoint.forConstructorOf(implementation);
+      this.injectionPoint =  
InjectionPoint.forConstructorOf(implementation.getType());
      } catch (ConfigurationException e) {
        throw errors.merge(e.getErrorMessages()).toException();
      }

Modified: trunk/src/com/google/inject/Initializer.java
==============================================================================
--- trunk/src/com/google/inject/Initializer.java        (original)
+++ trunk/src/com/google/inject/Initializer.java        Mon Nov  3 18:52:54 2008
@@ -22,10 +22,9 @@
  import com.google.inject.internal.Errors;
  import com.google.inject.internal.ErrorsException;
  import com.google.inject.spi.InjectionPoint;
-import com.google.inject.SingleMemberInjector;
+import java.util.List;
  import java.util.Map;
  import java.util.Set;
-import java.util.List;
  import java.util.concurrent.CountDownLatch;

  /**
@@ -119,7 +118,8 @@
      }

      public void validate(Errors errors) throws ErrorsException {
-      injectors = injector.injectors.get(instance.getClass(),  
errors.withSource(source));
+      injectors = injector.injectors.get(
+          TypeLiteral.get(instance.getClass()), errors.withSource(source));
      }

      /**

Modified: trunk/src/com/google/inject/InjectorImpl.java
==============================================================================
--- trunk/src/com/google/inject/InjectorImpl.java       (original)
+++ trunk/src/com/google/inject/InjectorImpl.java       Mon Nov  3 18:52:54 2008
@@ -29,6 +29,7 @@
  import com.google.inject.internal.ErrorsException;
  import com.google.inject.internal.FailableCache;
  import com.google.inject.internal.MatcherAndConverter;
+import com.google.inject.internal.MoreTypes;
  import com.google.inject.internal.ToStringBuilder;
  import com.google.inject.spi.BindingTargetVisitor;
  import com.google.inject.spi.Dependency;
@@ -340,72 +341,68 @@
    /**
     * Creates a binding for an injectable type with the given scope. Looks  
for a scope on the type if
     * none is specified.
-   *
-   * TODO(jessewilson): Fix raw types! this method makes a binding for  
[EMAIL PROTECTED] Foo} from a request
-   *     for [EMAIL PROTECTED] Foo<String>}
-   *
-   * @param type the raw type for [EMAIL PROTECTED] key}
     */
-  <T> BindingImpl<T> createUnitializedBinding(Key<T> key, Class<T> type,  
Scope scope, Object source,
+  <T> BindingImpl<T> createUnitializedBinding(Key<T> key, Scope scope,  
Object source,
        LoadStrategy loadStrategy, Errors errors) throws ErrorsException {
+    Class<?> rawType =  
MoreTypes.getRawType(key.getTypeLiteral().getType());
+
      // Don't try to inject arrays, or enums.
-    if (type.isArray() || type.isEnum()) {
+    if (rawType.isArray() || rawType.isEnum()) {
        throw errors.missingImplementation(key).toException();
      }

      // Handle @ImplementedBy
-    ImplementedBy implementedBy = type.getAnnotation(ImplementedBy.class);
+    ImplementedBy implementedBy =  
rawType.getAnnotation(ImplementedBy.class);
      if (implementedBy != null) {
-      Annotations.checkForMisplacedScopeAnnotations(type, source, errors);
-      return createImplementedByBinding(type, scope, implementedBy,  
loadStrategy, errors);
+      Annotations.checkForMisplacedScopeAnnotations(rawType, source,  
errors);
+      return createImplementedByBinding(key, scope, implementedBy,  
loadStrategy, errors);
      }

      // Handle @ProvidedBy.
-    ProvidedBy providedBy = type.getAnnotation(ProvidedBy.class);
+    ProvidedBy providedBy = rawType.getAnnotation(ProvidedBy.class);
      if (providedBy != null) {
-      Annotations.checkForMisplacedScopeAnnotations(type, source, errors);
-      return createProvidedByBinding(type, scope, providedBy,  
loadStrategy, errors);
+      Annotations.checkForMisplacedScopeAnnotations(rawType, source,  
errors);
+      return createProvidedByBinding(key, scope, providedBy, loadStrategy,  
errors);
      }

      // We can't inject abstract classes.
      // TODO: Method interceptors could actually enable us to implement
      // abstract types. Should we remove this restriction?
-    if (Modifier.isAbstract(type.getModifiers())) {
+    if (Modifier.isAbstract(rawType.getModifiers())) {
        throw errors.missingImplementation(key).toException();
      }

      // Error: Inner class.
-    if (Classes.isInnerClass(type)) {
-      throw errors.cannotInjectInnerClass(type).toException();
+    if (Classes.isInnerClass(rawType)) {
+      throw errors.cannotInjectInnerClass(rawType).toException();
      }

      if (scope == null) {
-      Class<? extends Annotation> scopeAnnotation =  
Annotations.findScopeAnnotation(errors, type);
+      Class<? extends Annotation> scopeAnnotation
+          = Annotations.findScopeAnnotation(errors, rawType);
        if (scopeAnnotation != null) {
          scope = state.getScope(scopeAnnotation);
          if (scope == null) {
-          errors.withSource(type).scopeNotFound(scopeAnnotation);
+          errors.withSource(rawType).scopeNotFound(scopeAnnotation);
          }
        }
      }

-    Key<T> keyForRawType = Key.get(type);
-
      LateBoundConstructor<T> lateBoundConstructor = new  
LateBoundConstructor<T>();
      InternalFactory<? extends T> scopedFactory
-        = Scopes.scope(keyForRawType, this, lateBoundConstructor, scope);
+        = Scopes.scope(key, this, lateBoundConstructor, scope);
      return new ClassBindingImpl<T>(
-        this, keyForRawType, source, scopedFactory, scope,  
lateBoundConstructor, loadStrategy);
+        this, key, source, scopedFactory, scope, lateBoundConstructor,  
loadStrategy);
    }

    static class LateBoundConstructor<T> implements InternalFactory<T> {
      ConstructorInjector<T> constructorInjector;

      @SuppressWarnings("unchecked") // the constructor T is the same as the  
implementation T
-    void bind(InjectorImpl injector, Class<T> implementation, Errors  
errors)
+    void bind(InjectorImpl injector, TypeLiteral<T> implementation, Errors  
errors)
          throws ErrorsException {
-      constructorInjector = (ConstructorInjector<T>)  
injector.constructors.get(
-          implementation, errors);
+      constructorInjector
+          = (ConstructorInjector<T>)  
injector.constructors.get(implementation, errors);
      }

      public Constructor<T> getConstructor() {
@@ -426,12 +423,13 @@
    }

    /** Creates a binding for a type annotated with @ProvidedBy. */
-  <T> BindingImpl<T> createProvidedByBinding(final Class<T> type, Scope  
scope,
+  <T> BindingImpl<T> createProvidedByBinding(Key<T> key, Scope scope,
        ProvidedBy providedBy, LoadStrategy loadStrategy, Errors errors)  
throws ErrorsException {
+    final Class<?> rawType =  
MoreTypes.getRawType(key.getTypeLiteral().getType());
      final Class<? extends Provider<?>> providerType = providedBy.value();

      // Make sure it's not the same type. TODO: Can we check for deeper  
loops?
-    if (providerType == type) {
+    if (providerType == rawType) {
        throw errors.recursiveProviderType().toException();
      }

@@ -449,8 +447,8 @@
          Provider<?> provider = providerBinding.internalFactory.get(errors,  
context, dependency);
          try {
            Object o = provider.get();
-          if (o != null && !type.isInstance(o)) {
-            throw errors.subtypeNotProvided(providerType,  
type).toException();
+          if (o != null && !rawType.isInstance(o)) {
+            throw errors.subtypeNotProvided(providerType,  
rawType).toException();
            }
            @SuppressWarnings("unchecked") // protected by isInstance()  
check above
            T t = (T) o;
@@ -461,11 +459,10 @@
        }
      };

-    Key<T> key = Key.get(type);
      return new LinkedProviderBindingImpl<T>(
          this,
          key,
-        type,
+        rawType /* source */,
          Scopes.<T>scope(key, this, internalFactory, scope),
          scope,
          providerKey,
@@ -473,19 +470,20 @@
    }

    /** Creates a binding for a type annotated with @ImplementedBy. */
-  <T> BindingImpl<T> createImplementedByBinding(Class<T> type, Scope scope,
+  <T> BindingImpl<T> createImplementedByBinding(Key<T> key, Scope scope,
        ImplementedBy implementedBy, LoadStrategy loadStrategy, Errors  
errors)
        throws ErrorsException {
+    Class<?> rawType =  
MoreTypes.getRawType(key.getTypeLiteral().getType());
      Class<?> implementationType = implementedBy.value();

      // Make sure it's not the same type. TODO: Can we check for deeper  
cycles?
-    if (implementationType == type) {
+    if (implementationType == rawType) {
        throw errors.recursiveImplementationType().toException();
      }

      // Make sure implementationType extends type.
-    if (!type.isAssignableFrom(implementationType)) {
-      throw errors.notASubtype(implementationType, type).toException();
+    if (!rawType.isAssignableFrom(implementationType)) {
+      throw errors.notASubtype(implementationType, rawType).toException();
      }

      @SuppressWarnings("unchecked") // After the preceding check, this cast  
is safe.
@@ -502,13 +500,13 @@
        }
      };

-    Key<T> key = Key.get(type);
      return new LinkedBindingImpl<T>(
          this,
          key,
-        type,
+        rawType /* source */,
          Scopes.<T>scope(key, this, internalFactory, scope),
-        scope, targetKey,
+        scope,
+        targetKey,
          loadStrategy);
    }

@@ -560,10 +558,8 @@
        throw errors.missingImplementation(key).toException();
      }

-    // Create a binding based on the raw type.
-    @SuppressWarnings("unchecked")
-    Class<T> rawType = (Class<T>) key.getRawType();
-    BindingImpl<T> binding = createUnitializedBinding(key, rawType, null  
/* scope */, rawType,
+    Object source = MoreTypes.getRawType(key.getTypeLiteral().getType());
+    BindingImpl<T> binding = createUnitializedBinding(key, null /* scope  
*/, source,
          LoadStrategy.LAZY, errors);
      initializeBinding(binding, errors);
      return binding;
@@ -575,14 +571,14 @@
    }

    /** Cached field and method injectors for a type. */
-  final FailableCache<Class<?>, ImmutableList<SingleMemberInjector>>  
injectors
-      = new FailableCache<Class<?>, ImmutableList<SingleMemberInjector>>()  
{
-    protected ImmutableList<SingleMemberInjector> create(Class<?> type,  
Errors errors)
+  final FailableCache<TypeLiteral<?>, ImmutableList<SingleMemberInjector>>  
injectors
+      = new FailableCache<TypeLiteral<?>,  
ImmutableList<SingleMemberInjector>>() {
+    protected ImmutableList<SingleMemberInjector> create(TypeLiteral<?>  
type, Errors errors)
          throws ErrorsException {
        int numErrorsBefore = errors.size();
        List<InjectionPoint> injectionPoints = Lists.newArrayList();
        try {
-        InjectionPoint.addForInstanceMethodsAndFields(type,  
injectionPoints);
+        InjectionPoint.addForInstanceMethodsAndFields(type.getType(),  
injectionPoints);
        } catch (ConfigurationException e) {
          errors.merge(e.getErrorMessages());
        }
@@ -672,10 +668,11 @@
    }

    /** Cached constructor injectors for each type */
-  final FailableCache<Class<?>, ConstructorInjector<?>> constructors
-      = new FailableCache<Class<?>, ConstructorInjector<?>>() {
+  final FailableCache<TypeLiteral<?>, ConstructorInjector<?>> constructors
+      = new FailableCache<TypeLiteral<?>, ConstructorInjector<?>>() {
      @SuppressWarnings("unchecked")
-    protected ConstructorInjector<?> create(Class<?> type, Errors errors)  
throws ErrorsException {
+    protected ConstructorInjector<?> create(TypeLiteral<?> type, Errors  
errors)
+        throws ErrorsException {
        return new ConstructorInjector(errors, InjectorImpl.this, type);
      }
    };
@@ -695,7 +692,7 @@
      // configuration/validation stuff throws ConfigurationException
      List<SingleMemberInjector> injectors;
      try {
-      injectors = this.injectors.get(o.getClass(), errors);
+      injectors = this.injectors.get(TypeLiteral.get(o.getClass()),  
errors);
      } catch (ErrorsException e) {
        throw new  
ConfigurationException(errors.merge(e.getErrors()).getMessages());
      }

Modified: trunk/src/com/google/inject/internal/TypeResolver.java
==============================================================================
--- trunk/src/com/google/inject/internal/TypeResolver.java      (original)
+++ trunk/src/com/google/inject/internal/TypeResolver.java      Mon Nov  3  
18:52:54 2008
@@ -25,6 +25,7 @@
  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;
@@ -51,7 +52,7 @@
    public final Type type;

    /** maps from type variables to the types they resolve to */
-  private final Map<FqTypeVar, Type> index = Maps.newHashMap();
+  private final Map<TypeVariable, Type> index = Maps.newHashMap();

    /** types to resolved types */
    private final Map<Type, Type> cache = Maps.newHashMap();
@@ -102,9 +103,8 @@
        Type[] arguments = parameterizedType.getActualTypeArguments();
        Type[] resolvedArguments = new Type[typeVariables.length];
        for (int v = 0; v < typeVariables.length; v++) {
-        FqTypeVar typeVar = new FqTypeVar(rawType,  
typeVariables[v].getName());
          resolvedArguments[v] = resolve(arguments[v]);
-        index.put(typeVar, resolvedArguments[v]);
+        index.put(typeVariables[v], resolvedArguments[v]);
        }

        Type resolvedRawType = resolve(rawType);
@@ -120,8 +120,7 @@
        GenericDeclaration genericDeclaration =  
typeVariable.getGenericDeclaration();
        Type result = typeVariable;
        if (genericDeclaration instanceof Class) {
-        FqTypeVar fqTypeVar = new FqTypeVar((Class<?>) genericDeclaration,  
typeVariable.getName());
-        Type resolved = index.get(fqTypeVar);
+        Type resolved = index.get(typeVariable);
          result = resolved != null ? resolved : result;
        }
        cache.put(type, result);
@@ -163,6 +162,13 @@
    }

    /**
+   * Returns the raw form of the type being resolved, such as [EMAIL 
PROTECTED] List}.
+   */
+  public Class<?> getRawType() {
+    return MoreTypes.getRawType(type);
+  }
+
+  /**
     * Returns the generic equivalent of [EMAIL PROTECTED] supertype}. For 
example, if  
this
     * is a resolver of [EMAIL PROTECTED] ArrayList<String>}, this method 
returns [EMAIL PROTECTED]
     * Iterable<String>} given the input [EMAIL PROTECTED] Iterable.class}.
@@ -190,19 +196,6 @@
    }

    /**
-   * Returns a list of the resolved generic parameter types of [EMAIL 
PROTECTED]
-   * constructor}.
-   *
-   * @param constructor a constructor defined by this resolver's type or  
any of
-   *      its superclasses.
-   */
-  public List<Type> getParameterTypes(Constructor constructor) {
-     
checkArgument(implementedTypes.containsKey(constructor.getDeclaringClass()),
-        "%s does not construct a supertype of %s", constructor, type);
-    return resolveAll(constructor.getGenericParameterTypes());
-  }
-
-  /**
     * Returns a list of the resolved generic exception types of [EMAIL 
PROTECTED]
     * constructor}.
     *
@@ -216,15 +209,31 @@
    }

    /**
-   * Returns a list of the resolved generic parameter types of [EMAIL 
PROTECTED]  
method}.
+   * Returns a list of the resolved generic parameter types of [EMAIL 
PROTECTED]  
methodOrConstructor}.
     *
-   * @param method a method defined by this resolver's type, its  
superclasses
-   *      or implemented interfaces.
+   * @param methodOrConstructor a method or constructor defined by this  
resolver's type, its
+   *      superclasses or implemented interfaces.
     */
-  public List<Type> getParameterTypes(Method method) {
-    checkArgument(implementedTypes.containsKey(method.getDeclaringClass()),
-        "%s is not defined by a supertype of %s", method, type);
-    return resolveAll(method.getGenericParameterTypes());
+  public List<Type> getParameterTypes(Member methodOrConstructor) {
+    Type[] genericParameterTypes;
+
+    if (methodOrConstructor instanceof Method) {
+      Method method = (Method) methodOrConstructor;
+       
checkArgument(implementedTypes.containsKey(method.getDeclaringClass()),
+          "%s is not defined by a supertype of %s", method, type);
+      genericParameterTypes = method.getGenericParameterTypes();
+
+    } else if (methodOrConstructor instanceof Constructor) {
+      Constructor constructor = (Constructor) methodOrConstructor;
+       
checkArgument(implementedTypes.containsKey(constructor.getDeclaringClass()),
+          "%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);
    }

    /**
@@ -262,32 +271,5 @@

    @Override public String toString() {
      return "Resolver:" + type;
-  }
-
-  /**
-   * A fully-qualified type variable, such as the "E" in java.util.List.
-   */
-  private static class FqTypeVar {
-    private final Class<?> rawType;
-    private final String name;
-
-    private FqTypeVar(Class<?> rawType, String name) {
-      this.rawType = rawType;
-      this.name = name;
-    }
-
-    @Override public boolean equals(Object o) {
-      return o instanceof FqTypeVar
-          && ((FqTypeVar) o).rawType == rawType
-          && ((FqTypeVar) o).name.equals(name);
-    }
-
-    @Override public int hashCode() {
-      return rawType.hashCode() ^ name.hashCode();
-    }
-
-    @Override public String toString() {
-      return rawType + ":" + name;
-    }
    }
  }

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 Mon Nov  3 18:52:54  
2008
@@ -26,6 +26,7 @@
  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;
@@ -61,25 +62,22 @@
      this.optional = optional;
    }

-  InjectionPoint(Method method) {
+  InjectionPoint(TypeResolver typeResolver, Method method) {
      this.member = method;

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

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

-  InjectionPoint(Constructor<?> constructor) {
+  InjectionPoint(TypeResolver typeResolver, Constructor<?> constructor) {
      this.member = constructor;
      this.optional = false;
-    // TODO(jessewilson): make sure that if @Inject it exists, its not  
optional
-    this.dependencies = forMember(constructor,  
constructor.getGenericParameterTypes(),
-        constructor.getParameterAnnotations());
+    this.dependencies = forMember(constructor, typeResolver,  
constructor.getParameterAnnotations());
    }

-  InjectionPoint(Field field) {
+  InjectionPoint(TypeResolver typeResolver, Field field) {
      this.member = field;

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

-  private ImmutableList<Dependency<?>> forMember(Member member, Type[]  
genericParameterTypes,
-      Annotation[][] annotations) {
+  private ImmutableList<Dependency<?>> forMember(Member member,  
TypeResolver typeResolver,
+      Annotation[][] paramterAnnotations) {
      Errors errors = new Errors(member);
-    Iterator<Annotation[]> annotationsIterator =  
Arrays.asList(annotations).iterator();
+    Iterator<Annotation[]> annotationsIterator =  
Arrays.asList(paramterAnnotations).iterator();

      List<Dependency<?>> dependencies = Lists.newArrayList();
      int index = 0;
-    for (Type parameterType : genericParameterTypes) {
+
+    for (Type parameterType : typeResolver.getParameterTypes(member)) {
        try {
          Annotation[] parameterAnnotations = annotationsIterator.next();
          Key<?> key = Annotations.getKey(parameterType, member,  
parameterAnnotations, errors);
@@ -157,7 +156,7 @@

    @Override public boolean equals(Object o) {
      return o instanceof InjectionPoint
-        && member == ((InjectionPoint) o).member;
+        && member.equals(((InjectionPoint) o).member);
    }

    @Override public int hashCode() {
@@ -178,15 +177,17 @@
     *
     * @param type a concrete type with exactly one constructor annotated  
[EMAIL PROTECTED] @[EMAIL PROTECTED] Inject},
     *     or a no-arguments constructor that is not private.
-   * @throws RuntimeException if there is no injectable constructor, more  
than one injectable
+   * @throws ConfigurationException if there is no injectable constructor,  
more than one injectable
     *     constructor, or if parameters of the injectable constructor are  
malformed, such as a
     *     parameter with multiple binding annotations.
     */
-  public static InjectionPoint forConstructorOf(Class<?> type) {
+  public static InjectionPoint forConstructorOf(Type type) {
      Errors errors = new Errors(type);
+    TypeResolver typeResolver = new TypeResolver(type);
+    Class<?> rawType = typeResolver.getRawType();

      Constructor<?> injectableConstructor = null;
-    for (Constructor<?> constructor : type.getDeclaredConstructors()) {
+    for (Constructor<?> constructor : rawType.getDeclaredConstructors()) {
        Inject inject = constructor.getAnnotation(Inject.class);
        if (inject != null) {
          if (inject.optional()) {
@@ -194,7 +195,7 @@
          }

          if (injectableConstructor != null) {
-          errors.tooManyConstructors(type);
+          errors.tooManyConstructors(rawType);
          }

          injectableConstructor = constructor;
@@ -205,24 +206,24 @@
      errors.throwConfigurationExceptionIfErrorsExist();

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

      // If no annotated constructor is found, look for a no-arg constructor  
instead.
      try {
-      Constructor<?> noArgConstructor = type.getDeclaredConstructor();
+      Constructor<?> noArgConstructor = rawType.getDeclaredConstructor();

        // Disallow private constructors on non-private classes (unless they  
have @Inject)
        if (Modifier.isPrivate(noArgConstructor.getModifiers())
-          && !Modifier.isPrivate(type.getModifiers())) {
-        errors.missingConstructor(type);
+          && !Modifier.isPrivate(rawType.getModifiers())) {
+        errors.missingConstructor(rawType);
          throw new ConfigurationException(errors.getMessages());
        }

        checkForMisplacedBindingAnnotations(noArgConstructor, errors);
-      return new InjectionPoint(noArgConstructor);
+      return new InjectionPoint(typeResolver, noArgConstructor);
      } catch (NoSuchMethodException e) {
-      errors.missingConstructor(type);
+      errors.missingConstructor(rawType);
        throw new ConfigurationException(errors.getMessages());
      }
    }
@@ -232,11 +233,11 @@
     * All fields are added first, and then all methods. Within the fields,  
supertype fields are added
     * before subtype fields. Similarly, supertype methods are added before  
subtype methods.
     *
-   * @throws RuntimeException if there is a malformed injection point on  
[EMAIL PROTECTED] type}, such as a
-   *      field with multiple binding annotations. When such an exception  
is thrown, the valid
+   * @throws ConfigurationException if there is a malformed injection  
point on [EMAIL PROTECTED] type}, such as
+   *      a field with multiple binding annotations. When such an  
exception is thrown, the valid
     *      injection points are still added to the collection.
     */
-  public static void addForStaticMethodsAndFields(Class<?> type,  
Collection<InjectionPoint> sink) {
+  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);
@@ -248,12 +249,11 @@
     * All fields are added first, and then all methods. Within the fields,  
supertype fields are added
     * before subtype fields. Similarly, supertype methods are added before  
subtype methods.
     *
-   * @throws RuntimeException if there is a malformed injection point on  
[EMAIL PROTECTED] type}, such as a
-   *      field with multiple binding annotations. When such an exception  
is thrown, the valid
+   * @throws ConfigurationException if there is a malformed injection  
point on [EMAIL PROTECTED] type}, such as
+   *      a field with multiple binding annotations. When such an  
exception is thrown, the valid
     *      injection points are still added to the collection.
     */
-  public static void addForInstanceMethodsAndFields(Class<?> type,
-      Collection<InjectionPoint> sink) {
+  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);
@@ -269,24 +269,27 @@
      }
    }

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

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

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

-  private static <M extends Member & AnnotatedElement> void  
addInjectorsForMembers(Class<?> type,
-      Factory<M> factory, boolean statics, Collection<InjectionPoint>  
injectionPoints,
-      Errors errors) {
-    for (M member : factory.getMembers(type)) {
+  private static <M extends Member & AnnotatedElement> void  
addInjectorsForMembers(
+      TypeResolver typeResolver, Factory<M> factory, boolean statics,
+      Collection<InjectionPoint> injectionPoints, Errors errors) {
+    for (M member : factory.getMembers(typeResolver.getRawType())) {
        if (isStatic(member) != statics) {
          continue;
        }
@@ -297,7 +300,7 @@
        }

        try {
-        injectionPoints.add(factory.create(member, errors));
+        injectionPoints.add(factory.create(typeResolver, member, errors));
        } catch (ConfigurationException ignorable) {
          if (!inject.optional()) {
            errors.merge(ignorable.getErrorMessages());
@@ -315,8 +318,8 @@
        public Field[] getMembers(Class<?> type) {
          return type.getDeclaredFields();
        }
-      public InjectionPoint create(Field member, Errors errors) {
-        return new InjectionPoint(member);
+      public InjectionPoint create(TypeResolver typeResolver, Field  
member, Errors errors) {
+        return new InjectionPoint(typeResolver, member);
        }
      };

@@ -324,14 +327,14 @@
        public Method[] getMembers(Class<?> type) {
          return type.getDeclaredMethods();
        }
-      public InjectionPoint create(Method member, Errors errors) {
+      public InjectionPoint create(TypeResolver typeResolver, Method  
member, Errors errors) {
          checkForMisplacedBindingAnnotations(member, errors);
-        return new InjectionPoint(member);
+        return new InjectionPoint(typeResolver, member);
        }
      };

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

    private static final long serialVersionUID = 0;

Modified: trunk/test/com/google/inject/GenericInjectionTest.java
==============================================================================
--- trunk/test/com/google/inject/GenericInjectionTest.java      (original)
+++ trunk/test/com/google/inject/GenericInjectionTest.java      Mon Nov  3  
18:52:54 2008
@@ -16,8 +16,14 @@

  package com.google.inject;

+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.inject.util.Modules;
  import java.util.Arrays;
+import java.util.Collection;
  import java.util.List;
+import java.util.Map;
+import java.util.Set;
  import junit.framework.TestCase;

  /**
@@ -69,5 +75,97 @@
    static class Parameterized<T> {
      @Inject
      Parameterized() { }
+  }
+
+  public void testInjectingParameterizedDependenciesForImplicitBinding() {
+    assertParameterizedDepsInjected(new Key<ParameterizedDeps<String,  
Integer>>() {},
+        Modules.EMPTY_MODULE);
+  }
+
+  public void testInjectingParameterizedDependenciesForBindingTarget() {
+    final TypeLiteral<ParameterizedDeps<String, Integer>> type
+        = new TypeLiteral<ParameterizedDeps<String, Integer>>() {};
+
+    assertParameterizedDepsInjected(Key.get(Object.class), new  
AbstractModule() {
+      protected void configure() {
+        bind(Object.class).to(type);
+      }
+    });
+  }
+
+  public void testInjectingParameterizedDependenciesForBindingSource() {
+    final TypeLiteral<ParameterizedDeps<String, Integer>> type
+        = new TypeLiteral<ParameterizedDeps<String, Integer>>() {};
+
+    assertParameterizedDepsInjected(Key.get(type), new AbstractModule() {
+      protected void configure() {
+        bind(type);
+      }
+    });
+  }
+
+  public void testBindingToSubtype() {
+    final TypeLiteral<ParameterizedDeps<String, Integer>> type
+        = new TypeLiteral<ParameterizedDeps<String, Integer>>() {};
+
+    assertParameterizedDepsInjected(Key.get(type), new AbstractModule() {
+      protected void configure() {
+        bind(type).to(new TypeLiteral<SubParameterizedDeps<String, Long,  
Integer>>() {});
+      }
+    });
+  }
+
+  public void testBindingSubtype() {
+    final TypeLiteral<SubParameterizedDeps<String, Long, Integer>> type
+        = new TypeLiteral<SubParameterizedDeps<String, Long, Integer>>()  
{};
+
+    assertParameterizedDepsInjected(Key.get(type), new AbstractModule() {
+      protected void configure() {
+        bind(type);
+      }
+    });
+  }
+
+  @SuppressWarnings("unchecked")
+  public void assertParameterizedDepsInjected(Key<?> key, Module  
bindingModule) {
+    Module bindDataModule = new AbstractModule() {
+      protected void configure() {}
+      @Provides Map<String, Integer> provideMap() {
+        return ImmutableMap.of("one", 1, "two", 2);
+      }
+      @Provides Set<String> provideSet(Map<String, Integer> map) {
+        return map.keySet();
+      }
+      @Provides Collection<Integer> provideCollection(Map<String, Integer>  
map) {
+        return map.values();
+      }
+    };
+
+    Injector injector = Guice.createInjector(bindDataModule,  
bindingModule);
+    ParameterizedDeps<String, Integer> parameterizedDeps
+        = (ParameterizedDeps<String, Integer>) injector.getInstance(key);
+    assertEquals(ImmutableMap.of("one", 1, "two", 2),  
parameterizedDeps.map);
+    assertEquals(ImmutableSet.of("one", "two"), parameterizedDeps.keys);
+    assertEquals(ImmutableSet.of(1, 2),  
ImmutableSet.copyOf(parameterizedDeps.values));
+  }
+
+  static class SubParameterizedDeps<A, B, C> extends ParameterizedDeps<A,  
C> {
+    @Inject SubParameterizedDeps(Set<A> keys) {
+      super(keys);
+    }
+  }
+
+  static class ParameterizedDeps<K, V> {
+    @Inject private Map<K, V> map;
+    private Set<K> keys;
+    private Collection<V> values;
+
+    @Inject ParameterizedDeps(Set<K> keys) {
+      this.keys = keys;
+    }
+
+    @Inject void method(Collection<V> values) {
+      this.values = values;
+    }
    }
  }

Modified: trunk/test/com/google/inject/ScopesTest.java
==============================================================================
--- trunk/test/com/google/inject/ScopesTest.java        (original)
+++ trunk/test/com/google/inject/ScopesTest.java        Mon Nov  3 18:52:54 2008
@@ -306,7 +306,7 @@
      } catch (ConfigurationException expected) {
        assertContains(expected.getMessage(),
            "1) More than one scope annotation was found: ",
-          "while locating binding for " +  
SingletonAndCustomScoped.class.getName());
+          "while locating " + SingletonAndCustomScoped.class.getName());
      }
    }


Modified: trunk/test/com/google/inject/TypeLiteralTest.java
==============================================================================
--- trunk/test/com/google/inject/TypeLiteralTest.java   (original)
+++ trunk/test/com/google/inject/TypeLiteralTest.java   Mon Nov  3 18:52:54  
2008
@@ -87,6 +87,12 @@
      assertEquals(arrayAsClass, arrayAsType);
    }

+  public void testEqualityOfMultidimensionalGenericArrayAndClassArray() {
+    TypeLiteral<String[][][]> arrayAsClass =  
TypeLiteral.get(String[][][].class);
+    TypeLiteral<String[][][]> arrayAsType = new  
TypeLiteral<String[][][]>() {};
+    assertEquals(arrayAsClass, arrayAsType);
+  }
+
    public void testTypeLiteralsMustHaveRawTypes() {
      try {
        TypeLiteral.get(Types.subtypeOf(Runnable.class));

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    Mon Nov  3  
18:52:54 2008
@@ -16,18 +16,25 @@

  package com.google.inject.spi;

+import com.google.common.collect.ImmutableSet;
  import static com.google.common.collect.Iterables.getOnlyElement;
+import com.google.common.collect.Sets;
  import static com.google.inject.Asserts.assertEqualsBothWays;
  import static com.google.inject.Asserts.assertSimilarWhenReserialized;
  import com.google.inject.Inject;
  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 com.google.inject.name.Names;
+import static com.google.inject.name.Names.named;
  import java.io.IOException;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Field;
  import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+import java.util.Map;
+import java.util.Set;
  import junit.framework.Assert;
  import junit.framework.TestCase;

@@ -44,13 +51,14 @@
    }

    public void testFieldInjectionPoint() throws NoSuchFieldException,  
IOException, ErrorsException {
+    TypeResolver typeResolver = new TypeResolver(getClass());
      Field fooField = getClass().getField("foo");

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

      Dependency<?> dependency =  
getOnlyElement(injectionPoint.getDependencies());
@@ -58,20 +66,22 @@
          + getClass().getName() + ".foo", dependency.toString());
      assertEquals(fooField, dependency.getInjectionPoint().getMember());
      assertEquals(-1, dependency.getParameterIndex());
-    Assert.assertEquals(Key.get(String.class, Names.named("a")),  
dependency.getKey());
+    Assert.assertEquals(Key.get(String.class, named("a")),  
dependency.getKey());
      assertEquals(false, dependency.isNullable());
      assertSimilarWhenReserialized(dependency);
      assertEqualsBothWays(dependency,
-        getOnlyElement(new InjectionPoint(fooField).getDependencies()));
+        getOnlyElement(new InjectionPoint(typeResolver,  
fooField).getDependencies()));
    }

    public void testMethodInjectionPoint() throws Exception {
+    TypeResolver typeResolver = new TypeResolver(getClass());
+
      Method barMethod = getClass().getMethod("bar", String.class);
-    InjectionPoint injectionPoint = new InjectionPoint(barMethod);
+    InjectionPoint injectionPoint = new InjectionPoint(typeResolver,  
barMethod);
      assertSame(barMethod, injectionPoint.getMember());
      assertFalse(injectionPoint.isOptional());
      assertEquals(getClass().getName() + ".bar()",  
injectionPoint.toString());
-    assertEqualsBothWays(injectionPoint, new InjectionPoint(barMethod));
+    assertEqualsBothWays(injectionPoint, new InjectionPoint(typeResolver,  
barMethod));
      assertSimilarWhenReserialized(injectionPoint);

      Dependency<?> dependency =  
getOnlyElement(injectionPoint.getDependencies());
@@ -79,21 +89,23 @@
          + getClass().getName() + ".bar()[0]", dependency.toString());
      assertEquals(barMethod, dependency.getInjectionPoint().getMember());
      assertEquals(0, dependency.getParameterIndex());
-    assertEquals(Key.get(String.class, Names.named("b")),  
dependency.getKey());
+    assertEquals(Key.get(String.class, named("b")), dependency.getKey());
      assertEquals(false, dependency.isNullable());
      assertSimilarWhenReserialized(dependency);
      assertEqualsBothWays(dependency,
-        getOnlyElement(new InjectionPoint(barMethod).getDependencies()));
+        getOnlyElement(new InjectionPoint(typeResolver,  
barMethod).getDependencies()));
    }

    public void testConstructorInjectionPoint() throws  
NoSuchMethodException, IOException,
        ErrorsException {
+    TypeResolver typeResolver = new TypeResolver(Constructable.class);
+
      Constructor<?> constructor =  
Constructable.class.getConstructor(String.class);
-    InjectionPoint injectionPoint = new InjectionPoint(constructor);
+    InjectionPoint injectionPoint = new InjectionPoint(typeResolver,  
constructor);
      assertSame(constructor, injectionPoint.getMember());
      assertFalse(injectionPoint.isOptional());
      assertEquals(Constructable.class.getName() + ".<init>()",  
injectionPoint.toString());
-    assertEqualsBothWays(injectionPoint, new InjectionPoint(constructor));
+    assertEqualsBothWays(injectionPoint, new InjectionPoint(typeResolver,  
constructor));
      assertSimilarWhenReserialized(injectionPoint);

      Dependency<?> dependency =  
getOnlyElement(injectionPoint.getDependencies());
@@ -101,22 +113,76 @@
          + Constructable.class.getName() + ".<init>()[0]",  
dependency.toString());
      assertEquals(constructor, dependency.getInjectionPoint().getMember());
      assertEquals(0, dependency.getParameterIndex());
-    assertEquals(Key.get(String.class, Names.named("c")),  
dependency.getKey());
+    assertEquals(Key.get(String.class, named("c")), dependency.getKey());
      assertEquals(false, dependency.isNullable());
      assertSimilarWhenReserialized(dependency);
      assertEqualsBothWays(dependency,
-        getOnlyElement(new InjectionPoint(constructor).getDependencies()));
+        getOnlyElement(new InjectionPoint(typeResolver,  
constructor).getDependencies()));
    }

    public void testUnattachedDependency() throws IOException {
-    Dependency<String> dependency = Dependency.get(Key.get(String.class,  
Names.named("d")));
+    Dependency<String> dependency = Dependency.get(Key.get(String.class,  
named("d")));
      assertEquals("Key[type=java.lang.String,  
[EMAIL PROTECTED](value=d)]",
          dependency.toString());
      assertNull(dependency.getInjectionPoint());
      assertEquals(-1, dependency.getParameterIndex());
-    assertEquals(Key.get(String.class, Names.named("d")),  
dependency.getKey());
+    assertEquals(Key.get(String.class, named("d")), dependency.getKey());
      assertEquals(true, dependency.isNullable());
      assertSimilarWhenReserialized(dependency);
-    assertEqualsBothWays(dependency, Dependency.get(Key.get(String.class,  
Names.named("d"))));
+    assertEqualsBothWays(dependency, Dependency.get(Key.get(String.class,  
named("d"))));
+  }
+
+  public void testForConstructorOf() {
+    InjectionPoint injectionPoint =  
InjectionPoint.forConstructorOf(Constructable.class);
+    assertEquals(Constructable.class.getName() + ".<init>()",  
injectionPoint.toString());
+  }
+
+  public void testAddForInstanceMethodsAndFields() throws Exception {
+    Method instanceMethod =  
HasInjections.class.getMethod("instanceMethod", String.class);
+    Field instanceField = HasInjections.class.getField("instanceField");
+
+    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)),
+        sink);
+  }
+
+  public void testAddForStaticMethodsAndFields() throws Exception {
+    Method staticMethod = HasInjections.class.getMethod("staticMethod",  
String.class);
+    Field staticField = HasInjections.class.getField("staticField");
+
+    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)),
+        sink);
+  }
+
+  static class HasInjections {
+    @Inject public static void staticMethod(@Named("a") String a) {}
+    @Inject @Named("c") public static String staticField;
+    @Inject public void instanceMethod(@Named("d") String d) {}
+    @Inject @Named("f") public String instanceField;
+  }
+
+  public void testAddForParameterizedInjections() {
+    Set<InjectionPoint> sink = Sets.newHashSet();
+    Type type = new TypeLiteral<ParameterizedInjections<String>>()  
{}.getType();
+
+    InjectionPoint constructor = InjectionPoint.forConstructorOf(type);
+    assertEquals(new Key<Map<String, String>>() {},
+        getOnlyElement(constructor.getDependencies()).getKey());
+
+    InjectionPoint.addForInstanceMethodsAndFields(type, sink);
+    InjectionPoint field = getOnlyElement(sink);
+    assertEquals(new Key<Set<String>>() {},  
getOnlyElement(field.getDependencies()).getKey());
+  }
+
+  static class ParameterizedInjections<T> {
+    @Inject Set<T> setOfTees;
+    @Inject public ParameterizedInjections(Map<T, T> map) {}
    }
  }

--~--~---------~--~----~------------~-------~--~----~
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