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