Author: limpbizkit
Date: Sat Nov 15 01:19:28 2008
New Revision: 668

Added:
    trunk/test/com/google/inject/TypeLiteralInjectionTest.java
Modified:
    trunk/src/com/google/inject/InjectorImpl.java
    trunk/src/com/google/inject/internal/Errors.java

Log:
Guice now reifies types! If you inject a TypeLiteral<T>, Guice will deduce  
what T is and inject the proper TypeLiteral for you.

Modified: trunk/src/com/google/inject/InjectorImpl.java
==============================================================================
--- trunk/src/com/google/inject/InjectorImpl.java       (original)
+++ trunk/src/com/google/inject/InjectorImpl.java       Sat Nov 15 01:19:28 2008
@@ -19,6 +19,7 @@
  import com.google.common.base.Nullable;
  import static com.google.common.base.Preconditions.checkState;
  import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
  import com.google.common.collect.Lists;
  import com.google.common.collect.Maps;
  import com.google.common.collect.Multimap;
@@ -30,6 +31,7 @@
  import com.google.inject.internal.FailableCache;
  import com.google.inject.internal.MatcherAndConverter;
  import com.google.inject.internal.MoreTypes;
+import com.google.inject.internal.SourceProvider;
  import com.google.inject.internal.ToStringBuilder;
  import com.google.inject.spi.BindingTargetVisitor;
  import com.google.inject.spi.Dependency;
@@ -39,6 +41,7 @@
  import java.lang.reflect.AnnotatedElement;
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Field;
+import java.lang.reflect.GenericArrayType;
  import java.lang.reflect.InvocationTargetException;
  import java.lang.reflect.Member;
  import java.lang.reflect.Modifier;
@@ -351,6 +354,14 @@
        throw errors.missingImplementation(key).toException();
      }

+    // Handle TypeLiteral<T> by binding the inner type
+    if (rawType == TypeLiteral.class) {
+      @SuppressWarnings("unchecked") // we have to fudge the inner type as  
Object
+      BindingImpl<T> binding = (BindingImpl<T>) createTypeLiteralBinding(
+          (Key<TypeLiteral<Object>>) key, errors);
+      return binding;
+    }
+
      // Handle @ImplementedBy
      ImplementedBy implementedBy =  
