Home | History | Annotate | Download | only in inject
      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 (at) google.com (Bob Lee)
     34  */
     35 public class TypeLiteralTest extends TestCase {
     36 
     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 
     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 
     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 
     78   public void testMissingTypeParameter() {
     79     try {
     80       new TypeLiteral() {};
     81       fail();
     82     } catch (RuntimeException e) { /* expected */ }
     83   }
     84 
     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 
     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 
    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 
    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    */
    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 
    145   public void testSerialization() throws IOException {
    146     assertNotSerializable(new TypeLiteral<List<String>>() {});
    147   }
    148 
    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 
    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 
    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