/* * Copyright (C) 2006 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.assertEqualsBothWays; import static com.google.inject.Asserts.assertNotSerializable; import com.google.common.collect.ImmutableList; import com.google.inject.util.Types; import java.io.IOException; import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.util.List; import junit.framework.TestCase; /** @author crazybob@google.com (Bob Lee) */ public class TypeLiteralTest extends TestCase { public void testWithParameterizedType() { TypeLiteral<List<String>> a = new TypeLiteral<List<String>>() {}; TypeLiteral<List<String>> b = new TypeLiteral<List<String>>(Types.listOf(String.class)) {}; assertEqualsBothWays(a, b); } public void testEquality() { TypeLiteral<List<String>> t1 = new TypeLiteral<List<String>>() {}; TypeLiteral<List<String>> t2 = new TypeLiteral<List<String>>() {}; TypeLiteral<List<Integer>> t3 = new TypeLiteral<List<Integer>>() {}; TypeLiteral<String> t4 = new TypeLiteral<String>() {}; assertEqualsBothWays(t1, t2); assertFalse(t2.equals(t3)); assertFalse(t3.equals(t2)); assertFalse(t2.equals(t4)); assertFalse(t4.equals(t2)); TypeLiteral<String> t5 = TypeLiteral.get(String.class); assertEqualsBothWays(t4, t5); } public List<? extends CharSequence> wildcardExtends; public void testWithWildcardType() throws NoSuchFieldException, IOException { TypeLiteral<?> a = TypeLiteral.get(getClass().getField("wildcardExtends").getGenericType()); TypeLiteral<?> b = TypeLiteral.get(Types.listOf(Types.subtypeOf(CharSequence.class))); TypeLiteral<?> c = new TypeLiteral<List<? extends CharSequence>>() {}; assertEqualsBothWays(a, b); assertEqualsBothWays(b, c); assertEquals("java.util.List<? extends java.lang.CharSequence>", a.toString()); assertEquals("java.util.List<? extends java.lang.CharSequence>", b.toString()); assertEquals("java.util.List<? extends java.lang.CharSequence>", c.toString()); assertNotSerializable(a); assertNotSerializable(b); assertNotSerializable(c); } public void testMissingTypeParameter() { try { new TypeLiteral() {}; fail(); } catch (RuntimeException e) { /* expected */ } } public void testTypesInvolvingArraysForEquality() { TypeLiteral<String[]> stringArray = new TypeLiteral<String[]>() {}; assertEquals(stringArray, new TypeLiteral<String[]>() {}); TypeLiteral<List<String[]>> listOfStringArray = new TypeLiteral<List<String[]>>() {}; assertEquals(listOfStringArray, new TypeLiteral<List<String[]>>() {}); } public void testEqualityOfGenericArrayAndClassArray() { TypeLiteral<String[]> arrayAsClass = TypeLiteral.get(String[].class); TypeLiteral<String[]> arrayAsType = new TypeLiteral<String[]>() {}; 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)); fail(); } catch (IllegalArgumentException expected) { Asserts.assertContains( expected.getMessage(), "Expected a Class, ParameterizedType, or " + "GenericArrayType, but <? extends java.lang.Runnable> is of type " + "com.google.inject.internal.MoreTypes$WildcardTypeImpl"); } } /** * Unlike Key, TypeLiteral retains full type information and differentiates between {@code * int.class} and {@code Integer.class}. */ public void testDifferentiationBetweenWrappersAndPrimitives() { Class[] primitives = new Class[] { boolean.class, byte.class, short.class, int.class, long.class, float.class, double.class, char.class, void.class }; Class[] wrappers = new Class[] { Boolean.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, Character.class, Void.class }; for (int t = 0; t < primitives.length; t++) { @SuppressWarnings("unchecked") TypeLiteral primitiveTl = TypeLiteral.get(primitives[t]); @SuppressWarnings("unchecked") TypeLiteral wrapperTl = TypeLiteral.get(wrappers[t]); assertFalse(primitiveTl.equals(wrapperTl)); assertEquals(primitives[t], primitiveTl.getType()); assertEquals(wrappers[t], wrapperTl.getType()); assertEquals(primitives[t], primitiveTl.getRawType()); assertEquals(wrappers[t], wrapperTl.getRawType()); } } public void testSerialization() throws IOException { assertNotSerializable(new TypeLiteral<List<String>>() {}); } public void testTypeVariableWithNoBound() { TypeVariable<Class<HasTypeParameters>>[] typeVariables = HasTypeParameters.class.getTypeParameters(); TypeLiteral<?> aTl = TypeLiteral.get(typeVariables[0]); assertEquals(Object.class, aTl.getRawType()); assertEquals("A", aTl.toString()); TypeVariable<?> aTv = (TypeVariable) aTl.getType(); assertEquals(HasTypeParameters.class, aTv.getGenericDeclaration()); assertEquals("A", aTv.getName()); assertEquals(ImmutableList.<Type>of(Object.class), ImmutableList.copyOf(aTv.getBounds())); assertEquals("A", aTv.toString()); assertEqualsBothWays(aTl, TypeLiteral.get(HasTypeParameters.class.getTypeParameters()[0])); } public void testTypeVariablesWithSingleBound() { TypeVariable<Class<HasTypeParameters>>[] typeVariables = HasTypeParameters.class.getTypeParameters(); TypeLiteral<?> cTl = TypeLiteral.get(typeVariables[2]); assertEquals(Object.class, cTl.getRawType()); assertEquals("C", cTl.toString()); TypeVariable<?> cTv = (TypeVariable) cTl.getType(); assertEquals(HasTypeParameters.class, cTv.getGenericDeclaration()); assertEquals("C", cTv.getName()); assertEquals(ImmutableList.<Type>of(Runnable.class), ImmutableList.copyOf(cTv.getBounds())); assertEquals("C", cTv.toString()); assertEqualsBothWays(cTl, TypeLiteral.get(HasTypeParameters.class.getTypeParameters()[2])); } public void testTypeVariableWithMultipleBounds() { TypeVariable<Class<HasTypeParameters>>[] typeVariables = HasTypeParameters.class.getTypeParameters(); TypeLiteral<?> bTl = TypeLiteral.get(typeVariables[1]); assertEquals(Object.class, bTl.getRawType()); assertEquals("B", bTl.toString()); TypeVariable<?> bTv = (TypeVariable) bTl.getType(); assertEquals(HasTypeParameters.class, bTv.getGenericDeclaration()); assertEquals("B", bTv.getName()); assertEquals( ImmutableList.<Type>of(Types.listOf(typeVariables[0]), Runnable.class), ImmutableList.copyOf(bTv.getBounds())); assertEquals("B", bTv.toString()); assertEqualsBothWays(bTl, TypeLiteral.get(HasTypeParameters.class.getTypeParameters()[1])); } static class HasTypeParameters<A, B extends List<A> & Runnable, C extends Runnable> { A a; B b; C c; } }