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