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