crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 1 | /** |
| 2 | * Copyright (C) 2006 Google Inc. |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.google.inject; |
| 18 | |
kevinb9n | cad2c2b | 2007-05-15 17:28:03 +0000 | [diff] [blame] | 19 | import static com.google.inject.internal.Objects.nonNull; |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 20 | import com.google.inject.internal.Types; |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 21 | import static com.google.inject.internal.Types.canonicalize; |
limpbizkit | e4647a6 | 2008-05-25 18:03:35 +0000 | [diff] [blame] | 22 | |
| 23 | import java.io.Serializable; |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 24 | import java.lang.reflect.ParameterizedType; |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 25 | import java.lang.reflect.Type; |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 26 | |
| 27 | /** |
crazyboblee | 235d068 | 2007-01-31 02:25:21 +0000 | [diff] [blame] | 28 | * Represents a generic type {@code T}. Java doesn't yet provide a way to |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 29 | * represent generic types, so this class does. Forces clients to create a |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 30 | * subclass of this class which enables retrieval the type information even at |
| 31 | * runtime. |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 32 | * |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 33 | * <p>For example, to create a type literal for {@code List<String>}, you can |
| 34 | * create an empty anonymous inner class: |
crazyboblee | e3adfd6 | 2007-02-02 21:30:08 +0000 | [diff] [blame] | 35 | * |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 36 | * <p> |
| 37 | * {@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};} |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 38 | * |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 39 | * <p>Assumes that type {@code T} implements {@link Object#equals} and |
| 40 | * {@link Object#hashCode()} as value (as opposed to identity) comparison. |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 41 | * |
| 42 | * @author crazybob@google.com (Bob Lee) |
| 43 | */ |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 44 | public class TypeLiteral<T> implements Serializable { |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 45 | |
| 46 | final Class<? super T> rawType; |
| 47 | final Type type; |
crazyboblee | 1b54d6a | 2007-02-17 02:48:45 +0000 | [diff] [blame] | 48 | final int hashCode; |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 49 | |
| 50 | /** |
crazyboblee | 0baa9fc | 2007-01-31 02:38:54 +0000 | [diff] [blame] | 51 | * Constructs a new type literal. Derives represented class from type |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 52 | * parameter. |
| 53 | * |
| 54 | * <p>Clients create an empty anonymous subclass. Doing so embeds the type |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 55 | * parameter in the anonymous class's type hierarchy so we can reconstitute it |
| 56 | * at runtime despite erasure. |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 57 | */ |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 58 | @SuppressWarnings("unchecked") |
crazyboblee | 0baa9fc | 2007-01-31 02:38:54 +0000 | [diff] [blame] | 59 | protected TypeLiteral() { |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 60 | this.type = getSuperclassTypeParameter(getClass()); |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 61 | this.rawType = (Class<? super T>) Types.getRawType(type); |
| 62 | this.hashCode = Types.hashCode(type); |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 63 | } |
| 64 | |
| 65 | /** |
crazyboblee | 0baa9fc | 2007-01-31 02:38:54 +0000 | [diff] [blame] | 66 | * Unsafe. Constructs a type literal manually. |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 67 | */ |
kevinb9n | a99dca7 | 2007-02-11 04:48:57 +0000 | [diff] [blame] | 68 | @SuppressWarnings("unchecked") |
crazyboblee | 1b54d6a | 2007-02-17 02:48:45 +0000 | [diff] [blame] | 69 | TypeLiteral(Type type) { |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 70 | this.type = canonicalize(nonNull(type, "type")); |
| 71 | this.rawType = (Class<? super T>) Types.getRawType(this.type); |
| 72 | this.hashCode = Types.hashCode(this.type); |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 73 | } |
| 74 | |
| 75 | /** |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 76 | * Returns the type from super class's type parameter in {@link |
| 77 | * Types#canonicalize(Type) canonical form}. |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 78 | */ |
| 79 | static Type getSuperclassTypeParameter(Class<?> subclass) { |
| 80 | Type superclass = subclass.getGenericSuperclass(); |
| 81 | if (superclass instanceof Class) { |
| 82 | throw new RuntimeException("Missing type parameter."); |
| 83 | } |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 84 | ParameterizedType parameterized = (ParameterizedType) superclass; |
| 85 | return canonicalize(parameterized.getActualTypeArguments()[0]); |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 86 | } |
| 87 | |
| 88 | /** |
crazyboblee | 0baa9fc | 2007-01-31 02:38:54 +0000 | [diff] [blame] | 89 | * Gets type literal from super class's type parameter. |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 90 | */ |
crazyboblee | 0baa9fc | 2007-01-31 02:38:54 +0000 | [diff] [blame] | 91 | static TypeLiteral<?> fromSuperclassTypeParameter(Class<?> subclass) { |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 92 | return new TypeLiteral<Object>(getSuperclassTypeParameter(subclass)); |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 93 | } |
| 94 | |
| 95 | /** |
| 96 | * Gets the raw type. |
| 97 | */ |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 98 | final Class<? super T> getRawType() { |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 99 | return rawType; |
| 100 | } |
| 101 | |
| 102 | /** |
| 103 | * Gets underlying {@code Type} instance. |
| 104 | */ |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 105 | public final Type getType() { |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 106 | return type; |
| 107 | } |
| 108 | |
crazyboblee | 552472f | 2007-09-07 16:52:39 +0000 | [diff] [blame] | 109 | /** |
| 110 | * Gets the type of this type's provider. |
| 111 | */ |
| 112 | @SuppressWarnings("unchecked") |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 113 | final TypeLiteral<Provider<T>> providerType() { |
crazyboblee | 552472f | 2007-09-07 16:52:39 +0000 | [diff] [blame] | 114 | // This cast is safe and wouldn't generate a warning if Type had a type |
| 115 | // parameter. |
limpbizkit | e4647a6 | 2008-05-25 18:03:35 +0000 | [diff] [blame] | 116 | return (TypeLiteral<Provider<T>>) get( |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 117 | Types.newTypeWithArgument(Provider.class, getType())); |
crazyboblee | 552472f | 2007-09-07 16:52:39 +0000 | [diff] [blame] | 118 | } |
| 119 | |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 120 | @Override public final int hashCode() { |
crazyboblee | 1b54d6a | 2007-02-17 02:48:45 +0000 | [diff] [blame] | 121 | return this.hashCode; |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 122 | } |
| 123 | |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 124 | @Override public final boolean equals(Object o) { |
| 125 | return o instanceof TypeLiteral<?> |
| 126 | && Types.equals(type, ((TypeLiteral) o).type); |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 127 | } |
| 128 | |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 129 | @Override public final String toString() { |
| 130 | return Types.toString(type); |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 131 | } |
| 132 | |
| 133 | /** |
crazyboblee | 0baa9fc | 2007-01-31 02:38:54 +0000 | [diff] [blame] | 134 | * Gets type literal for the given {@code Type} instance. |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 135 | */ |
crazyboblee | 0baa9fc | 2007-01-31 02:38:54 +0000 | [diff] [blame] | 136 | public static TypeLiteral<?> get(Type type) { |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 137 | return new TypeLiteral<Object>(type); |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 138 | } |
| 139 | |
| 140 | /** |
crazyboblee | 0baa9fc | 2007-01-31 02:38:54 +0000 | [diff] [blame] | 141 | * Gets type literal for the given {@code Class} instance. |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 142 | */ |
crazyboblee | 0baa9fc | 2007-01-31 02:38:54 +0000 | [diff] [blame] | 143 | public static <T> TypeLiteral<T> get(Class<T> type) { |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 144 | return new TypeLiteral<T>(type); |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 145 | } |
| 146 | |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 147 | /** |
| 148 | * Returns the canonical form of this type literal for serialization. The |
| 149 | * returned instance is always a {@code TypeLiteral}, never a subclass. This |
| 150 | * prevents problems caused by serializing anonymous types. |
| 151 | */ |
limpbizkit | eab7647 | 2008-05-26 19:45:12 +0000 | [diff] [blame] | 152 | protected final Object writeReplace() { |
limpbizkit | f530b25 | 2008-05-27 23:03:42 +0000 | [diff] [blame] | 153 | return getClass() == TypeLiteral.class |
| 154 | ? this |
| 155 | : get(type); |
crazyboblee | 1b54d6a | 2007-02-17 02:48:45 +0000 | [diff] [blame] | 156 | } |
limpbizkit | e4647a6 | 2008-05-25 18:03:35 +0000 | [diff] [blame] | 157 | |
| 158 | private static final long serialVersionUID = 0; |
crazyboblee | 41bc852 | 2006-12-08 07:06:55 +0000 | [diff] [blame] | 159 | } |