1 /**
2  * Copyright (C) 2006 Google Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.inject;
18 
19 import static com.google.inject.Asserts.assertEqualsBothWays;
20 import static com.google.inject.Asserts.assertNotSerializable;
21 
22 import com.google.common.collect.ImmutableList;
23 import com.google.inject.util.Types;
24 
25 import junit.framework.TestCase;
26 
27 import java.io.IOException;
28 import java.lang.reflect.Type;
29 import java.lang.reflect.TypeVariable;
30 import java.util.List;
31 
32 /**
33  * @author crazybob@google.com (Bob Lee)
34  */
35 public class TypeLiteralTest extends TestCase {
36 
testWithParameterizedType()37   public void testWithParameterizedType() {
38     TypeLiteral<List<String>> a = new TypeLiteral<List<String>>() {};
39     TypeLiteral<List<String>> b = new TypeLiteral<List<String>>(
40         Types.listOf(String.class)) {};
41     assertEqualsBothWays(a, b);
42   }
43 
testEquality()44   public void testEquality() {
45     TypeLiteral<List<String>> t1 = new TypeLiteral<List<String>>() {};
46     TypeLiteral<List<String>> t2 = new TypeLiteral<List<String>>() {};
47     TypeLiteral<List<Integer>> t3 = new TypeLiteral<List<Integer>>() {};
48     TypeLiteral<String> t4 = new TypeLiteral<String>() {};
49 
50     assertEqualsBothWays(t1, t2);
51 
52     assertFalse(t2.equals(t3));
53     assertFalse(t3.equals(t2));
54 
55     assertFalse(t2.equals(t4));
56     assertFalse(t4.equals(t2));
57 
58     TypeLiteral<String> t5 = TypeLiteral.get(String.class);
59     assertEqualsBothWays(t4, t5);
60   }
61 
62   public List<? extends CharSequence> wildcardExtends;
63 
testWithWildcardType()64   public void testWithWildcardType() throws NoSuchFieldException, IOException {
65     TypeLiteral<?> a = TypeLiteral.get(getClass().getField("wildcardExtends").getGenericType());
66     TypeLiteral<?> b = TypeLiteral.get(Types.listOf(Types.subtypeOf(CharSequence.class)));
67     TypeLiteral<?> c = new TypeLiteral<List<? extends CharSequence>>() {};
68     assertEqualsBothWays(a, b);
69     assertEqualsBothWays(b, c);
70     assertEquals("java.util.List<? extends java.lang.CharSequence>", a.toString());
71     assertEquals("java.util.List<? extends java.lang.CharSequence>", b.toString());
72     assertEquals("java.util.List<? extends java.lang.CharSequence>", c.toString());
73     assertNotSerializable(a);
74     assertNotSerializable(b);
75     assertNotSerializable(c);
76   }
77 
testMissingTypeParameter()78   public void testMissingTypeParameter() {
79     try {
80       new TypeLiteral() {};
81       fail();
82     } catch (RuntimeException e) { /* expected */ }
83   }
84 
testTypesInvolvingArraysForEquality()85   public void testTypesInvolvingArraysForEquality() {
86     TypeLiteral<String[]> stringArray = new TypeLiteral<String[]>() {};
87     assertEquals(stringArray, new TypeLiteral<String[]>() {});
88 
89     TypeLiteral<List<String[]>> listOfStringArray
90         = new TypeLiteral<List<String[]>>() {};
91     assertEquals(listOfStringArray, new TypeLiteral<List<String[]>>() {});
92   }
93 
testEqualityOfGenericArrayAndClassArray()94   public void testEqualityOfGenericArrayAndClassArray() {
95     TypeLiteral<String[]> arrayAsClass = TypeLiteral.get(String[].class);
96     TypeLiteral<String[]> arrayAsType = new TypeLiteral<String[]>() {};
97     assertEquals(arrayAsClass, arrayAsType);
98   }
99 
testEqualityOfMultidimensionalGenericArrayAndClassArray()100   public void testEqualityOfMultidimensionalGenericArrayAndClassArray() {
101     TypeLiteral<String[][][]> arrayAsClass = TypeLiteral.get(String[][][].class);
102     TypeLiteral<String[][][]> arrayAsType = new TypeLiteral<String[][][]>() {};
103     assertEquals(arrayAsClass, arrayAsType);
104   }
105 
testTypeLiteralsMustHaveRawTypes()106   public void testTypeLiteralsMustHaveRawTypes() {
107     try {
108       TypeLiteral.get(Types.subtypeOf(Runnable.class));
109       fail();
110     } catch (IllegalArgumentException expected) {
111       Asserts.assertContains(expected.getMessage(), "Expected a Class, ParameterizedType, or "
112           + "GenericArrayType, but <? extends java.lang.Runnable> is of type "
113           + "com.google.inject.internal.MoreTypes$WildcardTypeImpl");
114     }
115   }
116 
117   /**
118    * Unlike Key, TypeLiteral retains full type information and differentiates
119    * between {@code int.class} and {@code Integer.class}.
120    */
testDifferentiationBetweenWrappersAndPrimitives()121   public void testDifferentiationBetweenWrappersAndPrimitives() {
122     Class[] primitives = new Class[] {
123         boolean.class, byte.class, short.class, int.class, long.class,
124         float.class, double.class, char.class, void.class
125     };
126     Class[] wrappers = new Class[] {
127         Boolean.class, Byte.class, Short.class, Integer.class, Long.class,
128         Float.class, Double.class, Character.class, Void.class
129     };
130 
131     for (int t = 0; t < primitives.length; t++) {
132       @SuppressWarnings("unchecked")
133       TypeLiteral primitiveTl = TypeLiteral.get(primitives[t]);
134       @SuppressWarnings("unchecked")
135       TypeLiteral wrapperTl = TypeLiteral.get(wrappers[t]);
136 
137       assertFalse(primitiveTl.equals(wrapperTl));
138       assertEquals(primitives[t], primitiveTl.getType());
139       assertEquals(wrappers[t], wrapperTl.getType());
140       assertEquals(primitives[t], primitiveTl.getRawType());
141       assertEquals(wrappers[t], wrapperTl.getRawType());
142     }
143   }
144 
testSerialization()145   public void testSerialization() throws IOException {
146     assertNotSerializable(new TypeLiteral<List<String>>() {});
147   }
148 
testTypeVariableWithNoBound()149   public void testTypeVariableWithNoBound() {
150     TypeVariable<Class<HasTypeParameters>>[] typeVariables
151         = HasTypeParameters.class.getTypeParameters();
152 
153     TypeLiteral<?> aTl = TypeLiteral.get(typeVariables[0]);
154     assertEquals(Object.class, aTl.getRawType());
155     assertEquals("A", aTl.toString());
156     TypeVariable<?> aTv = (TypeVariable) aTl.getType();
157     assertEquals(HasTypeParameters.class, aTv.getGenericDeclaration());
158     assertEquals("A", aTv.getName());
159     assertEquals(ImmutableList.<Type>of(Object.class), ImmutableList.copyOf(aTv.getBounds()));
160     assertEquals("A", aTv.toString());
161     assertEqualsBothWays(aTl, TypeLiteral.get(HasTypeParameters.class.getTypeParameters()[0]));
162   }
163 
testTypeVariablesWithSingleBound()164   public void testTypeVariablesWithSingleBound() {
165     TypeVariable<Class<HasTypeParameters>>[] typeVariables
166         = HasTypeParameters.class.getTypeParameters();
167 
168     TypeLiteral<?> cTl = TypeLiteral.get(typeVariables[2]);
169     assertEquals(Object.class, cTl.getRawType());
170     assertEquals("C", cTl.toString());
171     TypeVariable<?> cTv = (TypeVariable) cTl.getType();
172     assertEquals(HasTypeParameters.class, cTv.getGenericDeclaration());
173     assertEquals("C", cTv.getName());
174     assertEquals(ImmutableList.<Type>of(Runnable.class), ImmutableList.copyOf(cTv.getBounds()));
175     assertEquals("C", cTv.toString());
176     assertEqualsBothWays(cTl, TypeLiteral.get(HasTypeParameters.class.getTypeParameters()[2]));
177   }
178 
testTypeVariableWithMultipleBounds()179   public void testTypeVariableWithMultipleBounds() {
180     TypeVariable<Class<HasTypeParameters>>[] typeVariables
181         = HasTypeParameters.class.getTypeParameters();
182 
183     TypeLiteral<?> bTl = TypeLiteral.get(typeVariables[1]);
184     assertEquals(Object.class, bTl.getRawType());
185     assertEquals("B", bTl.toString());
186     TypeVariable<?> bTv = (TypeVariable) bTl.getType();
187     assertEquals(HasTypeParameters.class, bTv.getGenericDeclaration());
188     assertEquals("B", bTv.getName());
189     assertEquals(ImmutableList.<Type>of(Types.listOf(typeVariables[0]), Runnable.class),
190         ImmutableList.copyOf(bTv.getBounds()));
191     assertEquals("B", bTv.toString());
192     assertEqualsBothWays(bTl, TypeLiteral.get(HasTypeParameters.class.getTypeParameters()[1]));
193   }
194 
195   class HasTypeParameters<A, B extends List<A> & Runnable, C extends Runnable> {
196     A a; B b; C c;
197   }
198 }
199