rawType.getAnnotation(ImplementedBy.class);
      if (implementedBy != null) {
@@ -393,6 +404,36 @@
          = Scopes.scope(key, this, lateBoundConstructor, scope);
      return new ClassBindingImpl<T>(
          this, key, source, scopedFactory, scope, lateBoundConstructor,  
loadStrategy);
+  }
+
+  /**
+   * Converts a binding for a [EMAIL PROTECTED] Key<TypeLiteral<T>>} to the 
value  
[EMAIL PROTECTED] TypeLiteral<T>}. It's
+   * a bit awkward because we have to pull out the inner type in the type  
literal.
+   */
+  private <T> BindingImpl<TypeLiteral<T>> createTypeLiteralBinding(
+      Key<TypeLiteral<T>> key, Errors errors) throws ErrorsException {
+    Type typeLiteralType = key.getTypeLiteral().getType();
+    if (!(typeLiteralType instanceof ParameterizedType)) {
+      throw errors.cannotInjectRawTypeLiteral().toException();
+    }
+
+    ParameterizedType parameterizedType = (ParameterizedType)  
typeLiteralType;
+    Type innerType = parameterizedType.getActualTypeArguments()[0];
+
+    // this is unforunate. We don't support building TypeLiterals for type  
variable like 'T'. If
+    // this proves problematic, we can probably fix TypeLiteral to support  
type variables
+    if (!(innerType instanceof Class)
+        && !(innerType instanceof GenericArrayType)
+        && !(innerType instanceof ParameterizedType)) {
+      throw errors.cannotInjectTypeLiteralOf(innerType).toException();
+    }
+
+    @SuppressWarnings("unchecked") // by definition, innerType == T, so  
this is safe
+    TypeLiteral<T> value = (TypeLiteral<T>) TypeLiteral.get(innerType);
+    InternalFactory<TypeLiteral<T>> factory = new  
ConstantFactory<TypeLiteral<T>>(
+        Initializables.of(value));
+    return new InstanceBindingImpl<TypeLiteral<T>>(this, key,  
SourceProvider.UNKNOWN_SOURCE,
+        factory, ImmutableSet.<InjectionPoint>of(), value);
    }

    static class LateBoundConstructor<T> implements InternalFactory<T> {

Modified: trunk/src/com/google/inject/internal/Errors.java
==============================================================================
--- trunk/src/com/google/inject/internal/Errors.java    (original)
+++ trunk/src/com/google/inject/internal/Errors.java    Sat Nov 15 01:19:28  
2008
@@ -36,6 +36,7 @@
  import java.lang.reflect.Constructor;
  import java.lang.reflect.Field;
  import java.lang.reflect.Member;
+import java.lang.reflect.Type;
  import java.util.Collection;
  import java.util.Collections;
  import java.util.Comparator;
@@ -285,6 +286,14 @@

    public Errors cannotInjectRawProvider() {
      return addMessage("Cannot inject a Provider that has no type  
parameter");
+  }
+
+  public Errors cannotInjectTypeLiteralOf(Type unsupportedType) {
+    return addMessage("Cannot inject a TypeLiteral of %s",  
unsupportedType);
+  }
+
+  public Errors cannotInjectRawTypeLiteral() {
+    return addMessage("Cannot inject a TypeLiteral that has no type  
parameter");
    }

    public Errors cannotSatisfyCircularDependency(Class<?> expectedType) {

Added: trunk/test/com/google/inject/TypeLiteralInjectionTest.java
==============================================================================
--- (empty file)
+++ trunk/test/com/google/inject/TypeLiteralInjectionTest.java  Sat Nov 15  
01:19:28 2008
@@ -0,0 +1,106 @@
+/**
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.inject;
+
+import static com.google.inject.Asserts.assertContains;
+import com.google.inject.util.Types;
+import static com.google.inject.util.Types.listOf;
+import java.lang.reflect.Type;
+import java.util.List;
+import junit.framework.TestCase;
+
+/**
+ * Demonstrates type reification.
+ *
+ * @author [EMAIL PROTECTED] (Jesse Wilson)
+ */
+public class TypeLiteralInjectionTest extends TestCase {
+
+  public void testBindingToRawTypeLiteralIsNotAllowed() {
+    try {
+      Guice.createInjector(new AbstractModule() {
+        protected void configure() {
+           
bind(TypeLiteral.class).toInstance(TypeLiteral.get(String.class));
+        }
+      });
+      fail();
+    } catch (CreationException expected) {
+      assertContains(expected.getMessage(),
+          "Binding to core guice framework type is not allowed:  
TypeLiteral");
+    }
+  }
+
+  public void testBindingToParameterizedTypeLiteralIsNotAllowed() {
+    try {
+      Guice.createInjector(new AbstractModule() {
+        protected void configure() {
+          bind(new TypeLiteral<TypeLiteral<String>>() {})
+              .toInstance(TypeLiteral.get(String.class));
+        }
+      });
+      fail();
+    } catch (CreationException expected) {
+      assertContains(expected.getMessage(),
+          "Binding to core guice framework type is not allowed:  
TypeLiteral");
+    }
+  }
+
+  public void testInjectTypeLiteralWithRawTypes() {
+    Type t = A.class.getTypeParameters()[0];
+
+    A a = Guice.createInjector().getInstance(A.class);
+    assertEquals(TypeLiteral.get(String.class), a.string);
+    assertEquals(TypeLiteral.get(listOf(t)), a.listOfT);
+    assertEquals(TypeLiteral.get(listOf(Types.subtypeOf(t))),  
a.listOfWildcardT);
+
+    try {
+      Guice.createInjector().getInstance(B.class);
+      fail();
+    } catch (ConfigurationException expected) {
+      assertContains(expected.getMessage(), "Cannot inject a TypeLiteral  
of T",
+          "while locating com.google.inject.TypeLiteral<T>");
+    }
+  }
+
+  public void testInjectTypeLiteralWithClassTypes() {
+    B<Integer> b = Guice.createInjector().getInstance(new  
Key<B<Integer>>() {});
+    assertEquals(TypeLiteral.get(String.class), b.string);
+    assertEquals(TypeLiteral.get(Integer.class), b.t);
+    assertEquals(TypeLiteral.get(listOf(Integer.class)), b.listOfT);
+    assertEquals(TypeLiteral.get(listOf(Types.subtypeOf(Integer.class))),  
b.listOfWildcardT);
+  }
+
+  public void testInjectRawTypeLiteral() {
+    try {
+      Guice.createInjector().getInstance(TypeLiteral.class);
+      fail();
+    } catch (ConfigurationException expected) {
+      assertContains(expected.getMessage(),
+          "Cannot inject a TypeLiteral that has no type parameter");
+    }
+  }
+
+  static class A<T> {
+    @Inject TypeLiteral<String> string;
+    @Inject TypeLiteral<List<T>> listOfT;
+    @Inject TypeLiteral<List<? extends T>> listOfWildcardT;
+  }
+
+  static class B<T> extends A<T> {
+    @Inject TypeLiteral<T> t;
+  }
+}

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