001: /**
002: * Copyright (C) 2006 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */package com.google.inject;
016:
017: import static com.google.inject.util.Objects.nonNull;
018: import java.lang.reflect.ParameterizedType;
019: import java.lang.reflect.Type;
020: import java.lang.reflect.GenericArrayType;
021: import java.lang.reflect.Array;
022: import java.util.Arrays;
023:
024: /**
025: * Represents a generic type {@code T}. Java doesn't yet provide a way to
026: * represent generic types, so this class does. Forces clients to create a
027: * subclass of this class which enables retrieval the type information even at
028: * runtime.
029: *
030: * <p>For example, to create a type literal for {@code List<String>}, you can
031: * create an empty anonymous inner class:
032: *
033: * <p>
034: * {@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};}
035: *
036: * <p>Assumes that type {@code T} implements {@link Object#equals} and
037: * {@link Object#hashCode()} as value (as opposed to identity) comparison.
038: *
039: * @author crazybob@google.com (Bob Lee)
040: */
041: public abstract class TypeLiteral<T> {
042:
043: final Class<? super T> rawType;
044: final Type type;
045: final int hashCode;
046:
047: /**
048: * Constructs a new type literal. Derives represented class from type
049: * parameter.
050: *
051: * <p>Clients create an empty anonymous subclass. Doing so embeds the type
052: * parameter in the anonymous class's type hierarchy so we can reconstitute it
053: * at runtime despite erasure.
054: */
055: @SuppressWarnings("unchecked")
056: protected TypeLiteral() {
057: this .type = getSuperclassTypeParameter(getClass());
058: this .rawType = (Class<? super T>) getRawType(type);
059: this .hashCode = hashCode(type);
060: }
061:
062: /**
063: * Unsafe. Constructs a type literal manually.
064: */
065: @SuppressWarnings("unchecked")
066: TypeLiteral(Type type) {
067: this .rawType = (Class<? super T>) getRawType(nonNull(type,
068: "type"));
069: this .type = type;
070: this .hashCode = hashCode(type);
071: }
072:
073: /**
074: * Gets type from super class's type parameter.
075: */
076: static Type getSuperclassTypeParameter(Class<?> subclass) {
077: Type super class = subclass.getGenericSuperclass();
078: if (super class instanceof Class) {
079: throw new RuntimeException("Missing type parameter.");
080: }
081: return ((ParameterizedType) super class)
082: .getActualTypeArguments()[0];
083: }
084:
085: /**
086: * Gets type literal from super class's type parameter.
087: */
088: static TypeLiteral<?> fromSuperclassTypeParameter(Class<?> subclass) {
089: return new SimpleTypeLiteral<Object>(
090: getSuperclassTypeParameter(subclass));
091: }
092:
093: @SuppressWarnings({"unchecked"})
094: private static Class<?> getRawType(Type type) {
095: if (type instanceof Class<?>) {
096: // type is a normal class.
097: return (Class<?>) type;
098: } else {
099: if (type instanceof ParameterizedType) {
100: ParameterizedType parameterizedType = (ParameterizedType) type;
101:
102: // I'm not exactly sure why getRawType() returns Type instead of Class.
103: // Neal isn't either but suspects some pathological case related
104: // to nested classes exists.
105: Type rawType = parameterizedType.getRawType();
106: if (!(rawType instanceof Class<?>)) {
107: throw unexpectedType(rawType, Class.class);
108: }
109: return (Class<?>) rawType;
110: }
111:
112: if (type instanceof GenericArrayType) {
113: // TODO: Is this sufficient?
114: return Object[].class;
115: }
116:
117: // type is a parameterized type.
118: throw unexpectedType(type, ParameterizedType.class);
119: }
120: }
121:
122: /**
123: * Gets the raw type.
124: */
125: Class<? super T> getRawType() {
126: return rawType;
127: }
128:
129: /**
130: * Gets underlying {@code Type} instance.
131: */
132: public Type getType() {
133: return type;
134: }
135:
136: public int hashCode() {
137: return this .hashCode;
138: }
139:
140: public boolean equals(Object o) {
141: if (o == this ) {
142: return true;
143: }
144: if (!(o instanceof TypeLiteral<?>)) {
145: return false;
146: }
147: TypeLiteral<?> other = (TypeLiteral<?>) o;
148:
149: return equals(type, other.type);
150: }
151:
152: public String toString() {
153: return type instanceof Class<?> ? ((Class<?>) type).getName()
154: : type.toString();
155: }
156:
157: static AssertionError unexpectedType(Type type, Class<?> expected) {
158: return new AssertionError("Unexpected type. Expected: "
159: + expected.getName() + ", got: "
160: + type.getClass().getName() + ", for type literal: "
161: + type.toString() + ".");
162: }
163:
164: /**
165: * Gets type literal for the given {@code Type} instance.
166: */
167: public static TypeLiteral<?> get(Type type) {
168: return new SimpleTypeLiteral<Object>(type);
169: }
170:
171: /**
172: * Gets type literal for the given {@code Class} instance.
173: */
174: public static <T> TypeLiteral<T> get(Class<T> type) {
175: return new SimpleTypeLiteral<T>(type);
176: }
177:
178: private static class SimpleTypeLiteral<T> extends TypeLiteral<T> {
179: public SimpleTypeLiteral(Type type) {
180: super (type);
181: }
182: }
183:
184: static int hashCode(Type type) {
185: if (type instanceof ParameterizedType) {
186: ParameterizedType p = (ParameterizedType) type;
187: int h = p.getRawType().hashCode();
188: for (Type argument : p.getActualTypeArguments()) {
189: h = h * 31 + hashCode(argument);
190: }
191: return h;
192: }
193:
194: if (type instanceof Class) {
195: // Class specifies hashCode().
196: return type.hashCode();
197: }
198:
199: if (type instanceof GenericArrayType) {
200: return hashCode(((GenericArrayType) type)
201: .getGenericComponentType()) * 31;
202: }
203:
204: // This isn't a type we support. Could be a generic array type, wildcard
205: // type, etc.
206: return type.hashCode();
207: }
208:
209: static boolean equals(Type a, Type b) {
210: if (a instanceof Class) {
211: // Class already specifies equals().
212: return a.equals(b);
213: }
214:
215: if (a instanceof ParameterizedType) {
216: if (!(b instanceof ParameterizedType)) {
217: return false;
218: }
219:
220: ParameterizedType pa = (ParameterizedType) a;
221: ParameterizedType pb = (ParameterizedType) b;
222:
223: if (!pa.getRawType().equals(pb.getRawType())) {
224: return false;
225: }
226:
227: Type[] aa = pa.getActualTypeArguments();
228: Type[] ba = pb.getActualTypeArguments();
229: if (aa.length != ba.length) {
230: return false;
231: }
232:
233: for (int i = 0; i < aa.length; i++) {
234: if (!equals(aa[i], ba[i])) {
235: return false;
236: }
237: }
238:
239: return true;
240: }
241:
242: if (a instanceof GenericArrayType) {
243: if (!(b instanceof GenericArrayType)) {
244: return false;
245: }
246:
247: return equals(((GenericArrayType) a)
248: .getGenericComponentType(), ((GenericArrayType) b)
249: .getGenericComponentType());
250: }
251:
252: // This isn't a type we support. Could be a generic array type, wildcard
253: // type, etc.
254: return false;
255: }
256: }
|