alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (TypeTokenTest.java)

This example Java source code file (TypeTokenTest.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

assignability, integer, iterable, list, n11, number, parameterizedtype, reflection, string, suppresswarnings, typecapture, typetoken, util

The TypeTokenTest.java Java example source code

/*
 * Copyright (C) 2007 The Guava Authors
 *
 * 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.common.reflect;

import static com.google.common.truth.Truth.assertThat;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.primitives.Primitives;
import com.google.common.testing.EqualsTester;
import com.google.common.testing.NullPointerTester;
import com.google.common.testing.SerializableTester;
import com.google.common.truth.IterableSubject;
import com.google.errorprone.annotations.CanIgnoreReturnValue;

import junit.framework.TestCase;

import java.io.Serializable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

/**
 * Test cases for {@link TypeToken}.
 *
 * @author Sven Mawson
 * @author Ben Yu
 */
@AndroidIncompatible // lots of failures, possibly some related to bad equals() implementations?
public class TypeTokenTest extends TestCase {

  private abstract static class StringList implements List<String> {}

  private abstract static class IntegerList implements List<Integer> {}

  public void testValueEqualityNotInstanceEquality() {
    TypeToken<List a = new TypeToken>() {};
    TypeToken<List b = new TypeToken>() {};
    assertEquals(a, b);
  }

  public <T> void testVariableTypeTokenNotAllowed() {
    try {
      new TypeToken<T>() {};
      fail();
    } catch (IllegalStateException expected) {}
  }

  public void testRawTypeIsCorrect() {
    TypeToken<List token = new TypeToken>() {};
    assertEquals(List.class, token.getRawType());
  }

  public void testTypeIsCorrect() {
    TypeToken<List token = new TypeToken>() {};
    assertEquals(StringList.class.getGenericInterfaces()[0], token.getType());
  }

  @SuppressWarnings("rawtypes") // Trying to test TypeToken.of(List.class)
  public void testGetClass() {
    TypeToken<List> token = TypeToken.of(List.class);
    assertEquals(new TypeToken<List>() {}, token);
  }

  public void testGetType() {
    TypeToken<?> t = TypeToken.of(StringList.class.getGenericInterfaces()[0]);
    assertEquals(new TypeToken<List() {}, t);
  }

  public void testNonStaticLocalClass() {
    class Local<T> {}
    TypeToken<Local type = new TypeToken>() {};
    assertEquals(Types.newParameterizedType(Local.class, String.class),
        type.getType());
    assertEquals(new Local<String>() {}.getClass().getGenericSuperclass(), type.getType());
  }

  public void testStaticLocalClass() {
    doTestStaticLocalClass();
  }

  private static void doTestStaticLocalClass() {
    class Local<T> {}
    TypeToken<Local type = new TypeToken>() {};
    assertEquals(Types.newParameterizedType(Local.class, String.class),
        type.getType());
    assertEquals(new Local<String>() {}.getClass().getGenericSuperclass(), type.getType());
  }

  public void testGenericArrayType() {
    TypeToken<List token = new TypeToken[]>() {};
    assertEquals(List[].class, token.getRawType());
    assertThat(token.getType()).isInstanceOf(GenericArrayType.class);
  }

  public void testMultiDimensionalGenericArrayType() {
    TypeToken<List token = new TypeToken[][][]>() {};
    assertEquals(List[][][].class, token.getRawType());
    assertThat(token.getType()).isInstanceOf(GenericArrayType.class);
  }

  public <T> void testGenericVariableTypeArrays() {
    assertEquals("T[]", new TypeToken<T[]>() {}.toString());
  }

  public void testResolveType() throws Exception {
    Method getFromList = List.class.getMethod("get", int.class);
    TypeToken<?> returnType = new TypeToken>() {}
        .resolveType(getFromList.getGenericReturnType());
    assertEquals(String.class, returnType.getType());
  }

  public <F extends Enum & Iterable>
  void testResolveType_fromTypeVariable() {
    TypeToken<?> f = TypeToken.of(new TypeCapture() {}.capture());
    assertEquals(String.class,
        f.resolveType(Function.class.getTypeParameters()[0]).getType());
    assertEquals(Integer.class,
        f.resolveType(Function.class.getTypeParameters()[1]).getType());
    assertEquals(Long.class,
        f.resolveType(Iterable.class.getTypeParameters()[0]).getType());
  }

  public <E extends Comparable & Iterable>
  void testResolveType_fromTypeVariable_onlyDirectBoundsAreUsed() {
    TypeToken<?> e = TypeToken.of(new TypeCapture() {}.capture());
    assertEquals(Integer.class,
        e.resolveType(Iterable.class.getTypeParameters()[0]).getType());
  }

  public void testResolveType_fromWildcard() {
    ParameterizedType withWildcardType = (ParameterizedType)
        new TypeCapture<Comparable>() {}.capture();
    TypeToken<?> wildcardType = TypeToken.of(withWildcardType.getActualTypeArguments()[0]);
    assertEquals(String.class,
        wildcardType.resolveType(Iterable.class.getTypeParameters()[0]).getType());
  }

  public void testGetTypes_noSuperclass() {
    TypeToken<Object>.TypeSet types = new TypeToken() {}.getTypes();
    assertThat(types).contains(TypeToken.of(Object.class));
    assertThat(types.rawTypes()).contains(Object.class);
    assertThat(types.interfaces()).isEmpty();
    assertThat(types.interfaces().rawTypes()).isEmpty();
    assertThat(types.classes()).contains(TypeToken.of(Object.class));
    assertThat(types.classes().rawTypes()).contains(Object.class);
  }

  public void testGetTypes_fromInterface() {
    TypeToken<Interface1>.TypeSet types = new TypeToken() {}.getTypes();
    assertThat(types).contains(TypeToken.of(Interface1.class));
    assertThat(types.rawTypes()).contains(Interface1.class);
    assertThat(types.interfaces()).contains(TypeToken.of(Interface1.class));
    assertThat(types.interfaces().rawTypes()).contains(Interface1.class);
    assertThat(types.classes()).isEmpty();
    assertThat(types.classes().rawTypes()).isEmpty();
  }

  public void testGetTypes_fromPrimitive() {
    TypeToken<Integer>.TypeSet types = TypeToken.of(int.class).getTypes();
    assertThat(types).contains(TypeToken.of(int.class));
    assertThat(types.rawTypes()).contains(int.class);
    assertThat(types.interfaces()).isEmpty();
    assertThat(types.interfaces().rawTypes()).isEmpty();
    assertThat(types.classes()).contains(TypeToken.of(int.class));
    assertThat(types.classes().rawTypes()).contains(int.class);
  }

  public void testGetTypes_withInterfacesAndSuperclasses() {
    abstract class Class2 extends Class1 implements Interface12 {}
    abstract class Class3<T> extends Class2 implements Interface3 {}
    TypeToken<Class3.TypeSet types = new TypeToken>() {}.getTypes();
    makeUnmodifiable(types).containsExactly(
        new TypeToken<Class3() {},
        new TypeToken<Interface3() {},
        new TypeToken<Iterable() {},
        TypeToken.of(Class2.class),
        TypeToken.of(Interface12.class),
        TypeToken.of(Interface1.class),
        TypeToken.of(Interface2.class),
        TypeToken.of(Class1.class),
        TypeToken.of(Object.class));
    makeUnmodifiable(types.interfaces()).containsExactly(
        new TypeToken<Interface3() {},
        TypeToken.of(Interface12.class),
        TypeToken.of(Interface1.class),
        TypeToken.of(Interface2.class),
        new TypeToken<Iterable() {});
    makeUnmodifiable(types.classes()).containsExactly(
        new TypeToken<Class3() {},
        TypeToken.of(Class2.class),
        TypeToken.of(Class1.class),
        TypeToken.of(Object.class));
    assertSubtypeFirst(types);
  }

  public void testGetTypes_rawTypes_withInterfacesAndSuperclasses() {
    abstract class Class2 extends Class1 implements Interface12 {}
    abstract class Class3<T> extends Class2 implements Interface3 {}
    TypeToken<Class3.TypeSet types = new TypeToken>() {}.getTypes();
    makeUnmodifiable(types.rawTypes()).containsExactly(
        Class3.class, Interface3.class,
        Iterable.class,
        Class2.class,
        Interface12.class,
        Interface1.class,
        Interface2.class,
        Class1.class,
        Object.class);
    makeUnmodifiable(types.interfaces().rawTypes()).containsExactly(
        Interface3.class,
        Interface12.class,
        Interface1.class,
        Interface2.class,
        Iterable.class);
    makeUnmodifiable(types.classes().rawTypes()).containsExactly(
        Class3.class,
        Class2.class,
        Class1.class,
        Object.class);
    assertSubtypeFirst(types);
  }

  public <A extends Class1 & Interface1, B extends A>
  void testGetTypes_ignoresTypeVariablesByDefault() {
    TypeToken<?>.TypeSet types = TypeToken.of(new TypeCapture() {}.capture()).getTypes();
    makeUnmodifiable(types).containsExactly(
        TypeToken.of(Interface1.class), TypeToken.of(Class1.class),
        TypeToken.of(Object.class));
    assertSubtypeFirst(types);
    makeUnmodifiable(types.interfaces()).containsExactly(TypeToken.of(Interface1.class));
    makeUnmodifiable(types.classes())
        .containsExactly(TypeToken.of(Class1.class), TypeToken.of(Object.class))
        .inOrder();
  }

  public <A extends Class1 & Interface1, B extends A>
  void testGetTypes_rawTypes_ignoresTypeVariablesByDefault() {
    TypeToken<?>.TypeSet types = TypeToken.of(new TypeCapture() {}.capture()).getTypes();
    makeUnmodifiable(types.rawTypes())
        .containsExactly(Interface1.class, Class1.class, Object.class);
    makeUnmodifiable(types.interfaces().rawTypes()).containsExactly(Interface1.class);
    makeUnmodifiable(types.classes().rawTypes())
        .containsExactly(Class1.class, Object.class)
        .inOrder();
  }

  public <A extends Interface1 & Interface2 & Interface3
  void testGetTypes_manyBounds() {
    TypeToken<?>.TypeSet types = TypeToken.of(new TypeCapture() {}.capture()).getTypes();
    makeUnmodifiable(types.rawTypes())
        .containsExactly(Interface1.class, Interface2.class, Interface3.class, Iterable.class);
  }

  private static void assertSubtypeFirst(TypeToken<?>.TypeSet types) {
    assertSubtypeTokenBeforeSupertypeToken(types);
    assertSubtypeTokenBeforeSupertypeToken(types.interfaces());
    assertSubtypeTokenBeforeSupertypeToken(types.classes());
    assertSubtypeBeforeSupertype(types.rawTypes());
    assertSubtypeBeforeSupertype(types.interfaces().rawTypes());
    assertSubtypeBeforeSupertype(types.classes().rawTypes());
  }

  private static void assertSubtypeTokenBeforeSupertypeToken(
      Iterable<? extends TypeToken types) {
    int i = 0;
    for (TypeToken<?> left : types) {
      int j = 0;
      for (TypeToken<?> right : types) {
        if (left.isSupertypeOf(right)) {
          assertTrue(left + " should be after " + right, i >= j);
        }
        j++;
      }
      i++;
    }
  }

  private static void assertSubtypeBeforeSupertype(Iterable<? extends Class types) {
    int i = 0;
    for (Class<?> left : types) {
      int j = 0;
      for (Class<?> right : types) {
        if (left.isAssignableFrom(right)) {
          assertTrue(left + " should be after " + right, i >= j);
        }
        j++;
      }
      i++;
    }
  }

  // Tests to make sure assertSubtypeBeforeSupertype() works.

  public void testAssertSubtypeTokenBeforeSupertypeToken_empty() {
    assertSubtypeTokenBeforeSupertypeToken(ImmutableList.<TypeTokenof());
  }

  public void testAssertSubtypeTokenBeforeSupertypeToken_oneType() {
    assertSubtypeTokenBeforeSupertypeToken(ImmutableList.of(TypeToken.of(String.class)));
  }

  public void testAssertSubtypeTokenBeforeSupertypeToken_subtypeFirst() {
    assertSubtypeTokenBeforeSupertypeToken(
        ImmutableList.of(TypeToken.of(String.class), TypeToken.of(CharSequence.class)));
  }

  public void testAssertSubtypeTokenBeforeSupertypeToken_supertypeFirst() {
    try {
      assertSubtypeTokenBeforeSupertypeToken(
          ImmutableList.of(TypeToken.of(CharSequence.class), TypeToken.of(String.class)));
    } catch (AssertionError expected) {
      return;
    }
    fail();
  }

  public void testAssertSubtypeTokenBeforeSupertypeToken_duplicate() {
    try {
      assertSubtypeTokenBeforeSupertypeToken(
          ImmutableList.of(TypeToken.of(String.class), TypeToken.of(String.class)));
    } catch (AssertionError expected) {
      return;
    }
    fail();
  }

  public void testAssertSubtypeBeforeSupertype_empty() {
    assertSubtypeBeforeSupertype(ImmutableList.<Classof());
  }

  public void testAssertSubtypeBeforeSupertype_oneType() {
    assertSubtypeBeforeSupertype(ImmutableList.of(String.class));
  }

  public void testAssertSubtypeBeforeSupertype_subtypeFirst() {
    assertSubtypeBeforeSupertype(
        ImmutableList.of(String.class, CharSequence.class));
  }

  public void testAssertSubtypeBeforeSupertype_supertypeFirst() {
    try {
      assertSubtypeBeforeSupertype(
          ImmutableList.of(CharSequence.class, String.class));
    } catch (AssertionError expected) {
      return;
    }
    fail();
  }

  public void testAssertSubtypeBeforeSupertype_duplicate() {
    try {
      assertSubtypeBeforeSupertype(
          ImmutableList.of(String.class, String.class));
    } catch (AssertionError expected) {
      return;
    }
    fail();
  }

  public void testGetGenericSuperclass_noSuperclass() {
    assertNull(new TypeToken<Object>() {}.getGenericSuperclass());
    assertEquals(TypeToken.of(Object.class),
        new TypeToken<Object[]>() {}.getGenericSuperclass());
    assertNull(new TypeToken<List() {}.getGenericSuperclass());
    assertEquals(TypeToken.of(Object.class),
        new TypeToken<List() {}.getGenericSuperclass());
  }

  public void testGetGenericSuperclass_withSuperclass() {
    TypeToken<? super ArrayList superToken =
        new TypeToken<ArrayList() {}.getGenericSuperclass();
    assertEquals(ArrayList.class.getSuperclass(), superToken.getRawType());
    assertEquals(String.class,
        ((ParameterizedType) superToken.getType()).getActualTypeArguments()[0]);
    assertEquals(TypeToken.of(Base.class), TypeToken.of(Sub.class).getGenericSuperclass());
    assertEquals(TypeToken.of(Object.class), TypeToken.of(Sub[].class).getGenericSuperclass());
  }

  public <T> void testGetGenericSuperclass_typeVariable_unbounded() {
    assertEquals(TypeToken.of(Object.class),
        TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericSuperclass());
    assertEquals(TypeToken.of(Object.class), new TypeToken<T[]>() {}.getGenericSuperclass());
  }

  public <T extends ArrayList
  void testGetGenericSuperclass_typeVariable_boundIsClass() {
    assertEquals(new TypeToken<ArrayList() {},
        TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericSuperclass());
    assertEquals(TypeToken.of(Object.class), new TypeToken<T[]>() {}.getGenericSuperclass());
  }

  public <T extends Enum
  void testGetGenericSuperclass_typeVariable_boundIsFBoundedClass() {
    assertEquals(new TypeToken<Enum() {},
        TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericSuperclass());
    assertEquals(TypeToken.of(Object.class), new TypeToken<T[]>() {}.getGenericSuperclass());
  }

  public <T extends List
  void testGetGenericSuperclass_typeVariable_boundIsInterface() {
    assertNull(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericSuperclass());
    assertEquals(TypeToken.of(Object.class), new TypeToken<T[]>() {}.getGenericSuperclass());
  }

  public <T extends ArrayList
  void testGetGenericSuperclass_typeVariable_boundIsTypeVariableAndClass() {
    assertEquals(TypeToken.of(new TypeCapture<T>() {}.capture()),
        TypeToken.of(new TypeCapture<T1>() {}.capture()).getGenericSuperclass());
    assertEquals(TypeToken.of(Object.class), new TypeToken<T[]>() {}.getGenericSuperclass());
  }

  public <T extends List
  void testGetGenericSuperclass_typeVariable_boundIsTypeVariableAndInterface() {
    assertNull(TypeToken.of(new TypeCapture<T1>() {}.capture()).getGenericSuperclass());
    assertEquals(TypeToken.of(Object.class), new TypeToken<T1[]>() {}.getGenericSuperclass());
  }

  public void testGetGenericSuperclass_wildcard_lowerBounded() {
    assertEquals(TypeToken.of(Object.class),
        TypeToken.of(Types.supertypeOf(String.class)).getGenericSuperclass());
    assertEquals(new TypeToken<Object>() {},
        TypeToken.of(Types.supertypeOf(String[].class)).getGenericSuperclass());
    assertEquals(new TypeToken<Object>() {},
        TypeToken.of(Types.supertypeOf(CharSequence.class)).getGenericSuperclass());
  }

  public void testGetGenericSuperclass_wildcard_boundIsClass() {
    assertEquals(TypeToken.of(Object.class),
        TypeToken.of(Types.subtypeOf(Object.class)).getGenericSuperclass());
    assertEquals(new TypeToken<Object[]>() {},
        TypeToken.of(Types.subtypeOf(Object[].class)).getGenericSuperclass());
  }

  public void testGetGenericSuperclass_wildcard_boundIsInterface() {
    assertNull(TypeToken.of(Types.subtypeOf(CharSequence.class)).getGenericSuperclass());
    assertEquals(new TypeToken<CharSequence[]>() {},
        TypeToken.of(Types.subtypeOf(CharSequence[].class)).getGenericSuperclass());
  }

  public <T> void testGetGenericInterfaces_typeVariable_unbounded() {
    assertThat(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces()).isEmpty();
    assertHasArrayInterfaces(new TypeToken<T[]>() {});
  }

  public <T extends NoInterface> void testGetGenericInterfaces_typeVariable_boundIsClass() {
    assertThat(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces()).isEmpty();
    assertHasArrayInterfaces(new TypeToken<T[]>() {});
  }

  public <T extends NoInterface&Iterable
  void testGetGenericInterfaces_typeVariable_boundsAreClassWithInterface() {
    makeUnmodifiable(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces())
        .containsExactly(new TypeToken<Iterable() {});
    assertHasArrayInterfaces(new TypeToken<T[]>() {});
  }

  public <T extends CharSequence&Iterable
  void testGetGenericInterfaces_typeVariable_boundsAreInterfaces() {
    makeUnmodifiable(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces())
        .containsExactly(TypeToken.of(CharSequence.class), new TypeToken<Iterable() {});
    assertHasArrayInterfaces(new TypeToken<T[]>() {});
  }

  public <T extends CharSequence&Iterable
  void testGetGenericInterfaces_typeVariable_boundsAreFBoundedInterfaces() {
    makeUnmodifiable(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces())
        .containsExactly(TypeToken.of(CharSequence.class), new TypeToken<Iterable() {});
    assertHasArrayInterfaces(new TypeToken<T[]>() {});
  }

  public <T extends Base&Iterable
  void testGetGenericInterfaces_typeVariable_boundsAreClassWithFBoundedInterface() {
    makeUnmodifiable(TypeToken.of(new TypeCapture<T>() {}.capture()).getGenericInterfaces())
        .containsExactly(new TypeToken<Iterable() {});
    assertHasArrayInterfaces(new TypeToken<T[]>() {});
  }

  public <T extends NoInterface, T1 extends T, T2 extends T1>
  void testGetGenericInterfaces_typeVariable_boundIsTypeVariableAndClass() {
    assertThat(TypeToken.of(new TypeCapture<T2>() {}.capture()).getGenericInterfaces()).isEmpty();
    assertHasArrayInterfaces(new TypeToken<T2[]>() {});
  }

  public <T extends Iterable
  void testGetGenericInterfaces_typeVariable_boundIsTypeVariableAndInterface() {
    makeUnmodifiable(TypeToken.of(new TypeCapture<T2>() {}.capture()).getGenericInterfaces())
        .containsExactly(TypeToken.of(new TypeCapture<T1>() {}.capture()));
    assertHasArrayInterfaces(new TypeToken<T2[]>() {});
  }

  public void testGetGenericInterfaces_wildcard_lowerBounded() {
    assertThat(TypeToken.of(Types.supertypeOf(String.class)).getGenericInterfaces()).isEmpty();
    assertThat(TypeToken.of(Types.supertypeOf(String[].class)).getGenericInterfaces()).isEmpty();
  }

  public void testGetGenericInterfaces_wildcard_boundIsClass() {
    assertThat(TypeToken.of(Types.subtypeOf(Object.class)).getGenericInterfaces()).isEmpty();
    assertThat(TypeToken.of(Types.subtypeOf(Object[].class)).getGenericInterfaces()).isEmpty();
  }

  public void testGetGenericInterfaces_wildcard_boundIsInterface() {
    TypeToken<Iterable interfaceType = new TypeToken>() {};
    makeUnmodifiable(TypeToken.of(Types.subtypeOf(interfaceType.getType())).getGenericInterfaces())
        .containsExactly(interfaceType);
    assertHasArrayInterfaces(new TypeToken<Iterable() {});
  }

  public void testGetGenericInterfaces_noInterface() {
    assertThat(new TypeToken<NoInterface>() {}.getGenericInterfaces()).isEmpty();
    assertHasArrayInterfaces(new TypeToken<NoInterface[]>() {});
  }

  public void testGetGenericInterfaces_withInterfaces() {
    Map<Class interfaceMap = Maps.newHashMap();
    for (TypeToken<?> interfaceType
        : new TypeToken<Implementation() {}.getGenericInterfaces()) {
      interfaceMap.put(interfaceType.getRawType(), interfaceType.getType());
    }
    assertEquals(ImmutableMap.of(
            Iterable.class, new TypeToken<Iterable() {}.getType(),
            Map.class, new TypeToken<Map() {}.getType()),
        interfaceMap);
  }

  private interface Interface1 {}
  private interface Interface2 {}
  private interface Interface3<T> extends Iterable {}
  private interface Interface12 extends Interface1, Interface2 {}
  private static class Class1 implements Interface1 {}

  private static final class NoInterface {}

  private abstract static class Implementation<K, V>
      implements Iterable<V>, Map {}

  private abstract static class First<T> {}

  private abstract static class Second<D> extends First {}

  private abstract static class Third<T, D> extends Second {}

  private abstract static class Fourth<T, D> extends Third {}

  private static class ConcreteIS extends Fourth<Integer, String> {}

  private static class ConcreteSI extends Fourth<String, Integer> {}

  public void testAssignableClassToClass() {
    @SuppressWarnings("rawtypes") // To test TypeToken<List>
    TypeToken<List> tokL = new TypeToken() {};
    assertTrue(tokL.isSupertypeOf(List.class));
    assertTrue(tokL.isSupertypeOf(ArrayList.class));
    assertFalse(tokL.isSupertypeOf(List[].class));

    TypeToken<Number> tokN = new TypeToken() {};
    assertTrue(tokN.isSupertypeOf(Number.class));
    assertTrue(tokN.isSupertypeOf(Integer.class));
  }

  public <T> void testAssignableParameterizedTypeToObject() {
    assertTrue(TypeToken.of(Object.class).isSupertypeOf(
        TypeToken.of(new TypeCapture<T>() {}.capture())));
    assertFalse(TypeToken.of(int.class).isSupertypeOf(
        TypeToken.of(new TypeCapture<T>() {}.capture())));
  }

  public <T, T1 extends T> void testAssignableGenericArrayToGenericArray() {
    assertTrue(new TypeToken<T[]>() {}.isSupertypeOf(new TypeToken() {}));
    assertTrue(new TypeToken<T[]>() {}.isSupertypeOf(new TypeToken() {}));
    assertFalse(new TypeToken<T[]>() {}.isSupertypeOf(new TypeToken() {}));
  }

  public <T, T1 extends T> void testAssignableGenericArrayToClass() {
    assertTrue(TypeToken.of(Object[].class.getSuperclass())
        .isSupertypeOf(new TypeToken<T[]>() {}));
    for (Class<?> interfaceType : Object[].class.getInterfaces()) {
      assertTrue(TypeToken.of(interfaceType)
          .isSupertypeOf(new TypeToken<T[]>() {}));
    }
    assertTrue(TypeToken.of(Object.class).isSupertypeOf(new TypeToken<T[]>() {}));
    assertFalse(TypeToken.of(String.class).isSupertypeOf(new TypeToken<T[]>() {}));
  }

  public void testAssignableWildcardBoundedByArrayToArrayClass() {
    Type wildcardType = Types.subtypeOf(Object[].class);
    assertTrue(TypeToken.of(Object[].class).isSupertypeOf(wildcardType));
    assertTrue(TypeToken.of(Object.class).isSupertypeOf(wildcardType));
    assertFalse(TypeToken.of(wildcardType).isSupertypeOf(wildcardType));
    assertFalse(TypeToken.of(int[].class).isSupertypeOf(wildcardType));
  }

  public void testAssignableWildcardTypeParameterToClassTypeParameter() {
    TypeToken<?> wildcardType = new TypeToken>() {};
    assertFalse(new TypeToken<Iterable() {}.isSupertypeOf(wildcardType));
    assertFalse(new TypeToken<Iterable() {}.isSupertypeOf(wildcardType));
    assertTrue(wildcardType.isSupertypeOf(wildcardType));
    assertFalse(new TypeToken<Iterable() {}.isSupertypeOf(wildcardType));
  }

  public void testAssignableArrayClassToBoundedWildcard() {
    TypeToken<?> subtypeOfArray = TypeToken.of(Types.subtypeOf(Object[].class));
    TypeToken<?> supertypeOfArray = TypeToken.of(Types.supertypeOf(Object[].class));
    assertFalse(subtypeOfArray.isSupertypeOf(Object[].class));
    assertFalse(subtypeOfArray.isSupertypeOf(Object[][].class));
    assertFalse(subtypeOfArray.isSupertypeOf(String[].class));
    assertTrue(supertypeOfArray.isSupertypeOf(Object[].class));
    assertFalse(supertypeOfArray.isSupertypeOf(Object.class));
    assertTrue(supertypeOfArray.isSupertypeOf(Object[][].class));
    assertTrue(supertypeOfArray.isSupertypeOf(String[].class));
  }

  public void testAssignableClassTypeParameterToWildcardTypeParameter() {
    TypeToken<?> subtypeOfArray = new TypeToken>() {};
    TypeToken<?> supertypeOfArray = new TypeToken>() {};
    assertTrue(subtypeOfArray.isSupertypeOf(new TypeToken<Iterable() {}));
    assertTrue(subtypeOfArray.isSupertypeOf(new TypeToken<Iterable() {}));
    assertTrue(subtypeOfArray.isSupertypeOf(new TypeToken<Iterable() {}));
    assertTrue(supertypeOfArray.isSupertypeOf(new TypeToken<Iterable() {}));
    assertTrue(supertypeOfArray.isSupertypeOf(new TypeToken<Iterable() {}));
    assertFalse(supertypeOfArray.isSupertypeOf(new TypeToken<Iterable() {}));
    assertFalse(supertypeOfArray.isSupertypeOf(new TypeToken<Iterable() {}));
  }

  public void testAssignableNonParameterizedClassToWildcard() {
    TypeToken<?> supertypeOfString = TypeToken.of(Types.supertypeOf(String.class));
    assertFalse(supertypeOfString.isSupertypeOf(supertypeOfString));
    assertFalse(supertypeOfString.isSupertypeOf(Object.class));
    assertFalse(supertypeOfString.isSupertypeOf(CharSequence.class));
    assertTrue(supertypeOfString.isSupertypeOf(String.class));
    assertTrue(supertypeOfString.isSupertypeOf(Types.subtypeOf(String.class)));
  }

  public void testAssignableWildcardBoundedByIntArrayToArrayClass() {
    Type wildcardType = Types.subtypeOf(int[].class);
    assertTrue(TypeToken.of(int[].class).isSupertypeOf(wildcardType));
    assertTrue(TypeToken.of(Object.class).isSupertypeOf(wildcardType));
    assertFalse(TypeToken.of(wildcardType).isSupertypeOf(wildcardType));
    assertFalse(TypeToken.of(Object[].class).isSupertypeOf(wildcardType));
  }

  public void testAssignableWildcardTypeParameterBoundedByIntArrayToArrayClassTypeParameter() {
    TypeToken<?> wildcardType = new TypeToken>() {};
    assertFalse(new TypeToken<Iterable() {}.isSupertypeOf(wildcardType));
    assertFalse(new TypeToken<Iterable() {}.isSupertypeOf(wildcardType));
    assertTrue(wildcardType.isSupertypeOf(wildcardType));
    assertFalse(new TypeToken<Iterable() {}.isSupertypeOf(wildcardType));
  }

  public void testAssignableWildcardToWildcard() {
    TypeToken<?> subtypeOfArray = TypeToken.of(Types.subtypeOf(Object[].class));
    TypeToken<?> supertypeOfArray = TypeToken.of(Types.supertypeOf(Object[].class));
    assertTrue(supertypeOfArray.isSupertypeOf(subtypeOfArray));
    assertFalse(supertypeOfArray.isSupertypeOf(supertypeOfArray));
    assertFalse(subtypeOfArray.isSupertypeOf(subtypeOfArray));
    assertFalse(subtypeOfArray.isSupertypeOf(supertypeOfArray));
  }

  public void testAssignableWildcardTypeParameterToWildcardTypeParameter() {
    TypeToken<?> subtypeOfArray = new TypeToken>() {};
    TypeToken<?> supertypeOfArray = new TypeToken>() {};
    assertFalse(supertypeOfArray.isSupertypeOf(subtypeOfArray));
    assertTrue(supertypeOfArray.isSupertypeOf(supertypeOfArray));
    assertTrue(subtypeOfArray.isSupertypeOf(subtypeOfArray));
    assertFalse(subtypeOfArray.isSupertypeOf(supertypeOfArray));
  }

  public <T> void testAssignableGenericArrayToArrayClass() {
    assertTrue(TypeToken.of(Object[].class).isSupertypeOf(new TypeToken<T[]>() {}));
    assertTrue(TypeToken.of(Object[].class).isSupertypeOf(new TypeToken<T[][]>() {}));
    assertTrue(TypeToken.of(Object[][].class).isSupertypeOf(new TypeToken<T[][]>() {}));
  }

  public void testAssignableParameterizedTypeToClass() {
    @SuppressWarnings("rawtypes") // Trying to test raw class
    TypeToken<List> tokL = new TypeToken() {};
    assertTrue(tokL.isSupertypeOf(StringList.class));
    assertTrue(tokL.isSupertypeOf(
        StringList.class.getGenericInterfaces()[0]));

    @SuppressWarnings("rawtypes") // Trying to test raw class
    TypeToken<Second> tokS = new TypeToken() {};
    assertTrue(tokS.isSupertypeOf(Second.class));
    assertTrue(tokS.isSupertypeOf(Third.class.getGenericSuperclass()));
  }

  public void testAssignableArrayToClass() {
    @SuppressWarnings("rawtypes") // Trying to test raw class
    TypeToken<List[]> tokL = new TypeToken() {};
    assertTrue(tokL.isSupertypeOf(List[].class));
    assertFalse(tokL.isSupertypeOf(List.class));

    @SuppressWarnings("rawtypes") // Trying to test raw class
    TypeToken<Second[]> tokS = new TypeToken() {};
    assertTrue(tokS.isSupertypeOf(Second[].class));
    assertTrue(tokS.isSupertypeOf(Third[].class));
  }

  @SuppressWarnings("rawtypes") // Trying to test raw class
  public void testAssignableTokenToClass() {
    TypeToken<List> tokL = new TypeToken() {};
    assertTrue(tokL.isSupertypeOf(new TypeToken<List>() {}));
    assertTrue(tokL.isSupertypeOf(new TypeToken<List() {}));
    assertTrue(tokL.isSupertypeOf(new TypeToken<List() {}));

    TypeToken<Second> tokS = new TypeToken() {};
    assertTrue(tokS.isSupertypeOf(new TypeToken<Second>() {}));
    assertTrue(tokS.isSupertypeOf(new TypeToken<Third>() {}));
    assertTrue(tokS.isSupertypeOf(
        new TypeToken<Third() {}));

    TypeToken<List[]> tokA = new TypeToken() {};
    assertTrue(tokA.isSupertypeOf(new TypeToken<List[]>() {}));
    assertTrue(tokA.isSupertypeOf(new TypeToken<List() {}));
    assertTrue(tokA.isSupertypeOf(new TypeToken<List() {}));
  }

  public void testAssignableClassToType() {
    TypeToken<List tokenL = new TypeToken>() {};
    assertTrue(tokenL.isSupertypeOf(StringList.class));
    assertFalse(tokenL.isSupertypeOf(List.class));

    TypeToken<First tokenF = new TypeToken>() {};
    assertTrue(tokenF.isSupertypeOf(ConcreteIS.class));
    assertFalse(tokenF.isSupertypeOf(ConcreteSI.class));
  }

  public void testAssignableClassToArrayType() {
    TypeToken<List tokenL = new TypeToken[]>() {};
    assertTrue(tokenL.isSupertypeOf(StringList[].class));
    assertFalse(tokenL.isSupertypeOf(List[].class));
  }

  public void testAssignableParameterizedTypeToType() {
    TypeToken<List tokenL = new TypeToken>() {};
    assertTrue(tokenL.isSupertypeOf(
        StringList.class.getGenericInterfaces()[0]));
    assertFalse(tokenL.isSupertypeOf(
        IntegerList.class.getGenericInterfaces()[0]));

    TypeToken<First tokenF = new TypeToken>() {};
    assertTrue(tokenF.isSupertypeOf(
        ConcreteIS.class.getGenericSuperclass()));
    assertFalse(tokenF.isSupertypeOf(
        ConcreteSI.class.getGenericSuperclass()));
  }

  public void testGenericArrayTypeToArrayType() {
    TypeToken<List tokL = new TypeToken[]>() {};
    TypeToken<ArrayList token =
        new TypeToken<ArrayList() {};
    assertTrue(tokL.isSupertypeOf(tokL.getType()));
    assertTrue(tokL.isSupertypeOf(token.getType()));
  }

  public void testAssignableTokenToType() {
    TypeToken<List tokenL = new TypeToken>() {};
    assertTrue(tokenL.isSupertypeOf(new TypeToken<List() {}));
    assertTrue(tokenL.isSupertypeOf(new TypeToken<ArrayList() {}));
    assertTrue(tokenL.isSupertypeOf(new TypeToken<StringList>() {}));

    TypeToken<First tokenF = new TypeToken>() {};
    assertTrue(tokenF.isSupertypeOf(new TypeToken<Second() {}));
    assertTrue(tokenF.isSupertypeOf(
        new TypeToken<Third() {}));
    assertFalse(tokenF.isSupertypeOf(
        new TypeToken<Third() {}));
    assertTrue(tokenF.isSupertypeOf(
        new TypeToken<Fourth() {}));
    assertFalse(tokenF.isSupertypeOf(
        new TypeToken<Fourth() {}));
    assertTrue(tokenF.isSupertypeOf(new TypeToken<ConcreteIS>() {}));
    assertFalse(tokenF.isSupertypeOf(new TypeToken<ConcreteSI>() {}));
  }

  public void testAssignableWithWildcards() {
    TypeToken<?> unboundedToken = new TypeToken>() {};
    TypeToken<?> upperBoundToken = new TypeToken>() {};
    TypeToken<?> lowerBoundToken = new TypeToken>() {};
    TypeToken<?> concreteToken = new TypeToken>() {};
    TypeToken<?> subtypeToken = new TypeToken>() {};
    TypeToken<?> supertypeToken = new TypeToken>() {};
    List<TypeToken allTokens = ImmutableList.of(
        unboundedToken, upperBoundToken, lowerBoundToken,
        concreteToken, subtypeToken, supertypeToken);

    for (TypeToken<?> typeToken : allTokens) {
      assertTrue(typeToken.toString(), unboundedToken.isSupertypeOf(typeToken));
    }

    assertFalse(upperBoundToken.isSupertypeOf(unboundedToken));
    assertTrue(upperBoundToken.isSupertypeOf(upperBoundToken));
    assertFalse(upperBoundToken.isSupertypeOf(lowerBoundToken));
    assertTrue(upperBoundToken.isSupertypeOf(concreteToken));
    assertTrue(upperBoundToken.isSupertypeOf(subtypeToken));
    assertFalse(upperBoundToken.isSupertypeOf(supertypeToken));

    assertFalse(lowerBoundToken.isSupertypeOf(unboundedToken));
    assertFalse(lowerBoundToken.isSupertypeOf(upperBoundToken));
    assertTrue(lowerBoundToken.isSupertypeOf(lowerBoundToken));
    assertTrue(lowerBoundToken.isSupertypeOf(concreteToken));
    assertFalse(lowerBoundToken.isSupertypeOf(subtypeToken));
    assertTrue(lowerBoundToken.isSupertypeOf(supertypeToken));

    for (TypeToken<?> typeToken : allTokens) {
      assertEquals(typeToken.toString(),
          typeToken == concreteToken, concreteToken.isSupertypeOf(typeToken));
    }

    for (TypeToken<?> typeToken : allTokens) {
      assertEquals(typeToken.toString(),
          typeToken == subtypeToken, subtypeToken.isSupertypeOf(typeToken));
    }

    for (TypeToken<?> typeToken : allTokens) {
      assertEquals(typeToken.toString(),
          typeToken == supertypeToken, supertypeToken.isSupertypeOf(typeToken));
    }
  }

  public <N1 extends Number, N2 extends Number, N11 extends N1>
      void testisSupertypeOf_typeVariable() {
    assertAssignable(TypeToken.of(new TypeCapture<N1>() {}.capture()),
        TypeToken.of(new TypeCapture<N1>() {}.capture()));
    assertNotAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
    assertNotAssignable(new TypeToken<Number>() {},
        TypeToken.of(new TypeCapture<N1>() {}.capture()));
    assertAssignable(TypeToken.of(new TypeCapture<N11>() {}.capture()),
        TypeToken.of(new TypeCapture<N1>() {}.capture()));
    assertNotAssignable(TypeToken.of(new TypeCapture<N2>() {}.capture()),
        TypeToken.of(new TypeCapture<N1>() {}.capture()));
  }

  public <N1 extends Number, N2 extends Number, N11 extends N1>
      void testisSupertypeOf_equalWildcardTypes() {
    assertAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
    assertAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
    assertAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
    assertAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
  }

  public <N> void testisSupertypeOf_wildcard_noBound() {
    assertAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
    assertAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
  }

  public <N1 extends Number, N2 extends Number, N11 extends N1>
      void testisSupertypeOf_wildcardType_upperBoundMatch() {
    // ? extends T
    assertAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
    assertNotAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
    assertNotAssignable(new TypeToken<List() {},
        new TypeToken<List() {});

    // ? extends Number
    assertAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
    assertAssignable(new TypeToken<ArrayList() {},
        new TypeToken<List() {});
    assertAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
  }

  public <N1 extends Number, N2 extends Number, N11 extends N1>
      void testisSupertypeOf_wildcardType_lowerBoundMatch() {
    // ? super T
    assertAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
    assertAssignable(new TypeToken<ArrayList() {},
        new TypeToken<List() {});
    assertNotAssignable(new TypeToken<ArrayList() {},
        new TypeToken<List() {});
    assertAssignable(new TypeToken<ArrayList() {},
        new TypeToken<List() {});
    assertAssignable(new TypeToken<ArrayList() {},
        new TypeToken<List() {});

    // ? super Number
    assertNotAssignable(new TypeToken<ArrayList() {},
        new TypeToken<List() {});
    assertAssignable(new TypeToken<ArrayList() {},
        new TypeToken<List() {});
    assertAssignable(new TypeToken<ArrayList() {},
        new TypeToken<List() {});
  }

  public <L extends List>
      void testisSupertypeOf_recursiveTypeVariableBounds() {
    assertAssignable(TypeToken.of(new TypeCapture<L>() {}.capture()),
        TypeToken.of(new TypeCapture<L>() {}.capture()));
    assertNotAssignable(TypeToken.of(new TypeCapture<R>() {}.capture()),
        TypeToken.of(new TypeCapture<L>() {}.capture()));
    assertAssignable(TypeToken.of(new TypeCapture<L>() {}.capture()),
        new TypeToken<List() {});
  }

  public void testisSupertypeOf_resolved() {
    assertFalse(Assignability.of().isAssignable());
    assertTrue(new Assignability<Integer, Integer>() {}.isAssignable());
    assertTrue(new Assignability<Integer, Object>() {}.isAssignable());
    assertFalse(new Assignability<Integer, String>() {}.isAssignable());
    TypeTokenTest.<Number, Integer>assignabilityTestWithTypeVariables();
  }

  public <From extends String&List
  void testMultipleTypeBoundsAssignability() {
    assertTrue(new Assignability<From, String>() {}.isAssignable());
    assertFalse(new Assignability<From, Number>() {}.isAssignable());
    assertTrue(new Assignability<From, Iterable() {}.isAssignable());
    assertFalse(new Assignability<From, Iterable() {}.isAssignable());
  }

  private static <N1 extends Number, N11 extends N1>
      void assignabilityTestWithTypeVariables() {
    assertTrue(new Assignability<N11, N1>() {}.isAssignable());
    assertTrue(new Assignability<N11, Number>() {}.isAssignable());
    assertFalse(new Assignability<Number, N11>() {}.isAssignable());
  }

  public void testIsArray_arrayClasses() {
    assertTrue(TypeToken.of(Object[].class).isArray());
    assertTrue(TypeToken.of(Object[][].class).isArray());
    assertTrue(TypeToken.of(char[].class).isArray());
    assertTrue(TypeToken.of(char[][].class).isArray());
    assertTrue(TypeToken.of(byte[].class).isArray());
    assertTrue(TypeToken.of(short[].class).isArray());
    assertTrue(TypeToken.of(int[].class).isArray());
    assertTrue(TypeToken.of(long[].class).isArray());
    assertTrue(TypeToken.of(float[].class).isArray());
    assertTrue(TypeToken.of(double[].class).isArray());
    assertFalse(TypeToken.of(Object.class).isArray());
    assertFalse(TypeToken.of(void.class).isArray());
  }

  public <T> void testIsArray_genericArrayClasses() {
    assertFalse(TypeToken.of(new TypeCapture<T>() {}.capture()).isArray());
    assertTrue(new TypeToken<T[]>() {}.isArray());
    assertTrue(new TypeToken<T[][]>() {}.isArray());
  }

  public void testIsArray_wildcardType() {
    assertTrue(TypeToken.of(Types.subtypeOf(Object[].class)).isArray());
    assertTrue(TypeToken.of(Types.subtypeOf(int[].class)).isArray());
    assertFalse(TypeToken.of(Types.subtypeOf(Object.class)).isArray());
    assertFalse(TypeToken.of(Types.supertypeOf(Object[].class)).isArray());
  }

  public <T extends Integer> void testPrimitiveWrappingAndUnwrapping() {
    for (Class<?> type : Primitives.allPrimitiveTypes()) {
      assertIsPrimitive(TypeToken.of(type));
    }
    for (Class<?> type : Primitives.allWrapperTypes()) {
      assertIsWrapper(TypeToken.of(type));
    }
    assertNotPrimitiveNorWrapper(TypeToken.of(String.class));
    assertNotPrimitiveNorWrapper(TypeToken.of(Object[].class));
    assertNotPrimitiveNorWrapper(TypeToken.of(Types.subtypeOf(Object.class)));
    assertNotPrimitiveNorWrapper(new TypeToken<List() {});
    assertNotPrimitiveNorWrapper(TypeToken.of(new TypeCapture<T>() {}.capture()));
  }

  public void testGetComponentType_arrayClasses() {
    assertEquals(Object.class, TypeToken.of(Object[].class).getComponentType().getType());
    assertEquals(Object[].class, TypeToken.of(Object[][].class).getComponentType().getType());
    assertEquals(char.class, TypeToken.of(char[].class).getComponentType().getType());
    assertEquals(char[].class, TypeToken.of(char[][].class).getComponentType().getType());
    assertEquals(byte.class, TypeToken.of(byte[].class).getComponentType().getType());
    assertEquals(short.class, TypeToken.of(short[].class).getComponentType().getType());
    assertEquals(int.class, TypeToken.of(int[].class).getComponentType().getType());
    assertEquals(long.class, TypeToken.of(long[].class).getComponentType().getType());
    assertEquals(float.class, TypeToken.of(float[].class).getComponentType().getType());
    assertEquals(double.class, TypeToken.of(double[].class).getComponentType().getType());
    assertNull(TypeToken.of(Object.class).getComponentType());
    assertNull(TypeToken.of(void.class).getComponentType());
  }

  public <T> void testGetComponentType_genericArrayClasses() {
    assertNull(TypeToken.of(new TypeCapture<T>() {}.capture()).getComponentType());
    assertEquals(TypeToken.of(new TypeCapture<T>() {}.capture()),
        new TypeToken<T[]>() {}.getComponentType());
    assertEquals(new TypeToken<T[]>() {}, new TypeToken() {}.getComponentType());
  }

  public void testGetComponentType_wildcardType() {
    assertEquals(Types.subtypeOf(Object.class),
        TypeToken.of(Types.subtypeOf(Object[].class)).getComponentType().getType());
    assertEquals(Types.subtypeOf(Object[].class),
        Types.newArrayType(
            TypeToken.of(Types.subtypeOf(Object[].class)).getComponentType().getType()));
    assertEquals(int.class,
        TypeToken.of(Types.subtypeOf(int[].class)).getComponentType().getType());
    assertNull(TypeToken.of(Types.subtypeOf(Object.class)).getComponentType());
    assertNull(TypeToken.of(Types.supertypeOf(Object[].class)).getComponentType());
  }

  private interface NumberList<T extends Number> {}

  public void testImplicitUpperBoundForWildcards() {
    assertAssignable(
        new TypeToken<NumberList() {},
        new TypeToken<NumberList() {});
    assertAssignable(
        new TypeToken<NumberList() {},
        new TypeToken<NumberList() {});
  }

  public <T extends Readable & Appendable> void testMultiBound() {
    assertAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
    assertAssignable(new TypeToken<List() {},
        new TypeToken<List() {});
  }

  public void testToGenericType() {
    assertEquals(TypeToken.of(String.class), TypeToken.toGenericType(String.class));
    assertEquals(new TypeToken<int[]>() {}, TypeToken.toGenericType(int[].class));
    @SuppressWarnings("rawtypes") // Iterable.class
    TypeToken<? extends Iterable> genericType = TypeToken.toGenericType(Iterable.class);
    assertEquals(Iterable.class, genericType.getRawType());
    assertEquals(Types.newParameterizedType(Iterable.class, Iterable.class.getTypeParameters()[0]),
        genericType.getType());
  }

  public void testToGenericType_staticMemberClass() throws Exception {
    Method getStaticAnonymousClassMethod =
        TypeTokenTest.class.getDeclaredMethod("getStaticAnonymousClass", Object.class);
    ParameterizedType javacReturnType =
        (ParameterizedType) getStaticAnonymousClassMethod.getGenericReturnType();

    ParameterizedType parameterizedType =
        (ParameterizedType) TypeToken.toGenericType(GenericClass.class).getType();
    assertThat(parameterizedType.getOwnerType()).isEqualTo(javacReturnType.getOwnerType());
  }

  public static <T> GenericClass getStaticAnonymousClass(final T value) {
    return new GenericClass<T>() {
      @SuppressWarnings("unused")
      public T innerValue = value;
    };
  }

  private interface ListIterable<T> extends Iterable> {}
  private interface StringListIterable extends ListIterable<String> {}
  private interface ListArrayIterable<T> extends Iterable[]> {}
  private interface StringListArrayIterable extends ListIterable<String> {}

  public void testGetSupertype_withTypeVariable() {
    ParameterizedType expectedType = Types.newParameterizedType(Iterable.class,
        Types.newParameterizedType(List.class, ListIterable.class.getTypeParameters()[0]));
    assertEquals(expectedType,
        TypeToken.of(ListIterable.class).getSupertype(Iterable.class).getType());
  }

  public <A, T extends Number&Iterable
  void testGetSupertype_typeVariableWithMultipleBounds() {
    assertEquals(Number.class,
        new TypeToken<T>(getClass()) {}.getSupertype(Number.class).getType());
    assertEquals(new TypeToken<Iterable() {},
        new TypeToken<T>(getClass()) {}.getSupertype(Iterable.class));
  }

  public void testGetSupertype_withoutTypeVariable() {
    ParameterizedType expectedType = Types.newParameterizedType(Iterable.class,
        Types.newParameterizedType(List.class, String.class));
    assertEquals(expectedType,
        TypeToken.of(StringListIterable.class).getSupertype(Iterable.class).getType());
  }

  public void testGetSupertype_chained() {
    @SuppressWarnings("unchecked") // StringListIterable extensd ListIterable<String>
    TypeToken<ListIterable listIterableType = (TypeToken>)
        TypeToken.of(StringListIterable.class).getSupertype(ListIterable.class);
    ParameterizedType expectedType = Types.newParameterizedType(Iterable.class,
        Types.newParameterizedType(List.class, String.class));
    assertEquals(expectedType, listIterableType.getSupertype(Iterable.class).getType());
  }

  public void testGetSupertype_withArray() {
    assertEquals(new TypeToken<Iterable[]>() {},
        TypeToken.of(StringListIterable[].class).getSupertype(Iterable[].class));
    assertEquals(int[].class, TypeToken.of(int[].class).getSupertype(int[].class).getType());
    assertEquals(Object.class, TypeToken.of(int[].class).getSupertype(Object.class).getType());
    assertEquals(int[][].class, TypeToken.of(int[][].class).getSupertype(int[][].class).getType());
    assertEquals(Object[].class,
        TypeToken.of(String[].class).getSupertype(Object[].class).getType());
    assertEquals(Object.class, TypeToken.of(String[].class).getSupertype(Object.class).getType());
  }

  public void testGetSupertype_fromWildcard() {
    @SuppressWarnings("unchecked") // can't do new TypeToken<? extends ...>() {}
    TypeToken<? extends List type = (TypeToken>)
        TypeToken.of(Types.subtypeOf(new TypeToken<List() {}.getType()));
    assertEquals(new TypeToken<Iterable() {}, type.getSupertype(Iterable.class));
  }

  public <T extends Iterable void testGetSupertype_fromTypeVariable() {
    @SuppressWarnings("unchecked") // to construct TypeToken<T> from TypeToken.of()
    TypeToken<T> typeVariableToken = (TypeToken) TypeToken.of(new TypeCapture() {}.capture());
    assertEquals(new TypeToken<Iterable() {},
        typeVariableToken.getSupertype(Iterable.class));
  }

  @SuppressWarnings("rawtypes") // purpose is to test raw type
  public void testGetSupertype_fromRawClass() {
    assertEquals(Types.newParameterizedType(Iterable.class, List.class.getTypeParameters()[0]),
        new TypeToken<List>() {}.getSupertype(Iterable.class).getType());
  }

  @SuppressWarnings({"rawtypes", "unchecked"}) // purpose is to test raw type
  public void testGetSupertype_notSupertype() {
    try {
      new TypeToken<List() {}.getSupertype((Class) String.class);
      fail();
    } catch (IllegalArgumentException expected) {}
  }

  public void testGetSupertype_fromArray() {
    assertEquals(new TypeToken<Iterable() {},
        new TypeToken<List() {}.getSupertype(Iterable[].class));
  }

  private interface ListMap<K, V> extends Map> {}

  public void testGetSupertype_fullyGenericType() {
    ParameterizedType expectedType = Types.newParameterizedType(Map.class,
        ListMap.class.getTypeParameters()[0],
        Types.newParameterizedType(List.class, ListMap.class.getTypeParameters()[1]));
    assertEquals(expectedType,
        TypeToken.of(ListMap.class).getSupertype(Map.class).getType());
  }

  public void testGetSupertype_fullySpecializedType() {
    Type expectedType = new TypeToken<Map>() {}.getType();
    assertEquals(expectedType,
        new TypeToken<ListMap() {}.getSupertype(Map.class).getType());
  }

  private interface StringListMap<V> extends ListMap {}

  public <V> void testGetSupertype_partiallySpecializedType() {
    Type expectedType = new TypeToken<Map>() {}.getType();
    assertEquals(expectedType,
        new TypeToken<StringListMap() {}.getSupertype(Map.class).getType());
  }

  public void testGetSubtype_withTypeVariable() {
    assertEquals(new TypeToken<ListIterable() {},
        new TypeToken<Iterable>() {}.getSubtype(ListIterable.class));
    assertEquals(new TypeToken<ListArrayIterable() {},
        new TypeToken<Iterable>() {}.getSubtype(ListArrayIterable.class));
    assertEquals(new TypeToken<ListArrayIterable() {},
        new TypeToken<Iterable[]>() {}.getSubtype(ListArrayIterable[].class));
  }

  public void testGetSubtype_withoutTypeVariable() {
    assertEquals(StringListIterable.class,
        TypeToken.of(Iterable.class).getSubtype(StringListIterable.class).getType());
    assertEquals(StringListIterable[].class,
        TypeToken.of(Iterable[].class).getSubtype(StringListIterable[].class).getType());
    assertEquals(TypeToken.of(StringListArrayIterable.class),
        new TypeToken<Iterable>() {}.getSubtype(StringListArrayIterable.class));
    assertEquals(TypeToken.of(StringListArrayIterable[].class),
        new TypeToken<Iterable[]>() {}.getSubtype(StringListArrayIterable[].class));
  }

  public void testGetSubtype_withArray() {
    assertEquals(TypeToken.of(StringListIterable[].class),
        TypeToken.of(Iterable[].class).getSubtype(StringListIterable[].class));
    assertEquals(TypeToken.of(String[].class),
        TypeToken.of(Object[].class).getSubtype(String[].class));
    assertEquals(TypeToken.of(int[].class),
        TypeToken.of(Object.class).getSubtype(int[].class));
  }

  public void testGetSubtype_fromWildcard() {
    @SuppressWarnings("unchecked") // can't do new TypeToken<? extends ...>() {}
    TypeToken<? super Iterable type = (TypeToken>)
        TypeToken.of(Types.supertypeOf(new TypeToken<Iterable() {}.getType()));
    assertEquals(new TypeToken<List() {}, type.getSubtype(List.class));
  }

  public void testGetSubtype_fromWildcard_lowerBoundNotSupertype() {
    @SuppressWarnings("unchecked") // can't do new TypeToken<? extends ...>() {}
    TypeToken<? super Iterable type = (TypeToken>)
        TypeToken.of(Types.supertypeOf(new TypeToken<ImmutableList() {}.getType()));
    try {
      type.getSubtype(List.class);
      fail();
    } catch (IllegalArgumentException expected) {}
  }

  public void testGetSubtype_fromWildcard_upperBounded() {
    @SuppressWarnings("unchecked") // can't do new TypeToken<? extends ...>() {}
    TypeToken<? extends Iterable type = (TypeToken>)
        TypeToken.of(Types.subtypeOf(new TypeToken<Iterable() {}.getType()));
    try {
      type.getSubtype(Iterable.class);
      fail();
    } catch (IllegalArgumentException expected) {}
  }

  public <T extends Iterable void testGetSubtype_fromTypeVariable() {
    try {
      TypeToken.of(new TypeCapture<T>() {}.capture()).getSubtype(List.class);
      fail();
    } catch (IllegalArgumentException expected) {}
  }

  @SuppressWarnings("rawtypes") // purpose is to test raw type
  public void testGetSubtype_fromRawClass() {
    assertEquals(List.class, new TypeToken<Iterable>() {}.getSubtype(List.class).getType());
  }

  public void testGetSubtype_fromArray() {
    assertEquals(new TypeToken<List() {},
        new TypeToken<Iterable() {}.getSubtype(List[].class));
  }

  public void testGetSubtype_toWildcard() {
    class TwoTypeArgs<K, V> {}
    class StringForFirstTypeArg<V> extends TwoTypeArgs {}
    TypeToken<TwoTypeArgs supertype =
        new TypeToken<TwoTypeArgs() {};
    TypeToken<StringForFirstTypeArg subtype =
        new TypeToken<StringForFirstTypeArg() {};
    assertTrue(subtype.isSubtypeOf(supertype));
    assertEquals(new TypeToken<StringForFirstTypeArg() {},
        supertype.getSubtype(subtype.getRawType()));
  }

  private static class TwoTypeArgs<K, V> {
    class InnerType<K2, V2> {}
  }

  private static class StringForFirstTypeArg<V> extends TwoTypeArgs {
    class StringInnerType<V2> extends InnerType {}
  }

  public void testGetSubtype_innerTypeOfGenericClassTranslatesOwnerTypeVars() {
    TypeToken<TwoTypeArgs> supertype =
        new TypeToken<TwoTypeArgs>() {};
    TypeToken<StringForFirstTypeArg> subtype =
        new TypeToken<StringForFirstTypeArg>() {};
    assertTrue(subtype.isSubtypeOf(supertype));
    ParameterizedType actualSubtype = (ParameterizedType)
        supertype.getSubtype(subtype.getRawType()).getType();
    assertEquals(StringForFirstTypeArg.StringInnerType.class, actualSubtype.getRawType());
    assertThat(actualSubtype.getActualTypeArguments()[0]).isInstanceOf(WildcardType.class);
    ParameterizedType actualOwnerType = (ParameterizedType) actualSubtype.getOwnerType();
    assertEquals(StringForFirstTypeArg.class, actualOwnerType.getRawType());
  }

  public void testGetSubtype_outerTypeVarTranslatesInnerTypeVar() {
    class TwoTypeArgs<K, V> {}
    class StringForFirstTypeArg<V> extends TwoTypeArgs {}
    class OuterTypeVar<V> extends StringForFirstTypeArg> {}
    TypeToken<StringForFirstTypeArg> type =
        new TypeToken<StringForFirstTypeArg>() {};
    assertEquals(new TypeToken<OuterTypeVar() {},
        type.getSubtype(OuterTypeVar.class));
  }

  public void testGetSubtype_toWildcardWithBounds() {
    class TwoTypeArgs<K, V> {}
    class StringForFirstTypeArg<V> extends TwoTypeArgs {}
    TypeToken<TwoTypeArgs supertype =
        new TypeToken<TwoTypeArgs() {};
    TypeToken<StringForFirstTypeArg subtype =
        new TypeToken<StringForFirstTypeArg() {};
    assertTrue(subtype.isSubtypeOf(supertype));

    // TODO(benyu): This should check equality to an expected value, see discussion in cl/98674873
    TypeToken<?> unused = supertype.getSubtype(subtype.getRawType());
  }

  public void testGetSubtype_baseClassWithNoTypeArgs() {
    class SingleGenericExtendsBase<T> extends Base {}
    TypeToken<Base> supertype = new TypeToken() {};
    TypeToken<SingleGenericExtendsBase subtype =
        new TypeToken<SingleGenericExtendsBase() {};
    assertTrue(subtype.isSubtypeOf(supertype));
    ParameterizedType actualSubtype =
        (ParameterizedType) supertype.getSubtype(subtype.getRawType()).getType();
    assertEquals(SingleGenericExtendsBase.class, actualSubtype.getRawType());
  }

  public void testGetSubtype_baseClassInGenericClassWithNoTypeArgs() {
    class SingleGenericExtendsBase<T> implements GenericClass.Base {}
    TypeToken<GenericClass.Base> supertype = new TypeToken() {};
    TypeToken<SingleGenericExtendsBase subtype =
        new TypeToken<SingleGenericExtendsBase() {};
    assertTrue(subtype.isSubtypeOf(supertype));
    ParameterizedType actualSubtype =
        (ParameterizedType) supertype.getSubtype(subtype.getRawType()).getType();
    assertEquals(SingleGenericExtendsBase.class, actualSubtype.getRawType());
    assertTrue(TypeToken.of(actualSubtype).isSubtypeOf(supertype));
  }

  public void testGetSubtype_genericSubtypeOfNonGenericType() {
    TypeToken<Serializable> supertype = new TypeToken() {};
    TypeToken<ArrayList subtype =
        new TypeToken<ArrayList() {};
    assertTrue(subtype.isSubtypeOf(supertype));
    ParameterizedType actualSubtype =
        (ParameterizedType) supertype.getSubtype(subtype.getRawType()).getType();
    assertEquals(ArrayList.class, actualSubtype.getRawType());
    assertThat(actualSubtype.getActualTypeArguments()[0]).isInstanceOf(TypeVariable.class);
    assertTrue(TypeToken.of(actualSubtype).isSubtypeOf(supertype));
  }

  private interface MySpecialList<E, F> extends List {}

  public void testGetSubtype_genericSubtypeOfGenericTypeWithFewerParameters() {
    TypeToken<List supertype = new TypeToken>() {};
    TypeToken<MySpecialList subtype =
        new TypeToken<MySpecialList() {};
    assertTrue(subtype.isSubtypeOf(supertype));
    ParameterizedType actualSubtype =
        (ParameterizedType) supertype.getSubtype(subtype.getRawType()).getType();
    assertEquals(MySpecialList.class, actualSubtype.getRawType());
    assertThat(actualSubtype.getActualTypeArguments()[0]).isEqualTo(String.class);
    assertThat(actualSubtype.getActualTypeArguments()[1]).isInstanceOf(TypeVariable.class);
    assertTrue(TypeToken.of(actualSubtype).isSubtypeOf(supertype));
  }

  public void testGetSubtype_genericSubtypeOfRawTypeWithFewerTypeParameters() {
    TypeToken<List> supertype = new TypeToken() {};
    TypeToken<MySpecialList> subtype = new TypeToken() {};
    assertTrue(subtype.isSubtypeOf(supertype));
    Class<?> actualSubtype =
        (Class<?>) supertype.getSubtype(subtype.getRawType()).getType();
    assertEquals(MySpecialList.class, actualSubtype);
    assertTrue(TypeToken.of(actualSubtype).isSubtypeOf(supertype));
  }

  public void testGetSubtype_baseClassWithLessTypeArgs() {
    class SingleGenericExtendsBase<T> extends Base {}
    class DoubleGenericExtendsSingleGeneric<T1, TUnused> extends SingleGenericExtendsBase {}
    TypeToken<SingleGenericExtendsBase supertype =
        new TypeToken<SingleGenericExtendsBase() {};
    TypeToken<DoubleGenericExtendsSingleGeneric subtype =
        new TypeToken<DoubleGenericExtendsSingleGeneric() {};
    assertTrue(subtype.isSubtypeOf(supertype));
    ParameterizedType actualSubtype = (ParameterizedType)
        supertype.getSubtype(subtype.getRawType()).getType();
    assertEquals(DoubleGenericExtendsSingleGeneric.class, actualSubtype.getRawType());
    assertThat(actualSubtype.getActualTypeArguments()[0]).isInstanceOf(WildcardType.class);
  }

  public <T> void testGetSubtype_manyGenericArgs() {
    class FourTypeArgs<T1, T2, T3, T4> {}
    class ThreeTypeArgs<T1, T2, T3> extends FourTypeArgs {}
    TypeToken<FourTypeArgs supertype =
        new TypeToken<FourTypeArgs() {};
    TypeToken<ThreeTypeArgs subtype =
        new TypeToken<ThreeTypeArgs() {};
    assertTrue(subtype.isSubtypeOf(supertype));
    assertEquals(new TypeToken<ThreeTypeArgs() {},
        supertype.getSubtype(subtype.getRawType()));
  }

  public void testGetSubtype_recursiveTypeBoundInSubtypeTranslatedAsIs() {
    class BaseWithTypeVar<T> {}
    class Outer<O> {
      class Sub<X> extends BaseWithTypeVar> {}
      class Sub2<Y extends Sub2 extends BaseWithTypeVar> {}
    }
    ParameterizedType subtype = (ParameterizedType) new TypeToken<BaseWithTypeVar>() {}
            .getSubtype(Outer.Sub.class)
            .getType();
    assertEquals(Outer.Sub.class, subtype.getRawType());
    assertThat(subtype.getActualTypeArguments()[0]).isInstanceOf(WildcardType.class);
    ParameterizedType owner = (ParameterizedType) subtype.getOwnerType();
    assertEquals(Outer.class, owner.getRawType());
    // This returns a strange ? extends Sub2<Y> type, which isn't ideal.
    TypeToken<?> unused = new TypeToken>>() {}.getSubtype(Outer.Sub2.class);
  }

  public void testGetSubtype_subtypeSameAsDeclaringType() throws Exception {
    class Bar<T> {}
    class SubBar<T> extends Bar {
      @SuppressWarnings("unused")
      Bar<T> delegate;

      TypeToken<SubBar fieldTypeAsSubBar() {
        return new TypeToken<SubBar() {};
      }
    }

    Field delegateField = SubBar.class.getDeclaredField("delegate");
    // barType is Bar<T>, a ParameterizedType with no generic arguments specified
    TypeToken<?> barType = TypeToken.of(delegateField.getGenericType());
    assertThat(barType.getSubtype(SubBar.class))
        .isEqualTo(new SubBar<Void>().fieldTypeAsSubBar());
  }

  @SuppressWarnings("unchecked") // To construct TypeToken<T> with TypeToken.of()
  public <T> void testWhere_circleRejected() {
    TypeToken<List type = new TypeToken>() {};
    try {
      type.where(new TypeParameter<T>() {},
          (TypeToken<T>) TypeToken.of(new TypeCapture() {}.capture()));
      fail();
    } catch (IllegalArgumentException expected) {}
  }

  public void testWhere() {
    assertEquals(
        new TypeToken<Map() {},
        mapOf(String.class, Integer.class));
    assertEquals(new TypeToken<int[]>() {}, arrayOf(int.class));
    assertEquals(int[].class, arrayOf(int.class).getRawType());
  }

  @SuppressWarnings("unused") // used by reflection
  private static class Holder<T> {
    T element;
    List<T> list;
    List<T>[] matrix;

    void setList(List<T> list) {
      this.list = list;
    }
  }

  public void testWildcardCaptured_methodParameter_upperBound() throws Exception {
    TypeToken<Holder type = new TypeToken>() {};
    TypeToken<?> parameterType = type.resolveType(
        Holder.class.getDeclaredMethod("setList", List.class).getGenericParameterTypes()[0]);
    assertEquals(List.class, parameterType.getRawType());
    assertFalse(parameterType.getType().toString(),
        parameterType.isSupertypeOf(new TypeToken<List() {}));
  }

  public void testWildcardCaptured_field_upperBound() throws Exception {
    TypeToken<Holder type = new TypeToken>() {};
    TypeToken<?> matrixType = type.resolveType(
        Holder.class.getDeclaredField("matrix").getGenericType());
    assertEquals(List[].class, matrixType.getRawType());
    assertThat(matrixType.getType())
        .isNotEqualTo(new TypeToken<List() {}.getType());
  }

  public void testArrayClassPreserved() {
    assertEquals(int[].class, TypeToken.of(int[].class).getType());
    assertEquals(int[][].class, TypeToken.of(int[][].class).getType());
    assertEquals(String[].class, TypeToken.of(String[].class).getType());
    assertEquals(Integer.class, new TypeToken<Integer>() {}.getType());
    assertEquals(Integer.class, TypeToken.of(Integer.class).getType());
  }

  public void testMethod_getOwnerType() throws NoSuchMethodException {
    Method sizeMethod = List.class.getMethod("size");
    assertEquals(TypeToken.of(List.class),
        TypeToken.of(List.class).method(sizeMethod).getOwnerType());
    assertEquals(new TypeToken<List() {},
        new TypeToken<List() {}.method(sizeMethod).getOwnerType());
  }

  public void testMethod_notDeclaredByType() throws NoSuchMethodException {
    Method sizeMethod = Map.class.getMethod("size");
    try {
      TypeToken.of(List.class).method(sizeMethod);
      fail();
    } catch (IllegalArgumentException expected) {}
  }

  public void testMethod_declaredBySuperclass() throws Exception {
    Method toStringMethod = Object.class.getMethod("toString");
    ImmutableList<String> list = ImmutableList.of("foo");
    assertEquals(list.toString(), TypeToken.of(List.class).method(toStringMethod).invoke(list));
  }

  public <T extends Number & List void testMethod_returnType_resolvedAgainstTypeBound()
      throws NoSuchMethodException {
    Method getMethod = List.class.getMethod("get", int.class);
    Invokable<T, String> invokable = new TypeToken(getClass()) {}
        .method(getMethod)
        .returning(String.class);
    assertEquals(TypeToken.of(String.class), invokable.getReturnType());
  }

  public <T extends List void testMethod_parameterTypes()
      throws NoSuchMethodException {
    Method setMethod = List.class.getMethod("set", int.class, Object.class);
    Invokable<T, ?> invokable = new TypeToken(getClass()) {}.method(setMethod);
    ImmutableList<Parameter> params = invokable.getParameters();
    assertEquals(2, params.size());
    assertEquals(TypeToken.of(int.class), params.get(0).getType());
    assertEquals(TypeToken.of(String.class), params.get(1).getType());
  }

  public void testMethod_equals() throws NoSuchMethodException {
    Method getMethod = List.class.getMethod("get", int.class);
    Method setMethod = List.class.getMethod("set", int.class, Object.class);
    new EqualsTester()
        .addEqualityGroup(Invokable.from(getMethod), Invokable.from(getMethod))
        .addEqualityGroup(Invokable.from(setMethod))
        .addEqualityGroup(new TypeToken<List() {}.method(getMethod))
        .addEqualityGroup(new TypeToken<List() {}.method(getMethod))
        .addEqualityGroup(new TypeToken<List() {}.method(setMethod))
        .addEqualityGroup(new TypeToken<List() {}.method(setMethod))
        .testEquals();
  }

  private interface Loser<E extends Throwable> {
    void lose() throws E;
  }

  public <T extends Loser void testMethod_exceptionTypes()
      throws NoSuchMethodException {
    Method failMethod = Loser.class.getMethod("lose");
    Invokable<T, ?> invokable = new TypeToken(getClass()) {}.method(failMethod);
    assertThat(invokable.getExceptionTypes()).contains(TypeToken.of(AssertionError.class));
  }

  public void testConstructor_getOwnerType() throws NoSuchMethodException {
    @SuppressWarnings("rawtypes") // raw class ArrayList.class
    Constructor<ArrayList> constructor = ArrayList.class.getConstructor();
    assertEquals(TypeToken.of(ArrayList.class),
        TypeToken.of(ArrayList.class).constructor(constructor).getOwnerType());
    assertEquals(new TypeToken<ArrayList() {},
        new TypeToken<ArrayList() {}.constructor(constructor).getOwnerType());
  }

  public void testConstructor_notDeclaredByType() throws NoSuchMethodException {
    Constructor<String> constructor = String.class.getConstructor();
    try {
      TypeToken.of(Object.class).constructor(constructor);
      fail();
    } catch (IllegalArgumentException expected) {}
  }

  public void testConstructor_declaredBySuperclass() throws NoSuchMethodException {
    Constructor<Object> constructor = Object.class.getConstructor();
    try {
      TypeToken.of(String.class).constructor(constructor);
      fail();
    } catch (IllegalArgumentException expected) {}
  }

  public void testConstructor_equals() throws NoSuchMethodException {
    Constructor<?> defaultConstructor = ArrayList.class.getConstructor();
    Constructor<?> oneArgConstructor = ArrayList.class.getConstructor(int.class);
    new EqualsTester()
        .addEqualityGroup(Invokable.from(defaultConstructor), Invokable.from(defaultConstructor))
        .addEqualityGroup(Invokable.from(oneArgConstructor))
        .addEqualityGroup(new TypeToken<ArrayList() {}.constructor(defaultConstructor))
        .addEqualityGroup(new TypeToken<ArrayList() {}.constructor(defaultConstructor))
        .addEqualityGroup(new TypeToken<ArrayList() {}.constructor(oneArgConstructor))
        .addEqualityGroup(new TypeToken<ArrayList() {}.constructor(oneArgConstructor))
        .testEquals();
  }

  private static class Container<T> {
    @SuppressWarnings("unused")
    public Container(T data) {}
  }

  public <T extends Container void testConstructor_parameterTypes()
      throws NoSuchMethodException {
    @SuppressWarnings("rawtypes") // Reflection API skew
    Constructor<Container> constructor = Container.class.getConstructor(Object.class);
    Invokable<T, ?> invokable = new TypeToken(getClass()) {}.constructor(constructor);
    ImmutableList<Parameter> params = invokable.getParameters();
    assertEquals(1, params.size());
    assertEquals(TypeToken.of(String.class), params.get(0).getType());
  }

  private static class CannotConstruct<E extends Throwable> {
    @SuppressWarnings("unused")
    public CannotConstruct() throws E {}
  }

  public <T extends CannotConstruct void testConstructor_exceptionTypes()
      throws NoSuchMethodException {
    @SuppressWarnings("rawtypes") // Reflection API skew
    Constructor<CannotConstruct> constructor = CannotConstruct.class.getConstructor();
    Invokable<T, ?> invokable = new TypeToken(getClass()) {}.constructor(constructor);
    assertThat(invokable.getExceptionTypes()).contains(TypeToken.of(AssertionError.class));
  }

  public void testRejectTypeVariable_class() {
    assertNoTypeVariable(String.class);
    assertNoTypeVariable(String[].class);
    assertNoTypeVariable(int[].class);
  }

  public void testRejectTypeVariable_parameterizedType() {
    assertNoTypeVariable(new TypeCapture<Iterable() {}.capture());
  }

  public void testRejectTypeVariable_wildcardType() {
    assertNoTypeVariable(
        new TypeCapture<Iterable() {}.capture());
    assertNoTypeVariable(
        new TypeCapture<Iterable() {}.capture());
  }

  public void testRejectTypeVariable_genericArrayType() {
    assertNoTypeVariable(
        new TypeCapture<Iterable() {}.capture());
  }

  public <T> void testRejectTypeVariable_withTypeVariable() {
    assertHasTypeVariable(new TypeCapture<T>() {}.capture());
    assertHasTypeVariable(new TypeCapture<T[]>() {}.capture());
    assertHasTypeVariable(new TypeCapture<Iterable() {}.capture());
    assertHasTypeVariable(new TypeCapture<Map() {}.capture());
    assertHasTypeVariable(
        new TypeCapture<Map() {}.capture());
    assertHasTypeVariable(
        new TypeCapture<Map() {}.capture());
  }

  private static class From<K> {
    class To<V> {
      Type type() {
        return new TypeToken<To(getClass()) {}.getType();
      }
    }
  }

  public <T> void testRejectTypeVariable_withOwnerType() {
    // Neither has subclass
    assertHasTypeVariable(new From<Integer>().new To().type());
    assertHasTypeVariable(new From<T>().new To().type());
    assertHasTypeVariable(new From<Integer>().new To().type());

    // Owner is subclassed
    assertHasTypeVariable(new From<Integer>() {}.new To().type());
    assertHasTypeVariable(new From<T>() {}.new To().type());

    // Inner is subclassed
    assertNoTypeVariable(new From<Integer>().new To() {}.type());
    assertHasTypeVariable(new From<Integer>().new To() {}.type());
    assertHasTypeVariable(new From<T>().new To() {}.type());

    // both subclassed
    assertHasTypeVariable(new From<T>() {}.new To() {}.type());
    assertNoTypeVariable(new From<Integer>() {}.new To() {}.type());
    assertHasTypeVariable(new From<Integer>() {}.new To() {}.type());
  }

  private static void assertHasTypeVariable(Type type) {
    try {
      TypeToken.of(type).rejectTypeVariables();
      fail("Should contain TypeVariable");
    } catch (IllegalArgumentException expected) {}
  }

  private static void assertNoTypeVariable(Type type) {
    TypeToken.of(type).rejectTypeVariables();
  }

  private abstract static class RawTypeConsistencyTester<T extends Enum {
    abstract T returningT();
    abstract void acceptT(T t);
    abstract <X extends T> X returningX();
    abstract <X> void acceptX(X x);
    abstract <T2 extends Enum T2 returningT2();
    abstract <T2 extends CharSequence&Iterable void acceptT2(T2 t2);

    static void verifyConsitentRawType() {
      for (Method method : RawTypeConsistencyTester.class.getDeclaredMethods()) {
        assertEquals(method.getReturnType(),
            TypeToken.of(method.getGenericReturnType()).getRawType());
        for (int i = 0; i < method.getParameterTypes().length; i++) {
          assertEquals(method.getParameterTypes()[i],
              TypeToken.of(method.getGenericParameterTypes()[i]).getRawType());
        }
      }
    }
  }

  public void testRawTypes() {
    RawTypeConsistencyTester.verifyConsitentRawType();
    assertEquals(Object.class, TypeToken.of(Types.subtypeOf(Object.class)).getRawType());
    assertEquals(CharSequence.class,
        TypeToken.of(Types.subtypeOf(CharSequence.class)).getRawType());
    assertEquals(Object.class, TypeToken.of(Types.supertypeOf(CharSequence.class)).getRawType());
  }

  private abstract static class IKnowMyType<T> {
    TypeToken<T> type() {
      return new TypeToken<T>(getClass()) {};
    }
  }

  public void testTypeResolution() {
    assertEquals(String.class,
        new IKnowMyType<String>() {}.type().getType());
    assertEquals(new TypeToken<Map() {},
        new IKnowMyType<Map() {}.type());
  }

  public <A extends Iterable void testSerializable() {
    reserialize(TypeToken.of(String.class));
    reserialize(TypeToken.of(String.class).getTypes());
    reserialize(TypeToken.of(String.class).getTypes().classes());
    reserialize(TypeToken.of(String.class).getTypes().interfaces());
    reserialize(TypeToken.of(String.class).getTypes().rawTypes());
    reserialize(TypeToken.of(String.class).getTypes().classes().rawTypes());
    reserialize(TypeToken.of(String.class).getTypes().interfaces().rawTypes());
    reserialize(new TypeToken<int[]>() {});
    reserialize(new TypeToken<Map() {});
    reserialize(new IKnowMyType<Map() {}.type());
    reserialize(TypeToken.of(new TypeCapture<B>() {}.capture()).getTypes().rawTypes());
    try {
      SerializableTester.reserialize(TypeToken.of(new TypeCapture<B>() {}.capture()));
      fail();
    } catch (RuntimeException expected) {}
  }

  public <A> void testSerializable_typeVariableNotSupported() {
    try {
      new ITryToSerializeMyTypeVariable<String>().go();
      fail();
    } catch (RuntimeException expected) {}
  }

  private static class ITryToSerializeMyTypeVariable<T> {
    void go() {
      SerializableTester.reserialize(TypeToken.of(new TypeCapture<T>() {}.capture()));
    }
  }

  @CanIgnoreReturnValue
  private static <T> T reserialize(T object) {
    T copy = SerializableTester.reserialize(object);
    new EqualsTester()
        .addEqualityGroup(object, copy)
        .testEquals();
    return copy;
  }

  public void testTypeResolutionAfterReserialized() {
    reserialize(new TypeToken<String>() {});
    reserialize(new TypeToken<Map() {});
    TypeToken<Map reserialized = reserialize(
        new TypeToken<Map() {});
    assertEquals(reserialized, substitute(reserialized, String.class));
  }

  private static <T, X> TypeToken substitute(TypeToken type, Class arg) {
    return type.where(new TypeParameter<X>() {}, arg);
  }

  private abstract static class ToReproduceGenericSignatureFormatError<V> {
    private abstract class BaseOuter {
      abstract class BaseInner {}
    }
    private abstract class SubOuter extends BaseOuter {
      private abstract class SubInner extends BaseInner {}
    }
  }

  // For Guava bug http://code.google.com/p/guava-libraries/issues/detail?id=1025
  public void testDespiteGenericSignatureFormatError() {
    ImmutableSet<?> unused =
        ImmutableSet.copyOf(
            TypeToken.of(ToReproduceGenericSignatureFormatError.SubOuter.SubInner.class)
                .getTypes()
                .rawTypes());
  }

  private abstract static class Entry<K, V> {
    TypeToken<K> keyType() {
      return new TypeToken<K>(getClass()) {};
    }
    TypeToken<V> valueType() {
      return new TypeToken<V>(getClass()) {};
    }
  }

  // The A and B type parameters are used inside the test to test type variable
  public <A, B> void testEquals() {
    new EqualsTester()
        .addEqualityGroup(
            TypeToken.of(String.class),
            TypeToken.of(String.class),
            new Entry<String, Integer>() {}.keyType(),
            new Entry<Integer, String>() {}.valueType(),
            new TypeToken<String>() {},
            new TypeToken<String>() {})
        .addEqualityGroup(
            TypeToken.of(Integer.class),
            new TypeToken<Integer>() {},
            new Entry<Integer, String>() {}.keyType(),
            new Entry<String, Integer>() {}.valueType())
        .addEqualityGroup(
            new TypeToken<List() {},
            new TypeToken<List() {})
        .addEqualityGroup(
            new TypeToken<List() {},
            new TypeToken<List() {})
        .addEqualityGroup(
            new TypeToken<Map() {},
            new TypeToken<Map() {})
        .addEqualityGroup(
            new TypeToken<Map() {})
        .addEqualityGroup(
            TypeToken.of(new TypeCapture<A>() {}.capture()),
            TypeToken.of(new TypeCapture<A>() {}.capture()))
        .addEqualityGroup(TypeToken.of(new TypeCapture<B>() {}.capture()))
        .testEquals();
  }

  // T is used inside to test type variable
  public <T> void testToString() {
    assertEquals(String.class.getName(), new TypeToken<String>() {}.toString());
    assertEquals("T", TypeToken.of(new TypeCapture<T>() {}.capture()).toString());
    assertEquals("java.lang.String", new Entry<String, Integer>() {}.keyType().toString());
  }

  private static <K, V> TypeToken> mapOf(Class keyType, Class valueType) {
    return new TypeToken<Map() {}
        .where(new TypeParameter<K>() {}, keyType)
        .where(new TypeParameter<V>() {}, valueType);
  }

  private static <T> TypeToken arrayOf(Class componentType) {
    return new TypeToken<T[]>() {}
        .where(new TypeParameter<T>() {}, componentType);
  }

  public <T> void testNulls() {
    new NullPointerTester()
        .testAllPublicStaticMethods(TypeToken.class);
    new NullPointerTester()
        .setDefault(TypeParameter.class, new TypeParameter<T>() {})
        .testAllPublicInstanceMethods(TypeToken.of(String.class));
  }

  private static class Assignability<From, To> {

    boolean isAssignable() {
      return new TypeToken<To>(getClass()) {}.isSupertypeOf(new TypeToken(getClass()) {});
    }

    static <From, To> Assignability of() {
      return new Assignability<From, To>();
    }
  }

  private static void assertAssignable(TypeToken<?> from, TypeToken to) {
    assertTrue(
        from.getType() + " is expected to be assignable to " + to.getType(),
        to.isSupertypeOf(from));
    assertTrue(
        to.getType() + " is expected to be a supertype of " + from.getType(),
        to.isSupertypeOf(from));
    assertTrue(
        from.getType() + " is expected to be a subtype of " + to.getType(),
        from.isSubtypeOf(to));
  }

  private static void assertNotAssignable(TypeToken<?> from, TypeToken to) {
    assertFalse(
        from.getType() + " shouldn't be assignable to " + to.getType(),
        to.isSupertypeOf(from));
    assertFalse(
        to.getType() + " shouldn't be a supertype of " + from.getType(),
        to.isSupertypeOf(from));
    assertFalse(
        from.getType() + " shouldn't be a subtype of " + to.getType(),
        from.isSubtypeOf(to));
  }

  private static void assertHasArrayInterfaces(TypeToken<?> arrayType) {
    assertEquals(arrayInterfaces(), ImmutableSet.copyOf(arrayType.getGenericInterfaces()));
  }

  private static ImmutableSet<TypeToken arrayInterfaces() {
    ImmutableSet.Builder<TypeToken builder = ImmutableSet.builder();
    for (Class<?> interfaceType : Object[].class.getInterfaces()) {
      builder.add(TypeToken.of(interfaceType));
    }
    return builder.build();
  }

  private static void assertIsPrimitive(TypeToken<?> type) {
    assertTrue(type.isPrimitive());
    assertNotWrapper(type);
    assertEquals(TypeToken.of(Primitives.wrap((Class<?>) type.getType())), type.wrap());
  }

  private static void assertNotPrimitive(TypeToken<?> type) {
    assertFalse(type.isPrimitive());
    assertSame(type, type.wrap());
  }

  private static void assertIsWrapper(TypeToken<?> type) {
    assertNotPrimitive(type);
    assertEquals(TypeToken.of(Primitives.unwrap((Class<?>) type.getType())), type.unwrap());
  }

  private static void assertNotWrapper(TypeToken<?> type) {
    assertSame(type, type.unwrap());
  }

  private static void assertNotPrimitiveNorWrapper(TypeToken<?> type) {
    assertNotPrimitive(type);
    assertNotWrapper(type);
  }

  private interface BaseInterface {}
  private static class Base implements BaseInterface {}
  private static class Sub extends Base {}
  private static class GenericClass<T> {
    private static interface Base {}
  }

  private static IterableSubject makeUnmodifiable(Collection<?> actual) {
    return assertThat(Collections.<Object>unmodifiableCollection(actual));
  }
}


... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.