• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 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.util;
18 
19 import static com.google.inject.Asserts.assertContains;
20 import static com.google.inject.Asserts.assertEqualWhenReserialized;
21 import static com.google.inject.Asserts.assertEqualsBothWays;
22 import static com.google.inject.util.Types.subtypeOf;
23 import static com.google.inject.util.Types.supertypeOf;
24 
25 import com.google.inject.TypeLiteral;
26 import com.google.inject.internal.MoreTypes;
27 import java.io.IOException;
28 import java.lang.reflect.GenericArrayType;
29 import java.lang.reflect.ParameterizedType;
30 import java.lang.reflect.Type;
31 import java.lang.reflect.WildcardType;
32 import java.util.List;
33 import java.util.Map;
34 import java.util.Set;
35 import junit.framework.Assert;
36 import junit.framework.TestCase;
37 
38 /** @author jessewilson@google.com (Jesse Wilson) */
39 public class TypesTest extends TestCase {
40 
41   // generic types for comparison
42   Map<String, Integer> a;
43   Inner<Float, Double> b;
44   List<Set<String>[][]> c;
45   List<String> d;
46   Set<String> e;
47   Outer<String>.Inner f;
48 
49   private ParameterizedType mapStringInteger;
50   private ParameterizedType innerFloatDouble;
51   private ParameterizedType listSetStringArray;
52   private ParameterizedType listString;
53   private ParameterizedType setString;
54   private ParameterizedType outerInner;
55   private GenericArrayType setStringArray;
56 
57   @Override
setUp()58   protected void setUp() throws Exception {
59     super.setUp();
60     mapStringInteger = (ParameterizedType) getClass().getDeclaredField("a").getGenericType();
61     innerFloatDouble = (ParameterizedType) getClass().getDeclaredField("b").getGenericType();
62     listSetStringArray = (ParameterizedType) getClass().getDeclaredField("c").getGenericType();
63     listString = (ParameterizedType) getClass().getDeclaredField("d").getGenericType();
64     setString = (ParameterizedType) getClass().getDeclaredField("e").getGenericType();
65     outerInner = (ParameterizedType) getClass().getDeclaredField("f").getGenericType();
66     setStringArray = (GenericArrayType) listSetStringArray.getActualTypeArguments()[0];
67   }
68 
testListSetMap()69   public void testListSetMap() {
70     assertEqualsBothWays(mapStringInteger, Types.mapOf(String.class, Integer.class));
71     assertEqualsBothWays(listString, Types.listOf(String.class));
72     assertEqualsBothWays(setString, Types.setOf(String.class));
73   }
74 
testDefensiveCopies()75   public void testDefensiveCopies() {
76     Type[] arguments = new Type[] {String.class, Integer.class};
77     ParameterizedType parameterizedType = Types.newParameterizedType(Map.class, arguments);
78     arguments[0] = null;
79     assertEquals(String.class, parameterizedType.getActualTypeArguments()[0]);
80     parameterizedType.getActualTypeArguments()[1] = null;
81     assertEquals(Integer.class, parameterizedType.getActualTypeArguments()[1]);
82   }
83 
testTypeWithOwnerType()84   public void testTypeWithOwnerType() {
85     ParameterizedType actual =
86         Types.newParameterizedTypeWithOwner(
87             TypesTest.class, Inner.class, Float.class, Double.class);
88     assertEquals(TypesTest.class, actual.getOwnerType());
89     assertEqualsBothWays(innerFloatDouble, actual);
90     // The JDK prints this out as:
91     //     com.google.inject.util.TypesTest.com.google.inject.util.TypesTest$Inner<java.lang.Float, java.lang.Double>
92     // and we think that's wrong, so the assertEquals comparison is worthless. :-(
93     //    assertEquals(innerFloatDouble.toString(), actual.toString());
94 
95     // We think the correct comparison is:
96     assertEquals(
97         "com.google.inject.util.TypesTest$Inner<java.lang.Float, java.lang.Double>",
98         actual.toString());
99   }
100 
testTypeParametersMustNotBePrimitives()101   public void testTypeParametersMustNotBePrimitives() {
102     try {
103       Types.newParameterizedType(Map.class, String.class, int.class);
104       fail();
105     } catch (IllegalArgumentException expected) {
106       assertContains(
107           expected.getMessage(), "Primitive types are not allowed in type parameters: int");
108     }
109   }
110 
111   public List<? extends CharSequence> wildcardExtends;
112   public List<? super CharSequence> wildcardSuper;
113   public List<?> wildcardObject;
114 
testWildcardTypes()115   public void testWildcardTypes() throws NoSuchFieldException, IOException {
116     assertEqualsBothWays(getWildcard("wildcardSuper"), supertypeOf(CharSequence.class));
117     assertEqualsBothWays(getWildcard("wildcardExtends"), subtypeOf(CharSequence.class));
118     assertEqualsBothWays(getWildcard("wildcardObject"), subtypeOf(Object.class));
119 
120     assertEquals("? super java.lang.CharSequence", supertypeOf(CharSequence.class).toString());
121     assertEquals("? extends java.lang.CharSequence", subtypeOf(CharSequence.class).toString());
122     assertEquals("?", subtypeOf(Object.class).toString());
123 
124     assertEqualWhenReserialized(supertypeOf(CharSequence.class));
125     assertEqualWhenReserialized(subtypeOf(CharSequence.class));
126   }
127 
testWildcardBoundsMustNotBePrimitives()128   public void testWildcardBoundsMustNotBePrimitives() {
129     try {
130       supertypeOf(int.class);
131       fail();
132     } catch (IllegalArgumentException expected) {
133       assertContains(
134           expected.getMessage(), "Primitive types are not allowed in wildcard bounds: int");
135     }
136 
137     try {
138       subtypeOf(int.class);
139       fail();
140     } catch (IllegalArgumentException expected) {
141       assertContains(
142           expected.getMessage(), "Primitive types are not allowed in wildcard bounds: int");
143     }
144   }
145 
getWildcard(String fieldName)146   private WildcardType getWildcard(String fieldName) throws NoSuchFieldException {
147     ParameterizedType type = (ParameterizedType) getClass().getField(fieldName).getGenericType();
148     return (WildcardType) type.getActualTypeArguments()[0];
149   }
150 
testEqualsAndHashcode()151   public void testEqualsAndHashcode() {
152     ParameterizedType parameterizedType =
153         Types.newParameterizedType(Map.class, String.class, Integer.class);
154     assertEqualsBothWays(mapStringInteger, parameterizedType);
155     assertEquals(mapStringInteger.toString(), parameterizedType.toString());
156 
157     GenericArrayType genericArrayType =
158         Types.arrayOf(Types.arrayOf(Types.newParameterizedType(Set.class, String.class)));
159     assertEqualsBothWays(setStringArray, genericArrayType);
160     assertEquals(setStringArray.toString(), genericArrayType.toString());
161   }
162 
testToString()163   public void testToString() {
164     Assert.assertEquals("java.lang.String", MoreTypes.typeToString(String.class));
165     assertEquals("java.util.Set<java.lang.String>[][]", MoreTypes.typeToString(setStringArray));
166     assertEquals(
167         "java.util.Map<java.lang.String, java.lang.Integer>",
168         MoreTypes.typeToString(mapStringInteger));
169     assertEquals(
170         "java.util.List<java.util.Set<java.lang.String>[][]>",
171         MoreTypes.typeToString(listSetStringArray));
172     assertEquals(innerFloatDouble.toString(), MoreTypes.typeToString(innerFloatDouble));
173   }
174 
175   static class Owning<A> {}
176 
177   /** Ensure that owning types are required when necessary, and forbidden otherwise. */
testCanonicalizeRequiresOwnerTypes()178   public void testCanonicalizeRequiresOwnerTypes() {
179     try {
180       Types.newParameterizedType(Owning.class, String.class);
181       fail();
182     } catch (IllegalArgumentException expected) {
183       assertContains(expected.getMessage(), "No owner type for enclosed " + Owning.class);
184     }
185 
186     try {
187       Types.newParameterizedTypeWithOwner(Object.class, Set.class, String.class);
188       fail("Expected IllegalArgumentException");
189     } catch (IllegalArgumentException expected) {
190       assertContains(expected.getMessage(), "Owner type for unenclosed " + Set.class);
191     }
192   }
193 
194   @SuppressWarnings("UnusedDeclaration")
195   class Inner<T1, T2> {}
196 
testInnerParameterizedEvenWithZeroArgs()197   public void testInnerParameterizedEvenWithZeroArgs() {
198     TypeLiteral<Outer<String>.Inner> type = new TypeLiteral<Outer<String>.Inner>() {};
199     assertEqualsBothWays(outerInner, type.getType());
200 
201     ParameterizedType parameterizedType = (ParameterizedType) type.getType();
202     assertEquals(0, parameterizedType.getActualTypeArguments().length);
203     assertEquals(new TypeLiteral<Outer<String>>() {}.getType(), parameterizedType.getOwnerType());
204     assertEquals(Outer.Inner.class, parameterizedType.getRawType());
205   }
206 
207   static class Outer<T> {
208     @SuppressWarnings("ClassCanBeStatic")
209     class Inner {}
210   }
211 }
212