141bc85288590d19c50f299372f942aa27677d77ccrazyboblee/**
241bc85288590d19c50f299372f942aa27677d77ccrazyboblee * Copyright (C) 2006 Google Inc.
341bc85288590d19c50f299372f942aa27677d77ccrazyboblee *
441bc85288590d19c50f299372f942aa27677d77ccrazyboblee * Licensed under the Apache License, Version 2.0 (the "License");
541bc85288590d19c50f299372f942aa27677d77ccrazyboblee * you may not use this file except in compliance with the License.
641bc85288590d19c50f299372f942aa27677d77ccrazyboblee * You may obtain a copy of the License at
741bc85288590d19c50f299372f942aa27677d77ccrazyboblee *
841bc85288590d19c50f299372f942aa27677d77ccrazyboblee * http://www.apache.org/licenses/LICENSE-2.0
941bc85288590d19c50f299372f942aa27677d77ccrazyboblee *
1041bc85288590d19c50f299372f942aa27677d77ccrazyboblee * Unless required by applicable law or agreed to in writing, software
1141bc85288590d19c50f299372f942aa27677d77ccrazyboblee * distributed under the License is distributed on an "AS IS" BASIS,
1241bc85288590d19c50f299372f942aa27677d77ccrazyboblee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1341bc85288590d19c50f299372f942aa27677d77ccrazyboblee * See the License for the specific language governing permissions and
1441bc85288590d19c50f299372f942aa27677d77ccrazyboblee * limitations under the License.
1541bc85288590d19c50f299372f942aa27677d77ccrazyboblee */
1641bc85288590d19c50f299372f942aa27677d77ccrazyboblee
1741bc85288590d19c50f299372f942aa27677d77ccrazybobleepackage com.google.inject;
1841bc85288590d19c50f299372f942aa27677d77ccrazyboblee
19eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkitimport static com.google.inject.Asserts.assertEqualsBothWays;
208c4c71cf6b0d4fcaee49ac6f95acca6ffa78536elimpbizkitimport static com.google.inject.Asserts.assertNotSerializable;
21b7a02b02d81c830d148355c90bc309bcd66fb592sberlin
22d9c913acca55023ef5d76a32c3d4a51ee6b420cbsberlinimport com.google.common.collect.ImmutableList;
233beaaaff52598e849659281fed35dc29a221fac4limpbizkitimport com.google.inject.util.Types;
24b7a02b02d81c830d148355c90bc309bcd66fb592sberlin
25b7a02b02d81c830d148355c90bc309bcd66fb592sberlinimport junit.framework.TestCase;
26b7a02b02d81c830d148355c90bc309bcd66fb592sberlin
27eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkitimport java.io.IOException;
284272aef70de48e239e9f70ab10b0becefd3030cblimpbizkitimport java.lang.reflect.Type;
294272aef70de48e239e9f70ab10b0becefd3030cblimpbizkitimport java.lang.reflect.TypeVariable;
305019270849439d3aa58bc086a4514d7471716a35limpbizkitimport java.util.List;
315019270849439d3aa58bc086a4514d7471716a35limpbizkit
3241bc85288590d19c50f299372f942aa27677d77ccrazyboblee/**
3341bc85288590d19c50f299372f942aa27677d77ccrazyboblee * @author crazybob@google.com (Bob Lee)
3441bc85288590d19c50f299372f942aa27677d77ccrazyboblee */
350baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazybobleepublic class TypeLiteralTest extends TestCase {
3641bc85288590d19c50f299372f942aa27677d77ccrazyboblee
37eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkit  public void testWithParameterizedType() {
381b54d6a560517b057c66c29f3700d8b10bc7bfadcrazyboblee    TypeLiteral<List<String>> a = new TypeLiteral<List<String>>() {};
391b54d6a560517b057c66c29f3700d8b10bc7bfadcrazyboblee    TypeLiteral<List<String>> b = new TypeLiteral<List<String>>(
403beaaaff52598e849659281fed35dc29a221fac4limpbizkit        Types.listOf(String.class)) {};
41eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkit    assertEqualsBothWays(a, b);
421b54d6a560517b057c66c29f3700d8b10bc7bfadcrazyboblee  }
431b54d6a560517b057c66c29f3700d8b10bc7bfadcrazyboblee
4441bc85288590d19c50f299372f942aa27677d77ccrazyboblee  public void testEquality() {
450baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    TypeLiteral<List<String>> t1 = new TypeLiteral<List<String>>() {};
460baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    TypeLiteral<List<String>> t2 = new TypeLiteral<List<String>>() {};
470baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    TypeLiteral<List<Integer>> t3 = new TypeLiteral<List<Integer>>() {};
480baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    TypeLiteral<String> t4 = new TypeLiteral<String>() {};
4941bc85288590d19c50f299372f942aa27677d77ccrazyboblee
50eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkit    assertEqualsBothWays(t1, t2);
5141bc85288590d19c50f299372f942aa27677d77ccrazyboblee
5241bc85288590d19c50f299372f942aa27677d77ccrazyboblee    assertFalse(t2.equals(t3));
5341bc85288590d19c50f299372f942aa27677d77ccrazyboblee    assertFalse(t3.equals(t2));
5441bc85288590d19c50f299372f942aa27677d77ccrazyboblee
5541bc85288590d19c50f299372f942aa27677d77ccrazyboblee    assertFalse(t2.equals(t4));
5641bc85288590d19c50f299372f942aa27677d77ccrazyboblee    assertFalse(t4.equals(t2));
5741bc85288590d19c50f299372f942aa27677d77ccrazyboblee
580baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    TypeLiteral<String> t5 = TypeLiteral.get(String.class);
59eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkit    assertEqualsBothWays(t4, t5);
6041bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
6141bc85288590d19c50f299372f942aa27677d77ccrazyboblee
62cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit  public List<? extends CharSequence> wildcardExtends;
63cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit
64cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit  public void testWithWildcardType() throws NoSuchFieldException, IOException {
65cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit    TypeLiteral<?> a = TypeLiteral.get(getClass().getField("wildcardExtends").getGenericType());
66cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit    TypeLiteral<?> b = TypeLiteral.get(Types.listOf(Types.subtypeOf(CharSequence.class)));
675d5941f9c5a882ac98a3312bd411bde00a1f425fsberlin    TypeLiteral<?> c = new TypeLiteral<List<? extends CharSequence>>() {};
68cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit    assertEqualsBothWays(a, b);
695d5941f9c5a882ac98a3312bd411bde00a1f425fsberlin    assertEqualsBothWays(b, c);
70cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit    assertEquals("java.util.List<? extends java.lang.CharSequence>", a.toString());
71cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit    assertEquals("java.util.List<? extends java.lang.CharSequence>", b.toString());
725d5941f9c5a882ac98a3312bd411bde00a1f425fsberlin    assertEquals("java.util.List<? extends java.lang.CharSequence>", c.toString());
738c4c71cf6b0d4fcaee49ac6f95acca6ffa78536elimpbizkit    assertNotSerializable(a);
748c4c71cf6b0d4fcaee49ac6f95acca6ffa78536elimpbizkit    assertNotSerializable(b);
755d5941f9c5a882ac98a3312bd411bde00a1f425fsberlin    assertNotSerializable(c);
76cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit  }
77cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit
7841bc85288590d19c50f299372f942aa27677d77ccrazyboblee  public void testMissingTypeParameter() {
7941bc85288590d19c50f299372f942aa27677d77ccrazyboblee    try {
800baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee      new TypeLiteral() {};
8141bc85288590d19c50f299372f942aa27677d77ccrazyboblee      fail();
8241bc85288590d19c50f299372f942aa27677d77ccrazyboblee    } catch (RuntimeException e) { /* expected */ }
8341bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
84be2a67fab538548f580477d8a6aca41297fe083ccrazyboblee
85be2a67fab538548f580477d8a6aca41297fe083ccrazyboblee  public void testTypesInvolvingArraysForEquality() {
86be2a67fab538548f580477d8a6aca41297fe083ccrazyboblee    TypeLiteral<String[]> stringArray = new TypeLiteral<String[]>() {};
87be2a67fab538548f580477d8a6aca41297fe083ccrazyboblee    assertEquals(stringArray, new TypeLiteral<String[]>() {});
88be2a67fab538548f580477d8a6aca41297fe083ccrazyboblee
89be2a67fab538548f580477d8a6aca41297fe083ccrazyboblee    TypeLiteral<List<String[]>> listOfStringArray
90be2a67fab538548f580477d8a6aca41297fe083ccrazyboblee        = new TypeLiteral<List<String[]>>() {};
91be2a67fab538548f580477d8a6aca41297fe083ccrazyboblee    assertEquals(listOfStringArray, new TypeLiteral<List<String[]>>() {});
92be2a67fab538548f580477d8a6aca41297fe083ccrazyboblee  }
93eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkit
94eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkit  public void testEqualityOfGenericArrayAndClassArray() {
95eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkit    TypeLiteral<String[]> arrayAsClass = TypeLiteral.get(String[].class);
96eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkit    TypeLiteral<String[]> arrayAsType = new TypeLiteral<String[]>() {};
97f530b2542e7a93416b392f598c90b018d0f38991limpbizkit    assertEquals(arrayAsClass, arrayAsType);
98eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkit  }
99eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkit
1008ba97884d8759890f6b32b65325c1c189061c09elimpbizkit  public void testEqualityOfMultidimensionalGenericArrayAndClassArray() {
1018ba97884d8759890f6b32b65325c1c189061c09elimpbizkit    TypeLiteral<String[][][]> arrayAsClass = TypeLiteral.get(String[][][].class);
1028ba97884d8759890f6b32b65325c1c189061c09elimpbizkit    TypeLiteral<String[][][]> arrayAsType = new TypeLiteral<String[][][]>() {};
1038ba97884d8759890f6b32b65325c1c189061c09elimpbizkit    assertEquals(arrayAsClass, arrayAsType);
1048ba97884d8759890f6b32b65325c1c189061c09elimpbizkit  }
1058ba97884d8759890f6b32b65325c1c189061c09elimpbizkit
106cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit  public void testTypeLiteralsMustHaveRawTypes() {
107cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit    try {
108cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit      TypeLiteral.get(Types.subtypeOf(Runnable.class));
109cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit      fail();
110cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit    } catch (IllegalArgumentException expected) {
111cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit      Asserts.assertContains(expected.getMessage(), "Expected a Class, ParameterizedType, or "
112cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit          + "GenericArrayType, but <? extends java.lang.Runnable> is of type "
113cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit          + "com.google.inject.internal.MoreTypes$WildcardTypeImpl");
114cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit    }
115cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit  }
116cb32cbcd87c8b511afd532fc626110ee9362fb03limpbizkit
117820d486060f4abac469437e3c4943e520036c3b3limpbizkit  /**
118820d486060f4abac469437e3c4943e520036c3b3limpbizkit   * Unlike Key, TypeLiteral retains full type information and differentiates
119820d486060f4abac469437e3c4943e520036c3b3limpbizkit   * between {@code int.class} and {@code Integer.class}.
120820d486060f4abac469437e3c4943e520036c3b3limpbizkit   */
121820d486060f4abac469437e3c4943e520036c3b3limpbizkit  public void testDifferentiationBetweenWrappersAndPrimitives() {
122820d486060f4abac469437e3c4943e520036c3b3limpbizkit    Class[] primitives = new Class[] {
123820d486060f4abac469437e3c4943e520036c3b3limpbizkit        boolean.class, byte.class, short.class, int.class, long.class,
124820d486060f4abac469437e3c4943e520036c3b3limpbizkit        float.class, double.class, char.class, void.class
125820d486060f4abac469437e3c4943e520036c3b3limpbizkit    };
126820d486060f4abac469437e3c4943e520036c3b3limpbizkit    Class[] wrappers = new Class[] {
127820d486060f4abac469437e3c4943e520036c3b3limpbizkit        Boolean.class, Byte.class, Short.class, Integer.class, Long.class,
128820d486060f4abac469437e3c4943e520036c3b3limpbizkit        Float.class, Double.class, Character.class, Void.class
129820d486060f4abac469437e3c4943e520036c3b3limpbizkit    };
130820d486060f4abac469437e3c4943e520036c3b3limpbizkit
131820d486060f4abac469437e3c4943e520036c3b3limpbizkit    for (int t = 0; t < primitives.length; t++) {
132820d486060f4abac469437e3c4943e520036c3b3limpbizkit      @SuppressWarnings("unchecked")
133820d486060f4abac469437e3c4943e520036c3b3limpbizkit      TypeLiteral primitiveTl = TypeLiteral.get(primitives[t]);
134820d486060f4abac469437e3c4943e520036c3b3limpbizkit      @SuppressWarnings("unchecked")
135820d486060f4abac469437e3c4943e520036c3b3limpbizkit      TypeLiteral wrapperTl = TypeLiteral.get(wrappers[t]);
136820d486060f4abac469437e3c4943e520036c3b3limpbizkit
137820d486060f4abac469437e3c4943e520036c3b3limpbizkit      assertFalse(primitiveTl.equals(wrapperTl));
138820d486060f4abac469437e3c4943e520036c3b3limpbizkit      assertEquals(primitives[t], primitiveTl.getType());
139820d486060f4abac469437e3c4943e520036c3b3limpbizkit      assertEquals(wrappers[t], wrapperTl.getType());
140820d486060f4abac469437e3c4943e520036c3b3limpbizkit      assertEquals(primitives[t], primitiveTl.getRawType());
141820d486060f4abac469437e3c4943e520036c3b3limpbizkit      assertEquals(wrappers[t], wrapperTl.getRawType());
142820d486060f4abac469437e3c4943e520036c3b3limpbizkit    }
143820d486060f4abac469437e3c4943e520036c3b3limpbizkit  }
144820d486060f4abac469437e3c4943e520036c3b3limpbizkit
145eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkit  public void testSerialization() throws IOException {
1468c4c71cf6b0d4fcaee49ac6f95acca6ffa78536elimpbizkit    assertNotSerializable(new TypeLiteral<List<String>>() {});
147eab76471fbc2118a3c07d103d4b5548e153ed9e7limpbizkit  }
1484272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit
1494272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit  public void testTypeVariableWithNoBound() {
1504272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    TypeVariable<Class<HasTypeParameters>>[] typeVariables
1514272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit        = HasTypeParameters.class.getTypeParameters();
1524272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit
1534272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    TypeLiteral<?> aTl = TypeLiteral.get(typeVariables[0]);
1544272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals(Object.class, aTl.getRawType());
1554272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals("A", aTl.toString());
1564272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    TypeVariable<?> aTv = (TypeVariable) aTl.getType();
1574272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals(HasTypeParameters.class, aTv.getGenericDeclaration());
1584272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals("A", aTv.getName());
159de4cc320c98b800f81703b8a186e08c478fab74cguice.mirrorbot@gmail.com    assertEquals(ImmutableList.<Type>of(Object.class), ImmutableList.copyOf(aTv.getBounds()));
1604272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals("A", aTv.toString());
1614272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEqualsBothWays(aTl, TypeLiteral.get(HasTypeParameters.class.getTypeParameters()[0]));
1624272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit  }
1634272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit
1644272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit  public void testTypeVariablesWithSingleBound() {
1654272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    TypeVariable<Class<HasTypeParameters>>[] typeVariables
1664272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit        = HasTypeParameters.class.getTypeParameters();
1674272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit
1684272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    TypeLiteral<?> cTl = TypeLiteral.get(typeVariables[2]);
1694272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals(Object.class, cTl.getRawType());
1704272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals("C", cTl.toString());
1714272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    TypeVariable<?> cTv = (TypeVariable) cTl.getType();
1724272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals(HasTypeParameters.class, cTv.getGenericDeclaration());
1734272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals("C", cTv.getName());
174de4cc320c98b800f81703b8a186e08c478fab74cguice.mirrorbot@gmail.com    assertEquals(ImmutableList.<Type>of(Runnable.class), ImmutableList.copyOf(cTv.getBounds()));
1754272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals("C", cTv.toString());
1764272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEqualsBothWays(cTl, TypeLiteral.get(HasTypeParameters.class.getTypeParameters()[2]));
1774272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit  }
1784272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit
1794272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit  public void testTypeVariableWithMultipleBounds() {
1804272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    TypeVariable<Class<HasTypeParameters>>[] typeVariables
1814272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit        = HasTypeParameters.class.getTypeParameters();
1824272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit
1834272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    TypeLiteral<?> bTl = TypeLiteral.get(typeVariables[1]);
1844272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals(Object.class, bTl.getRawType());
1854272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals("B", bTl.toString());
1864272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    TypeVariable<?> bTv = (TypeVariable) bTl.getType();
1874272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals(HasTypeParameters.class, bTv.getGenericDeclaration());
1884272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals("B", bTv.getName());
1894272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals(ImmutableList.<Type>of(Types.listOf(typeVariables[0]), Runnable.class),
190de4cc320c98b800f81703b8a186e08c478fab74cguice.mirrorbot@gmail.com        ImmutableList.copyOf(bTv.getBounds()));
1914272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEquals("B", bTv.toString());
1924272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    assertEqualsBothWays(bTl, TypeLiteral.get(HasTypeParameters.class.getTypeParameters()[1]));
1934272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit  }
1944272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit
1954272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit  class HasTypeParameters<A, B extends List<A> & Runnable, C extends Runnable> {
1964272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit    A a; B b; C c;
1974272aef70de48e239e9f70ab10b0becefd3030cblimpbizkit  }
19841bc85288590d19c50f299372f942aa27677d77ccrazyboblee}
199