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

Java example source code file (TypeTokenResolutionTest.java)

This example Java source code file (TypeTokenResolutionTest.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

class, exception, foo, inner, list, mapping, parameterizedtype, red, reflection, string, suppresswarnings, type, typetoken, typevariable, util, withgenericbound

The TypeTokenResolutionTest.java Java example source code

/*
 * Copyright (C) 2009 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.Predicate;
import com.google.common.base.Supplier;

import junit.framework.TestCase;

import java.lang.reflect.GenericArrayType;
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.List;
import java.util.Map;

/**
 * Unit test for {@link TypeToken} and {@link TypeResolver}.
 *
 * @author Ben Yu
 */
@AndroidIncompatible // lots of failures, possibly some related to bad equals() implementations?
public class TypeTokenResolutionTest extends TestCase {

  private static class Foo<A, B> {

    Class<? super A> getClassA() {
      return new TypeToken<A>(getClass()) {}.getRawType();
    }

    Class<? super B> getClassB() {
      return new TypeToken<B>(getClass()) {}.getRawType();
    }

    Class<? super A[]> getArrayClassA() {
      return new TypeToken<A[]>(getClass()) {}.getRawType();
    }

    Type getArrayTypeA() {
      return new TypeToken<A[]>(getClass()) {}.getType();
    }

    Class<? super B[]> getArrayClassB() {
      return new TypeToken<B[]>(getClass()) {}.getRawType();
    }
  }

  public void testSimpleTypeToken() {
    Foo<String, Integer> foo = new Foo() {};
    assertEquals(String.class, foo.getClassA());
    assertEquals(Integer.class, foo.getClassB());
    assertEquals(String[].class, foo.getArrayClassA());
    assertEquals(Integer[].class, foo.getArrayClassB());
  }

  public void testCompositeTypeToken() {
    Foo<String[], List foo = new Foo>() {};
    assertEquals(String[].class, foo.getClassA());
    assertEquals(List.class, foo.getClassB());
    assertEquals(String[][].class, foo.getArrayClassA());
    assertEquals(List[].class, foo.getArrayClassB());
  }

  private static class StringFoo<T> extends Foo {}

  public void testPartialSpecialization() {
    StringFoo<Integer> foo = new StringFoo() {};
    assertEquals(String.class, foo.getClassA());
    assertEquals(Integer.class, foo.getClassB());
    assertEquals(String[].class, foo.getArrayClassA());
    assertEquals(Integer[].class, foo.getArrayClassB());
    assertEquals(new TypeToken<String[]>() {}.getType(), foo.getArrayTypeA());
  }

  public void testTypeArgNotFound() {
    StringFoo<Integer> foo = new StringFoo();
    assertEquals(String.class, foo.getClassA());
    assertEquals(String[].class, foo.getArrayClassA());
    assertEquals(Object.class, foo.getClassB());
    assertEquals(Object[].class, foo.getArrayClassB());
  }

  private static abstract class Bar<T> {}

  private abstract static class Parameterized<O, T, P> {
    ParameterizedType parameterizedType() {
      return new ParameterizedType() {
        @Override public Type[] getActualTypeArguments() {
          return new Type[]{new TypeCapture<P>() {}.capture()};
        }
        @Override public Type getOwnerType() {
          return new TypeCapture<O>() {}.capture();
        }
        @Override public Type getRawType() {
          return new TypeCapture<T>() {}.capture();
        }
      };
    }
  }

  public void testResolveType_parameterizedType() {
    @SuppressWarnings("rawtypes") // trying to test raw type
    Parameterized<?, ?, ?> parameterized =
        new Parameterized<TypeTokenResolutionTest, Bar, String>() {};
    TypeResolver typeResolver = TypeResolver.accordingTo(parameterized.getClass());
    ParameterizedType resolved = (ParameterizedType) typeResolver.resolveType(
        parameterized.parameterizedType());
    assertEquals(TypeTokenResolutionTest.class, resolved.getOwnerType());
    assertEquals(Bar.class, resolved.getRawType());
    assertThat(resolved.getActualTypeArguments()).asList().contains(String.class);
  }
  private interface StringListPredicate extends Predicate<List {}

  private interface IntegerSupplier extends Supplier<Integer> {}

  // Intentionally duplicate the Predicate interface to test that it won't cause
  // exceptions
  private interface IntegerStringFunction extends IntegerSupplier,
      Predicate<List, StringListPredicate {}

  public void testGenericInterface() {
    // test the 1st generic interface on the class
    Type fType = Supplier.class.getTypeParameters()[0];
    assertEquals(Integer.class,
        TypeToken.of(IntegerStringFunction.class).resolveType(fType)
            .getRawType());

    // test the 2nd generic interface on the class
    Type predicateParameterType = Predicate.class.getTypeParameters()[0];
    assertEquals(new TypeToken<List() {}.getType(),
        TypeToken.of(IntegerStringFunction.class).resolveType(predicateParameterType)
            .getType());
  }

  private static abstract class StringIntegerFoo extends Foo<String, Integer> {}

  public void testConstructor_typeArgsResolvedFromAncestorClass() {
    assertEquals(String.class, new StringIntegerFoo() {}.getClassA());
    assertEquals(Integer.class, new StringIntegerFoo() {}.getClassB());
  }

  private static class Owner<T> {
    private static abstract class Nested<X> {
      Class<? super X> getTypeArgument() {
        return new TypeToken<X>(getClass()) {}.getRawType();
      }
    }

    private abstract class Inner<Y> extends Nested {
      Class<? super T> getOwnerType() {
        return new TypeToken<T>(getClass()) {}.getRawType();
      }
    }
  }

  public void testResolveNestedClass() {
    assertEquals(String.class, new Owner.Nested<String>() {}.getTypeArgument());
  }

  public void testResolveInnerClass() {
    assertEquals(String.class,
        new Owner<Integer>().new Inner() {}.getTypeArgument());
  }

  public void testResolveOwnerClass() {
    assertEquals(Integer.class,
        new Owner<Integer>().new Inner() {}.getOwnerType());
  }

  private static class Mapping<F, T> {

    final Type f = new TypeToken<F>(getClass()) {}.getType();
    final Type t = new TypeToken<T>(getClass()) {}.getType();

    Type getFromType() {
      return new TypeToken<F>(getClass()) {}.getType();
    }

    Type getToType() {
      return new TypeToken<T>(getClass()) {}.getType();
    }

    Mapping<T, F> flip() {
      return new Mapping<T, F>() {};
    }

    Mapping<F, T> selfMapping() {
      return new Mapping<F, T>() {};
    }
  }

  public void testCyclicMapping() {
    Mapping<Integer, String> mapping = new Mapping();
    assertEquals(mapping.f, mapping.getFromType());
    assertEquals(mapping.t, mapping.getToType());
    assertEquals(mapping.f, mapping.flip().getFromType());
    assertEquals(mapping.t, mapping.flip().getToType());
    assertEquals(mapping.f, mapping.selfMapping().getFromType());
    assertEquals(mapping.t, mapping.selfMapping().getToType());
  }

  private static class ParameterizedOuter<T> {

    @SuppressWarnings("unused") // used by reflection
    public Inner field;

    class Inner {}
  }

  public void testInnerClassWithParameterizedOwner() throws Exception {
    Type fieldType = ParameterizedOuter.class.getField("field")
        .getGenericType();
    assertEquals(fieldType,
        TypeToken.of(ParameterizedOuter.class).resolveType(fieldType).getType());
  }

  private interface StringIterable extends Iterable<String> {}

  public void testResolveType() {
    assertEquals(String.class, TypeToken.of(this.getClass()).resolveType(String.class).getType());
    assertEquals(String.class,
        TypeToken.of(StringIterable.class)
            .resolveType(Iterable.class.getTypeParameters()[0]).getType());
    assertEquals(String.class,
        TypeToken.of(StringIterable.class)
            .resolveType(Iterable.class.getTypeParameters()[0]).getType());
    try {
      TypeToken.of(this.getClass()).resolveType(null);
      fail();
    } catch (NullPointerException expected) {}
  }

  public void testConextIsParameterizedType() throws Exception {
    class Context {
      @SuppressWarnings("unused") // used by reflection
      Map<String, Integer> returningMap() {
        throw new AssertionError();
      }
    }
    Type context = Context.class.getDeclaredMethod("returningMap")
        .getGenericReturnType();
    Type keyType = Map.class.getTypeParameters()[0];
    Type valueType = Map.class.getTypeParameters()[1];

    // context is parameterized type
    assertEquals(String.class, TypeToken.of(context).resolveType(keyType).getType());
    assertEquals(Integer.class,
        TypeToken.of(context).resolveType(valueType).getType());

    // context is type variable
    assertEquals(keyType, TypeToken.of(keyType).resolveType(keyType).getType());
    assertEquals(valueType, TypeToken.of(valueType).resolveType(valueType).getType());
  }

  private static final class GenericArray<T> {
    final Type t = new TypeToken<T>(getClass()) {}.getType();
    final Type array = new TypeToken<T[]>(getClass()) {}.getType();
  }

  public void testGenericArrayType() {
    GenericArray<?> genericArray = new GenericArray();
    assertEquals(GenericArray.class.getTypeParameters()[0], genericArray.t);
    assertEquals(Types.newArrayType(genericArray.t),
        genericArray.array);
  }

  public void testClassWrapper() {
    TypeToken<String> typeExpression = TypeToken.of(String.class);
    assertEquals(String.class, typeExpression.getType());
    assertEquals(String.class, typeExpression.getRawType());
  }

  private static class Red<A> {
    private class Orange {
      Class<?> getClassA() {
        return new TypeToken<A>(getClass()) {}.getRawType();
      }

      Red<A> getSelfB() {
        return Red.this;
      }
    }

    Red<A> getSelfA() {
      return this;
    }

    private class Yellow<B> extends Red.Orange {
      Yellow(Red<B> red) {
        red.super();
      }

      Class<?> getClassB() {
        return new TypeToken<B>(getClass()) {}.getRawType();
      }

      Red<A> getA() {
        return getSelfA();
      }

      Red<B> getB() {
        return getSelfB();
      }
    }

    Class<?> getClassDirect() {
      return new TypeToken<A>(getClass()) {}.getRawType();
    }
  }

  public void test1() {
    Red<String> redString = new Red() {};
    Red<Integer> redInteger = new Red() {};
    assertEquals(String.class, redString.getClassDirect());
    assertEquals(Integer.class, redInteger.getClassDirect());

    Red<String>.Yellow yellowInteger =
        redString.new Yellow<Integer>(redInteger) {};
    assertEquals(Integer.class, yellowInteger.getClassA());
    assertEquals(Integer.class, yellowInteger.getClassB());
    assertEquals(String.class, yellowInteger.getA().getClassDirect());
    assertEquals(Integer.class, yellowInteger.getB().getClassDirect());
  }

  public void test2() {
    Red<String> redString = new Red();
    Red<Integer> redInteger = new Red();
    Red<String>.Yellow yellowInteger =
        redString.new Yellow<Integer>(redInteger) {};
    assertEquals(Integer.class, yellowInteger.getClassA());
    assertEquals(Integer.class, yellowInteger.getClassB());
  }

  private static <T> Type staticMethodWithLocalClass() {
    class MyLocalClass {
      Type getType() {
        return new TypeToken<T>(getClass()) {}.getType();
      }
    }
    return new MyLocalClass().getType();
  }

  public void testLocalClassInsideStaticMethod() {
    assertNotNull(staticMethodWithLocalClass());
  }

  public void testLocalClassInsideNonStaticMethod() {
    class MyLocalClass<T> {
      Type getType() {
        return new TypeToken<T>(getClass()) {}.getType();
      }
    }
    assertNotNull(new MyLocalClass<String>().getType());
  }

  private static <T> Type staticMethodWithAnonymousClass() {
    return new Object() {
      Type getType() {
        return new TypeToken<T>(getClass()) {}.getType();
      }
    }.getType();
  }

  public void testAnonymousClassInsideStaticMethod() {
    assertNotNull(staticMethodWithAnonymousClass());
  }

  public void testAnonymousClassInsideNonStaticMethod() {
    assertNotNull(new Object() {
      Type getType() {
        return new TypeToken<Object>() {}.getType();
      }
    }.getType());
  }

  public void testStaticContext() {
    assertEquals(Map.class, mapType().getRawType());
  }

  private abstract static class Holder<T> {
    Type getContentType() {
      return new TypeToken<T>(getClass()) {}.getType();
    }
  }

  public void testResolvePrimitiveArrayType() {
    assertEquals(new TypeToken<int[]>() {}.getType(),
        new Holder<int[]>() {}.getContentType());
    assertEquals(new TypeToken<int[][]> () {}.getType(),
        new Holder<int[][]>() {}.getContentType());
  }

  public void testResolveToGenericArrayType() {
    GenericArrayType arrayType = (GenericArrayType)
        new Holder<List() {}.getContentType();
    ParameterizedType listType = (ParameterizedType)
        arrayType.getGenericComponentType();
    assertEquals(List.class, listType.getRawType());
    assertEquals(Types.newArrayType(int[].class),
        listType.getActualTypeArguments()[0]);
  }

  private abstract class WithGenericBound<A> {

    @SuppressWarnings("unused")
    public <B extends A> void withTypeVariable(List list) {}

    @SuppressWarnings("unused")
    public <E extends Enum void withRecursiveBound(List list) {}

    @SuppressWarnings("unused")
    public <K extends List> void withMutualRecursiveBound(
        List<Map list) {}

    @SuppressWarnings("unused")
    void withWildcardLowerBound(List<? super A> list) {}

    @SuppressWarnings("unused")
    void withWildcardUpperBound(List<? extends A> list) {}

    Type getTargetType(String methodName) throws Exception {
      ParameterizedType parameterType = (ParameterizedType)
          WithGenericBound.class.getDeclaredMethod(methodName, List.class)
              .getGenericParameterTypes()[0];
      parameterType = (ParameterizedType)
          TypeToken.of(this.getClass()).resolveType(parameterType).getType();
      return parameterType.getActualTypeArguments()[0];
    }
  }

  public void testWithGenericBoundInTypeVariable() throws Exception {
    TypeVariable<?> typeVariable = (TypeVariable)
        new WithGenericBound<String>() {}.getTargetType("withTypeVariable");
    assertEquals(String.class, typeVariable.getBounds()[0]);
  }

  public void testWithRecursiveBoundInTypeVariable() throws Exception {
    TypeVariable<?> typeVariable = (TypeVariable)
        new WithGenericBound<String>() {}.getTargetType("withRecursiveBound");
    assertEquals(Types.newParameterizedType(Enum.class, typeVariable),
        typeVariable.getBounds()[0]);
  }

  public void testWithMutualRecursiveBoundInTypeVariable() throws Exception {
    ParameterizedType paramType = (ParameterizedType)
        new WithGenericBound<String>() {}
            .getTargetType("withMutualRecursiveBound");
    TypeVariable<?> k = (TypeVariable) paramType.getActualTypeArguments()[0];
    TypeVariable<?> v = (TypeVariable) paramType.getActualTypeArguments()[1];
    assertEquals(Types.newParameterizedType(List.class, v), k.getBounds()[0]);
    assertEquals(Types.newParameterizedType(List.class, k), v.getBounds()[0]);
  }

  public void testWithGenericLowerBoundInWildcard() throws Exception {
    WildcardType wildcardType = (WildcardType)
        new WithGenericBound<String>() {}
            .getTargetType("withWildcardLowerBound");
    assertEquals(String.class, wildcardType.getLowerBounds()[0]);
  }

  public void testWithGenericUpperBoundInWildcard() throws Exception {
    WildcardType wildcardType = (WildcardType)
        new WithGenericBound<String>() {}
            .getTargetType("withWildcardUpperBound");
    assertEquals(String.class, wildcardType.getUpperBounds()[0]);
  }

  public void testInterfaceTypeParameterResolution() throws Exception {
    assertEquals(String.class,
        TypeToken.of(new TypeToken<ArrayList() {}.getType())
            .resolveType(List.class.getTypeParameters()[0]).getType());
  }

  private static TypeToken<Map mapType() {
    return new TypeToken<Map() {};
  }

  // Looks like recursive, but legit.
  private interface WithFalseRecursiveType<K, V> {
    WithFalseRecursiveType<List keyShouldNotResolveToStringList();
    WithFalseRecursiveType<List> shouldNotCauseInfiniteLoop();
    SubtypeOfWithFalseRecursiveType<List> evenSubtypeWorks();
  }

  private interface SubtypeOfWithFalseRecursiveType<K1, V1>
      extends WithFalseRecursiveType<List> {
    SubtypeOfWithFalseRecursiveType<V1, K1> revertKeyAndValueTypes();
  }

  public void testFalseRecursiveType_mappingOnTheSameDeclarationNotUsed() {
    Type returnType = genericReturnType(
        WithFalseRecursiveType.class, "keyShouldNotResolveToStringList");
    TypeToken<?> keyType = TypeToken.of(returnType)
        .resolveType(WithFalseRecursiveType.class.getTypeParameters()[0]);
    assertEquals("java.util.List<V>", keyType.getType().toString());
  }

  public void testFalseRecursiveType_notRealRecursiveMapping() {
    Type returnType = genericReturnType(
        WithFalseRecursiveType.class, "shouldNotCauseInfiniteLoop");
    TypeToken<?> keyType = TypeToken.of(returnType)
        .resolveType(WithFalseRecursiveType.class.getTypeParameters()[0]);
    assertEquals("java.util.List<K>", keyType.getType().toString());
  }

  public void testFalseRecursiveType_referenceOfSubtypeDoesNotConfuseMe() {
    Type returnType = genericReturnType(
        WithFalseRecursiveType.class, "evenSubtypeWorks");
    TypeToken<?> keyType = TypeToken.of(returnType)
        .resolveType(WithFalseRecursiveType.class.getTypeParameters()[0]);
    assertEquals("java.util.List<java.util.List", keyType.getType().toString());
  }

  public void testFalseRecursiveType_intermediaryTypeMappingDoesNotConfuseMe() {
    Type returnType = genericReturnType(
        SubtypeOfWithFalseRecursiveType.class, "revertKeyAndValueTypes");
    TypeToken<?> keyType = TypeToken.of(returnType)
        .resolveType(WithFalseRecursiveType.class.getTypeParameters()[0]);
    assertEquals("java.util.List<K1>", keyType.getType().toString());
  }

  private static Type genericReturnType(Class<?> cls, String methodName) {
    try {
      return cls.getMethod(methodName).getGenericReturnType();
    } catch (Exception e) {
      throw new RuntimeException(e);
    }
  }

  public void testTwoStageResolution() {
    class ForTwoStageResolution<A extends Number> {
      <B extends A> void verifyTwoStageResolution() {
        @SuppressWarnings({"unchecked", "rawtypes"})
        Type type = new TypeToken<B>(getClass()) {}
            // B's bound may have already resolved to something.
            // Make sure it can still further resolve when given a context.
            .where(new TypeParameter<B>() {}, (Class) Integer.class)
            .getType();
        assertEquals(Integer.class, type);
      }
    }
    new ForTwoStageResolution<Integer>().verifyTwoStageResolution();
    new ForTwoStageResolution<Integer>() {}.verifyTwoStageResolution();
  }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java TypeTokenResolutionTest.java source code file:

... 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.