TypeLiteral.java revision a99dca76dc81e4a7c45a5d2d7d875b040f51abdc
141bc85288590d19c50f299372f942aa27677d77ccrazyboblee/**
241bc85288590d19c50f299372f942aa27677d77ccrazyboblee * Copyright (C) 2006 Google Inc.
341bc85288590d19c50f299372f942aa27677d77ccrazyboblee *
441bc85288590d19c50f299372f942aa27677d77ccrazyboblee * Licensed under the Apache License, Version 2.0 (the "License");
541bc85288590d19c50f299372f942aa27677d77ccrazyboblee * you may not use this file except in compliance with the License.
641bc85288590d19c50f299372f942aa27677d77ccrazyboblee * You may obtain a copy of the License at
741bc85288590d19c50f299372f942aa27677d77ccrazyboblee *
841bc85288590d19c50f299372f942aa27677d77ccrazyboblee * http://www.apache.org/licenses/LICENSE-2.0
941bc85288590d19c50f299372f942aa27677d77ccrazyboblee *
1041bc85288590d19c50f299372f942aa27677d77ccrazyboblee * Unless required by applicable law or agreed to in writing, software
1141bc85288590d19c50f299372f942aa27677d77ccrazyboblee * distributed under the License is distributed on an "AS IS" BASIS,
1241bc85288590d19c50f299372f942aa27677d77ccrazyboblee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1341bc85288590d19c50f299372f942aa27677d77ccrazyboblee * See the License for the specific language governing permissions and
1441bc85288590d19c50f299372f942aa27677d77ccrazyboblee * limitations under the License.
1541bc85288590d19c50f299372f942aa27677d77ccrazyboblee */
1641bc85288590d19c50f299372f942aa27677d77ccrazyboblee
1741bc85288590d19c50f299372f942aa27677d77ccrazybobleepackage com.google.inject;
1841bc85288590d19c50f299372f942aa27677d77ccrazyboblee
1941bc85288590d19c50f299372f942aa27677d77ccrazybobleeimport static com.google.inject.util.Objects.nonNull;
2041bc85288590d19c50f299372f942aa27677d77ccrazybobleeimport java.lang.reflect.ParameterizedType;
21a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinbimport java.lang.reflect.Type;
2241bc85288590d19c50f299372f942aa27677d77ccrazyboblee
2341bc85288590d19c50f299372f942aa27677d77ccrazyboblee/**
24235d068516b98fcbf9c6f1a05bcbd9d3e97a71d5crazyboblee * Represents a generic type {@code T}. Java doesn't yet provide a way to
25e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee * represent generic types, so this class does. Forces clients to create a
26a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb * subclass of this class which enables retrieval the type information even at
27a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb * runtime.
28e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee *
29a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb * <p>For example, to create a type literal for {@code List<String>}, you can
30a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb * create an empty anonymous inner class:
31e3adfd619abae820b90951f383ec7a271a62c0b0crazyboblee *
32a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb * <p>
33a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb * {@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};}
3441bc85288590d19c50f299372f942aa27677d77ccrazyboblee *
35a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb * <p>Assumes that type {@code T} implements {@link Object#equals} and
36a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb * {@link Object#hashCode()} as value (as opposed to identity) comparison.
3741bc85288590d19c50f299372f942aa27677d77ccrazyboblee *
3841bc85288590d19c50f299372f942aa27677d77ccrazyboblee * @author crazybob@google.com (Bob Lee)
3941bc85288590d19c50f299372f942aa27677d77ccrazyboblee */
400baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazybobleepublic abstract class TypeLiteral<T> {
4141bc85288590d19c50f299372f942aa27677d77ccrazyboblee
4241bc85288590d19c50f299372f942aa27677d77ccrazyboblee  final Class<? super T> rawType;
4341bc85288590d19c50f299372f942aa27677d77ccrazyboblee  final Type type;
4441bc85288590d19c50f299372f942aa27677d77ccrazyboblee
4541bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
460baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee   * Constructs a new type literal. Derives represented class from type
4741bc85288590d19c50f299372f942aa27677d77ccrazyboblee   * parameter.
4841bc85288590d19c50f299372f942aa27677d77ccrazyboblee   *
4941bc85288590d19c50f299372f942aa27677d77ccrazyboblee   * <p>Clients create an empty anonymous subclass. Doing so embeds the type
50a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb   * parameter in the anonymous class's type hierarchy so we can reconstitute it
51a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb   * at runtime despite erasure.
5241bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
53a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb  @SuppressWarnings("unchecked")
540baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  protected TypeLiteral() {
5541bc85288590d19c50f299372f942aa27677d77ccrazyboblee    this.type = getSuperclassTypeParameter(getClass());
5641bc85288590d19c50f299372f942aa27677d77ccrazyboblee    this.rawType = (Class<? super T>) getRawType(type);
5741bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
5841bc85288590d19c50f299372f942aa27677d77ccrazyboblee
5941bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
600baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee   * Unsafe. Constructs a type literal manually.
6141bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
62a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb  @SuppressWarnings("unchecked")
630baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  private TypeLiteral(Type type) {
6441bc85288590d19c50f299372f942aa27677d77ccrazyboblee    this.rawType = (Class<? super T>) getRawType(nonNull(type, "type"));
6541bc85288590d19c50f299372f942aa27677d77ccrazyboblee    this.type = type;
6641bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
6741bc85288590d19c50f299372f942aa27677d77ccrazyboblee
6841bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
6941bc85288590d19c50f299372f942aa27677d77ccrazyboblee   * Gets type from super class's type parameter.
7041bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
7141bc85288590d19c50f299372f942aa27677d77ccrazyboblee  static Type getSuperclassTypeParameter(Class<?> subclass) {
7241bc85288590d19c50f299372f942aa27677d77ccrazyboblee    Type superclass = subclass.getGenericSuperclass();
7341bc85288590d19c50f299372f942aa27677d77ccrazyboblee    if (superclass instanceof Class) {
7441bc85288590d19c50f299372f942aa27677d77ccrazyboblee      throw new RuntimeException("Missing type parameter.");
7541bc85288590d19c50f299372f942aa27677d77ccrazyboblee    }
7641bc85288590d19c50f299372f942aa27677d77ccrazyboblee    return ((ParameterizedType) superclass).getActualTypeArguments()[0];
7741bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
7841bc85288590d19c50f299372f942aa27677d77ccrazyboblee
7941bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
800baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee   * Gets type literal from super class's type parameter.
8141bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
820baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  static TypeLiteral<?> fromSuperclassTypeParameter(Class<?> subclass) {
830baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    return new SimpleTypeLiteral<Object>(getSuperclassTypeParameter(subclass));
8441bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
8541bc85288590d19c50f299372f942aa27677d77ccrazyboblee
86a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb  @SuppressWarnings({ "unchecked" })
8741bc85288590d19c50f299372f942aa27677d77ccrazyboblee  private static Class<?> getRawType(Type type) {
8841bc85288590d19c50f299372f942aa27677d77ccrazyboblee    if (type instanceof Class<?>) {
8941bc85288590d19c50f299372f942aa27677d77ccrazyboblee      // type is a normal class.
9041bc85288590d19c50f299372f942aa27677d77ccrazyboblee      return (Class<?>) type;
91a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb    }
92a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb    else {
9341bc85288590d19c50f299372f942aa27677d77ccrazyboblee      // type is a parameterized type.
9441bc85288590d19c50f299372f942aa27677d77ccrazyboblee      if (!(type instanceof ParameterizedType)) {
9541bc85288590d19c50f299372f942aa27677d77ccrazyboblee        unexpectedType(type, ParameterizedType.class);
9641bc85288590d19c50f299372f942aa27677d77ccrazyboblee      }
9741bc85288590d19c50f299372f942aa27677d77ccrazyboblee      ParameterizedType parameterizedType = (ParameterizedType) type;
9841bc85288590d19c50f299372f942aa27677d77ccrazyboblee
9941bc85288590d19c50f299372f942aa27677d77ccrazyboblee      // I'm not exactly sure why getRawType() returns Type instead of Class.
10041bc85288590d19c50f299372f942aa27677d77ccrazyboblee      // Neal isn't either but suspects some pathological case related
10141bc85288590d19c50f299372f942aa27677d77ccrazyboblee      // to nested classes exists.
10241bc85288590d19c50f299372f942aa27677d77ccrazyboblee      Type rawType = parameterizedType.getRawType();
10341bc85288590d19c50f299372f942aa27677d77ccrazyboblee      if (!(rawType instanceof Class<?>)) {
10441bc85288590d19c50f299372f942aa27677d77ccrazyboblee        unexpectedType(rawType, Class.class);
10541bc85288590d19c50f299372f942aa27677d77ccrazyboblee      }
10641bc85288590d19c50f299372f942aa27677d77ccrazyboblee      return (Class<?>) rawType;
10741bc85288590d19c50f299372f942aa27677d77ccrazyboblee    }
10841bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
10941bc85288590d19c50f299372f942aa27677d77ccrazyboblee
11041bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
11141bc85288590d19c50f299372f942aa27677d77ccrazyboblee   * Gets the raw type.
11241bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
11341bc85288590d19c50f299372f942aa27677d77ccrazyboblee  Class<? super T> getRawType() {
11441bc85288590d19c50f299372f942aa27677d77ccrazyboblee    return rawType;
11541bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
11641bc85288590d19c50f299372f942aa27677d77ccrazyboblee
11741bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
11841bc85288590d19c50f299372f942aa27677d77ccrazyboblee   * Gets underlying {@code Type} instance.
11941bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
12041bc85288590d19c50f299372f942aa27677d77ccrazyboblee  public Type getType() {
12141bc85288590d19c50f299372f942aa27677d77ccrazyboblee    return type;
12241bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
12341bc85288590d19c50f299372f942aa27677d77ccrazyboblee
12441bc85288590d19c50f299372f942aa27677d77ccrazyboblee  public int hashCode() {
12541bc85288590d19c50f299372f942aa27677d77ccrazyboblee    return type.hashCode();
12641bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
12741bc85288590d19c50f299372f942aa27677d77ccrazyboblee
12841bc85288590d19c50f299372f942aa27677d77ccrazyboblee  public boolean equals(Object o) {
12941bc85288590d19c50f299372f942aa27677d77ccrazyboblee    if (o == this) {
13041bc85288590d19c50f299372f942aa27677d77ccrazyboblee      return true;
13141bc85288590d19c50f299372f942aa27677d77ccrazyboblee    }
1320baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    if (!(o instanceof TypeLiteral<?>)) {
13341bc85288590d19c50f299372f942aa27677d77ccrazyboblee      return false;
13441bc85288590d19c50f299372f942aa27677d77ccrazyboblee    }
1350baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    TypeLiteral<?> t = (TypeLiteral<?>) o;
13641bc85288590d19c50f299372f942aa27677d77ccrazyboblee    return type.equals(t.type);
13741bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
13841bc85288590d19c50f299372f942aa27677d77ccrazyboblee
13941bc85288590d19c50f299372f942aa27677d77ccrazyboblee  public String toString() {
14041bc85288590d19c50f299372f942aa27677d77ccrazyboblee    return type instanceof Class<?>
141a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb        ? ((Class<?>) type).getName()
142a99dca76dc81e4a7c45a5d2d7d875b040f51abdckevinb        : type.toString();
14341bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
14441bc85288590d19c50f299372f942aa27677d77ccrazyboblee
1450baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  static void unexpectedType(Type type, Class<?> expected) {
14641bc85288590d19c50f299372f942aa27677d77ccrazyboblee    throw new AssertionError(
14741bc85288590d19c50f299372f942aa27677d77ccrazyboblee        "Unexpected type. Expected: " + expected.getName()
1480baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee        + ", got: " + type.getClass().getName()
1490baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee        + ", for type literal: " + type.toString() + ".");
15041bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
15141bc85288590d19c50f299372f942aa27677d77ccrazyboblee
15241bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
1530baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee   * Gets type literal for the given {@code Type} instance.
15441bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
1550baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  public static TypeLiteral<?> get(Type type) {
1560baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    return new SimpleTypeLiteral<Object>(type);
15741bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
15841bc85288590d19c50f299372f942aa27677d77ccrazyboblee
15941bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
1600baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee   * Gets type literal for the given {@code Class} instance.
16141bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
1620baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  public static <T> TypeLiteral<T> get(Class<T> type) {
1630baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    return new SimpleTypeLiteral<T>(type);
16441bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
16541bc85288590d19c50f299372f942aa27677d77ccrazyboblee
1660baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  private static class SimpleTypeLiteral<T> extends TypeLiteral<T> {
1670baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    public SimpleTypeLiteral(Type type) {
16841bc85288590d19c50f299372f942aa27677d77ccrazyboblee      super(type);
16941bc85288590d19c50f299372f942aa27677d77ccrazyboblee    }
17041bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
17141bc85288590d19c50f299372f942aa27677d77ccrazyboblee}
172