TypeLiteral.java revision 0baa9fcb9ddf853e9bbf8b71c5f1167051c366e0
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;
2041bc85288590d19c50f299372f942aa27677d77ccrazyboblee
2141bc85288590d19c50f299372f942aa27677d77ccrazybobleeimport java.lang.reflect.Type;
2241bc85288590d19c50f299372f942aa27677d77ccrazybobleeimport java.lang.reflect.ParameterizedType;
2341bc85288590d19c50f299372f942aa27677d77ccrazyboblee
2441bc85288590d19c50f299372f942aa27677d77ccrazyboblee/**
25235d068516b98fcbf9c6f1a05bcbd9d3e97a71d5crazyboblee * Represents a generic type {@code T}. Java doesn't yet provide a way to
26235d068516b98fcbf9c6f1a05bcbd9d3e97a71d5crazyboblee * represent generic types, so this class does.
2741bc85288590d19c50f299372f942aa27677d77ccrazyboblee *
2841bc85288590d19c50f299372f942aa27677d77ccrazyboblee * <p>Assumes {@code Type} implements {@code equals()} and {@code hashCode()}
2941bc85288590d19c50f299372f942aa27677d77ccrazyboblee * as a value (as opposed to identity) comparison.
3041bc85288590d19c50f299372f942aa27677d77ccrazyboblee *
3141bc85288590d19c50f299372f942aa27677d77ccrazyboblee * @author crazybob@google.com (Bob Lee)
3241bc85288590d19c50f299372f942aa27677d77ccrazyboblee */
330baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazybobleepublic abstract class TypeLiteral<T> {
3441bc85288590d19c50f299372f942aa27677d77ccrazyboblee
3541bc85288590d19c50f299372f942aa27677d77ccrazyboblee  final Class<? super T> rawType;
3641bc85288590d19c50f299372f942aa27677d77ccrazyboblee  final Type type;
3741bc85288590d19c50f299372f942aa27677d77ccrazyboblee
3841bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
390baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee   * Constructs a new type literal. Derives represented class from type
4041bc85288590d19c50f299372f942aa27677d77ccrazyboblee   * parameter.
4141bc85288590d19c50f299372f942aa27677d77ccrazyboblee   *
4241bc85288590d19c50f299372f942aa27677d77ccrazyboblee   * <p>Clients create an empty anonymous subclass. Doing so embeds the type
4341bc85288590d19c50f299372f942aa27677d77ccrazyboblee   * parameter in the anonymous class's type hierarchy so we can reconstitute
4441bc85288590d19c50f299372f942aa27677d77ccrazyboblee   * it at runtime despite erasure.
4541bc85288590d19c50f299372f942aa27677d77ccrazyboblee   *
460baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee   * <p>For example: {@code TypeLiteral<List<String>> t = new
470baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee   * TypeLiteral<List<String>>() {};}
4841bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
4941bc85288590d19c50f299372f942aa27677d77ccrazyboblee  @SuppressWarnings({"unchecked"})
500baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  protected TypeLiteral() {
5141bc85288590d19c50f299372f942aa27677d77ccrazyboblee    this.type = getSuperclassTypeParameter(getClass());
5241bc85288590d19c50f299372f942aa27677d77ccrazyboblee    this.rawType = (Class<? super T>) getRawType(type);
5341bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
5441bc85288590d19c50f299372f942aa27677d77ccrazyboblee
5541bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
560baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee   * Unsafe. Constructs a type literal manually.
5741bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
5841bc85288590d19c50f299372f942aa27677d77ccrazyboblee  @SuppressWarnings({"unchecked"})
590baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  private TypeLiteral(Type type) {
6041bc85288590d19c50f299372f942aa27677d77ccrazyboblee    this.rawType = (Class<? super T>) getRawType(nonNull(type, "type"));
6141bc85288590d19c50f299372f942aa27677d77ccrazyboblee    this.type = type;
6241bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
6341bc85288590d19c50f299372f942aa27677d77ccrazyboblee
6441bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
6541bc85288590d19c50f299372f942aa27677d77ccrazyboblee   * Gets type from super class's type parameter.
6641bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
6741bc85288590d19c50f299372f942aa27677d77ccrazyboblee  static Type getSuperclassTypeParameter(Class<?> subclass) {
6841bc85288590d19c50f299372f942aa27677d77ccrazyboblee    Type superclass = subclass.getGenericSuperclass();
6941bc85288590d19c50f299372f942aa27677d77ccrazyboblee    if (superclass instanceof Class) {
7041bc85288590d19c50f299372f942aa27677d77ccrazyboblee      throw new RuntimeException("Missing type parameter.");
7141bc85288590d19c50f299372f942aa27677d77ccrazyboblee    }
7241bc85288590d19c50f299372f942aa27677d77ccrazyboblee    return ((ParameterizedType) superclass).getActualTypeArguments()[0];
7341bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
7441bc85288590d19c50f299372f942aa27677d77ccrazyboblee
7541bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
760baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee   * Gets type literal from super class's type parameter.
7741bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
780baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  static TypeLiteral<?> fromSuperclassTypeParameter(Class<?> subclass) {
790baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    return new SimpleTypeLiteral<Object>(getSuperclassTypeParameter(subclass));
8041bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
8141bc85288590d19c50f299372f942aa27677d77ccrazyboblee
8241bc85288590d19c50f299372f942aa27677d77ccrazyboblee  @SuppressWarnings({"unchecked"})
8341bc85288590d19c50f299372f942aa27677d77ccrazyboblee  private static Class<?> getRawType(Type type) {
8441bc85288590d19c50f299372f942aa27677d77ccrazyboblee    if (type instanceof Class<?>) {
8541bc85288590d19c50f299372f942aa27677d77ccrazyboblee      // type is a normal class.
8641bc85288590d19c50f299372f942aa27677d77ccrazyboblee      return (Class<?>) type;
8741bc85288590d19c50f299372f942aa27677d77ccrazyboblee    } else {
8841bc85288590d19c50f299372f942aa27677d77ccrazyboblee      // type is a parameterized type.
8941bc85288590d19c50f299372f942aa27677d77ccrazyboblee      if (!(type instanceof ParameterizedType)) {
9041bc85288590d19c50f299372f942aa27677d77ccrazyboblee        unexpectedType(type, ParameterizedType.class);
9141bc85288590d19c50f299372f942aa27677d77ccrazyboblee      }
9241bc85288590d19c50f299372f942aa27677d77ccrazyboblee      ParameterizedType parameterizedType = (ParameterizedType) type;
9341bc85288590d19c50f299372f942aa27677d77ccrazyboblee
9441bc85288590d19c50f299372f942aa27677d77ccrazyboblee      // I'm not exactly sure why getRawType() returns Type instead of Class.
9541bc85288590d19c50f299372f942aa27677d77ccrazyboblee      // Neal isn't either but suspects some pathological case related
9641bc85288590d19c50f299372f942aa27677d77ccrazyboblee      // to nested classes exists.
9741bc85288590d19c50f299372f942aa27677d77ccrazyboblee      Type rawType = parameterizedType.getRawType();
9841bc85288590d19c50f299372f942aa27677d77ccrazyboblee      if (!(rawType instanceof Class<?>)) {
9941bc85288590d19c50f299372f942aa27677d77ccrazyboblee        unexpectedType(rawType, Class.class);
10041bc85288590d19c50f299372f942aa27677d77ccrazyboblee      }
10141bc85288590d19c50f299372f942aa27677d77ccrazyboblee      return (Class<?>) rawType;
10241bc85288590d19c50f299372f942aa27677d77ccrazyboblee    }
10341bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
10441bc85288590d19c50f299372f942aa27677d77ccrazyboblee
10541bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
10641bc85288590d19c50f299372f942aa27677d77ccrazyboblee   * Gets the raw type.
10741bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
10841bc85288590d19c50f299372f942aa27677d77ccrazyboblee  Class<? super T> getRawType() {
10941bc85288590d19c50f299372f942aa27677d77ccrazyboblee    return rawType;
11041bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
11141bc85288590d19c50f299372f942aa27677d77ccrazyboblee
11241bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
11341bc85288590d19c50f299372f942aa27677d77ccrazyboblee   * Gets underlying {@code Type} instance.
11441bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
11541bc85288590d19c50f299372f942aa27677d77ccrazyboblee  public Type getType() {
11641bc85288590d19c50f299372f942aa27677d77ccrazyboblee    return type;
11741bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
11841bc85288590d19c50f299372f942aa27677d77ccrazyboblee
11941bc85288590d19c50f299372f942aa27677d77ccrazyboblee  public int hashCode() {
12041bc85288590d19c50f299372f942aa27677d77ccrazyboblee    return type.hashCode();
12141bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
12241bc85288590d19c50f299372f942aa27677d77ccrazyboblee
12341bc85288590d19c50f299372f942aa27677d77ccrazyboblee  public boolean equals(Object o) {
12441bc85288590d19c50f299372f942aa27677d77ccrazyboblee    if (o == this) {
12541bc85288590d19c50f299372f942aa27677d77ccrazyboblee      return true;
12641bc85288590d19c50f299372f942aa27677d77ccrazyboblee    }
1270baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    if (!(o instanceof TypeLiteral<?>)) {
12841bc85288590d19c50f299372f942aa27677d77ccrazyboblee      return false;
12941bc85288590d19c50f299372f942aa27677d77ccrazyboblee    }
1300baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    TypeLiteral<?> t = (TypeLiteral<?>) o;
13141bc85288590d19c50f299372f942aa27677d77ccrazyboblee    return type.equals(t.type);
13241bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
13341bc85288590d19c50f299372f942aa27677d77ccrazyboblee
13441bc85288590d19c50f299372f942aa27677d77ccrazyboblee  public String toString() {
13541bc85288590d19c50f299372f942aa27677d77ccrazyboblee    return type instanceof Class<?>
13641bc85288590d19c50f299372f942aa27677d77ccrazyboblee          ? ((Class<?>) type).getName()
13741bc85288590d19c50f299372f942aa27677d77ccrazyboblee          : type.toString();
13841bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
13941bc85288590d19c50f299372f942aa27677d77ccrazyboblee
1400baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  static void unexpectedType(Type type, Class<?> expected) {
14141bc85288590d19c50f299372f942aa27677d77ccrazyboblee    throw new AssertionError(
14241bc85288590d19c50f299372f942aa27677d77ccrazyboblee        "Unexpected type. Expected: " + expected.getName()
1430baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee        + ", got: " + type.getClass().getName()
1440baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee        + ", for type literal: " + type.toString() + ".");
14541bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
14641bc85288590d19c50f299372f942aa27677d77ccrazyboblee
14741bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
1480baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee   * Gets type literal for the given {@code Type} instance.
14941bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
1500baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  public static TypeLiteral<?> get(Type type) {
1510baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    return new SimpleTypeLiteral<Object>(type);
15241bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
15341bc85288590d19c50f299372f942aa27677d77ccrazyboblee
15441bc85288590d19c50f299372f942aa27677d77ccrazyboblee  /**
1550baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee   * Gets type literal for the given {@code Class} instance.
15641bc85288590d19c50f299372f942aa27677d77ccrazyboblee   */
1570baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  public static <T> TypeLiteral<T> get(Class<T> type) {
1580baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    return new SimpleTypeLiteral<T>(type);
15941bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
16041bc85288590d19c50f299372f942aa27677d77ccrazyboblee
1610baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee  private static class SimpleTypeLiteral<T> extends TypeLiteral<T> {
1620baa9fcb9ddf853e9bbf8b71c5f1167051c366e0crazyboblee    public SimpleTypeLiteral(Type type) {
16341bc85288590d19c50f299372f942aa27677d77ccrazyboblee      super(type);
16441bc85288590d19c50f299372f942aa27677d77ccrazyboblee    }
16541bc85288590d19c50f299372f942aa27677d77ccrazyboblee  }
16641bc85288590d19c50f299372f942aa27677d77ccrazyboblee}
167