001: /*
002: * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025: package com.sun.beans;
026:
027: import java.lang.reflect.Array;
028: import java.lang.reflect.GenericArrayType;
029: import java.lang.reflect.ParameterizedType;
030: import java.lang.reflect.Type;
031: import java.lang.reflect.TypeVariable;
032: import java.lang.reflect.WildcardType;
033: import java.util.HashMap;
034: import java.util.Map;
035:
036: import sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl;
037: import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
038:
039: /**
040: * This is utility class to resolve types.
041: *
042: * @since 1.7
043: *
044: * @version 1.1 06/06/07
045: * @author Eamonn McManus
046: * @author Sergey Malenkov
047: */
048: public final class TypeResolver {
049: /**
050: * Replaces the given {@code type} in an inherited method
051: * with the actual type it has in the given {@code inClass}.
052: *
053: * <p>Although type parameters are not inherited by subclasses in the Java
054: * language, they <em>are</em> effectively inherited when using reflection.
055: * For example, if you declare an interface like this...</p>
056: *
057: * <pre>
058: * public interface StringToIntMap extends Map<String,Integer> {}
059: * </pre>
060: *
061: * <p>...then StringToIntMap.class.getMethods() will show that it has methods
062: * like put(K,V) even though StringToIntMap has no type parameters. The K
063: * and V variables are the ones declared by Map, so
064: * {@link TypeVariable#getGenericDeclaration()} will return Map.class.</p>
065: *
066: * <p>The purpose of this method is to take a Type from a possibly-inherited
067: * method and replace it with the correct Type for the inheriting class.
068: * So given parameters of K and StringToIntMap.class in the above example,
069: * this method will return String.</p>
070: *
071: * @param inClass the base class used to resolve
072: * @param type the type to resolve
073: * @return a resolved type
074: *
075: * @see #getActualType(Class)
076: * @see #resolve(Type,Type)
077: */
078: public static Type resolveInClass(Class<?> inClass, Type type) {
079: return resolve(getActualType(inClass), type);
080: }
081:
082: /**
083: * Replaces all {@code types} in the given array
084: * with the actual types they have in the given {@code inClass}.
085: *
086: * @param inClass the base class used to resolve
087: * @param types the array of types to resolve
088: * @return an array of resolved types
089: *
090: * @see #getActualType(Class)
091: * @see #resolve(Type,Type[])
092: */
093: public static Type[] resolveInClass(Class<?> inClass, Type[] types) {
094: return resolve(getActualType(inClass), types);
095: }
096:
097: /**
098: * Replaces type variables of the given {@code formal} type
099: * with the types they stand for in the given {@code actual} type.
100: *
101: * <p>A ParameterizedType is a class with type parameters, and the values
102: * of those parameters. For example, Map<K,V> is a generic class, and
103: * a corresponding ParameterizedType might look like
104: * Map<K=String,V=Integer>. Given such a ParameterizedType, this method
105: * will replace K with String, or List<K> with List<String;, or
106: * List<? super K> with List<? super String>.</p>
107: *
108: * <p>The {@code actual} argument to this method can also be a Class.
109: * In this case, either it is equivalent to a ParameterizedType with
110: * no parameters (for example, Integer.class), or it is equivalent to
111: * a "raw" ParameterizedType (for example, Map.class). In the latter
112: * case, every type parameter declared or inherited by the class is replaced
113: * by its "erasure". For a type parameter declared as <T>, the erasure
114: * is Object. For a type parameter declared as <T extends Number>,
115: * the erasure is Number.</p>
116: *
117: * <p>Although type parameters are not inherited by subclasses in the Java
118: * language, they <em>are</em> effectively inherited when using reflection.
119: * For example, if you declare an interface like this...</p>
120: *
121: * <pre>
122: * public interface StringToIntMap extends Map<String,Integer> {}
123: * </pre>
124: *
125: * <p>...then StringToIntMap.class.getMethods() will show that it has methods
126: * like put(K,V) even though StringToIntMap has no type parameters. The K
127: * and V variables are the ones declared by Map, so
128: * {@link TypeVariable#getGenericDeclaration()} will return {@link Map Map.class}.</p>
129: *
130: * <p>For this reason, this method replaces inherited type parameters too.
131: * Therefore if this method is called with {@code actual} being
132: * StringToIntMap.class and {@code formal} being the K from Map,
133: * it will return {@link String String.class}.</p>
134: *
135: * <p>In the case where {@code actual} is a "raw" ParameterizedType, the
136: * inherited type parameters will also be replaced by their erasures.
137: * The erasure of a Class is the Class itself, so a "raw" subinterface of
138: * StringToIntMap will still show the K from Map as String.class. But
139: * in a case like this...
140: *
141: * <pre>
142: * public interface StringToIntListMap extends Map<String,List<Integer>> {}
143: * public interface RawStringToIntListMap extends StringToIntListMap {}
144: * </pre>
145: *
146: * <p>...the V inherited from Map will show up as List<Integer> in
147: * StringToIntListMap, but as plain List in RawStringToIntListMap.</p>
148: *
149: * @param actual the type that supplies bindings for type variables
150: * @param formal the type where occurrences of the variables
151: * in {@code actual} will be replaced by the corresponding bound values
152: * @return a resolved type
153: *
154: * @see #TypeResolver(Type)
155: * @see #resolve(Type)
156: */
157: public static Type resolve(Type actual, Type formal) {
158: return new TypeResolver(actual).resolve(formal);
159: }
160:
161: /**
162: * Replaces type variables of all formal types in the given array
163: * with the types they stand for in the given {@code actual} type.
164: *
165: * @param actual the type that supplies bindings for type variables
166: * @param formals the array of types to resolve
167: * @return an array of resolved types
168: *
169: * @see #TypeResolver(Type)
170: * @see #resolve(Type[])
171: */
172: public static Type[] resolve(Type actual, Type[] formals) {
173: return new TypeResolver(actual).resolve(formals);
174: }
175:
176: /**
177: * Converts the given {@code type} to the corresponding class.
178: * This method implements the concept of type erasure,
179: * that is described in <a href="http://jscstage.sfbay.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.6">section 4.6</a>
180: * of Java Language Specification.
181: *
182: * @param type the array of types to convert
183: * @return a corresponding class
184: */
185: public static Class<?> erase(Type type) {
186: if (type instanceof Class) {
187: return (Class<?>) type;
188: }
189: if (type instanceof ParameterizedType) {
190: ParameterizedType pt = (ParameterizedType) type;
191: return (Class<?>) pt.getRawType();
192: }
193: if (type instanceof TypeVariable) {
194: TypeVariable tv = (TypeVariable) type;
195: Type[] bounds = tv.getBounds();
196: return (0 < bounds.length) ? erase(bounds[0])
197: : Object.class;
198: }
199: if (type instanceof WildcardType) {
200: WildcardType wt = (WildcardType) type;
201: Type[] bounds = wt.getUpperBounds();
202: return (0 < bounds.length) ? erase(bounds[0])
203: : Object.class;
204: }
205: if (type instanceof GenericArrayType) {
206: GenericArrayType gat = (GenericArrayType) type;
207: return Array.newInstance(
208: erase(gat.getGenericComponentType()), 0).getClass();
209: }
210: throw new IllegalArgumentException("Unknown Type kind: "
211: + type.getClass());
212: }
213:
214: /**
215: * Converts all {@code types} in the given array
216: * to the corresponding classes.
217: *
218: * @param types the array of types to convert
219: * @return an array of corresponding classes
220: *
221: * @see #erase(Type)
222: */
223: public static Class[] erase(Type[] types) {
224: int length = types.length;
225: Class[] classes = new Class[length];
226: for (int i = 0; i < length; i++) {
227: classes[i] = TypeResolver.erase(types[i]);
228: }
229: return classes;
230: }
231:
232: private final Map<TypeVariable<?>, Type> map = new HashMap<TypeVariable<?>, Type>();
233:
234: /**
235: * Constructs the type resolver for the given actual type.
236: *
237: * @param actual the type that supplies bindings for type variables
238: *
239: * @see #prepare(Type)
240: */
241: private TypeResolver(Type actual) {
242: prepare(actual);
243: }
244:
245: /**
246: * Fills the map from type parameters
247: * to types as seen by the given {@code type}.
248: * The method is recursive because the {@code type}
249: * inherits mappings from its parent classes and interfaces.
250: * The {@code type} can be either a {@link Class Class}
251: * or a {@link ParameterizedType ParameterizedType}.
252: * If it is a {@link Class Class}, it is either equivalent
253: * to a {@link ParameterizedType ParameterizedType} with no parameters,
254: * or it represents the erasure of a {@link ParameterizedType ParameterizedType}.
255: *
256: * @param type the next type in the hierarchy
257: */
258: private void prepare(Type type) {
259: Class<?> raw = (Class<?>) ((type instanceof Class<?>) ? type
260: : ((ParameterizedType) type).getRawType());
261:
262: TypeVariable<?>[] formals = raw.getTypeParameters();
263:
264: Type[] actuals = (type instanceof Class<?>) ? formals
265: : ((ParameterizedType) type).getActualTypeArguments();
266:
267: assert formals.length == actuals.length;
268: for (int i = 0; i < formals.length; i++) {
269: this .map.put(formals[i], actuals[i]);
270: }
271: Type gSuperclass = raw.getGenericSuperclass();
272: if (gSuperclass != null) {
273: prepare(gSuperclass);
274: }
275: for (Type gInterface : raw.getGenericInterfaces()) {
276: prepare(gInterface);
277: }
278: // If type is the raw version of a parameterized class, we type-erase
279: // all of its type variables, including inherited ones.
280: if (type instanceof Class<?> && formals.length > 0) {
281: for (Map.Entry<TypeVariable<?>, Type> entry : this .map
282: .entrySet()) {
283: entry.setValue(erase(entry.getValue()));
284: }
285: }
286: }
287:
288: /**
289: * Replaces the given {@code formal} type
290: * with the type it stand for in this type resolver.
291: *
292: * @param formal the array of types to resolve
293: * @return a resolved type
294: */
295: private Type resolve(Type formal) {
296: if (formal instanceof Class) {
297: return formal;
298: }
299: if (formal instanceof GenericArrayType) {
300: Type comp = ((GenericArrayType) formal)
301: .getGenericComponentType();
302: comp = resolve(comp);
303: return (comp instanceof Class) ? Array.newInstance(
304: (Class<?>) comp, 0).getClass()
305: : GenericArrayTypeImpl.make(comp);
306: }
307: if (formal instanceof ParameterizedType) {
308: ParameterizedType fpt = (ParameterizedType) formal;
309: Type[] actuals = resolve(fpt.getActualTypeArguments());
310: return ParameterizedTypeImpl.make((Class<?>) fpt
311: .getRawType(), actuals, fpt.getOwnerType());
312: }
313: if (formal instanceof WildcardType) {
314: WildcardType fwt = (WildcardType) formal;
315: Type[] upper = resolve(fwt.getUpperBounds());
316: Type[] lower = resolve(fwt.getLowerBounds());
317: return new WildcardTypeImpl(upper, lower);
318: }
319: if (!(formal instanceof TypeVariable)) {
320: throw new IllegalArgumentException("Bad Type kind: "
321: + formal.getClass());
322: }
323: Type actual = this .map.get((TypeVariable) formal);
324: if (actual == null || actual.equals(formal)) {
325: return formal;
326: }
327: actual = fixGenericArray(actual);
328: return resolve(actual);
329: // A variable can be bound to another variable that is itself bound
330: // to something. For example, given:
331: // class Super<T> {...}
332: // class Mid<X> extends Super<T> {...}
333: // class Sub extends Mid<String>
334: // the variable T is bound to X, which is in turn bound to String.
335: // So if we have to resolve T, we need the tail recursion here.
336: }
337:
338: /**
339: * Replaces all formal types in the given array
340: * with the types they stand for in this type resolver.
341: *
342: * @param formals the array of types to resolve
343: * @return an array of resolved types
344: *
345: * @see #resolve(Type)
346: */
347: private Type[] resolve(Type[] formals) {
348: int length = formals.length;
349: Type[] actuals = new Type[length];
350: for (int i = 0; i < length; i++) {
351: actuals[i] = resolve(formals[i]);
352: }
353: return actuals;
354: }
355:
356: /**
357: * Replaces a {@link GenericArrayType GenericArrayType}
358: * with plain array class where it is possible.
359: * Bug <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5041784">5041784</a>
360: * is that arrays of non-generic type sometimes show up
361: * as {@link GenericArrayType GenericArrayType} when using reflection.
362: * For example, a {@code String[]} might show up
363: * as a {@link GenericArrayType GenericArrayType}
364: * where {@link GenericArrayType#getGenericComponentType getGenericComponentType}
365: * is {@code String.class}. This violates the specification,
366: * which says that {@link GenericArrayType GenericArrayType}
367: * is used when the component type is a type variable or parameterized type.
368: * We fit the specification here.
369: *
370: * @param type the type to fix
371: * @return a corresponding type for the generic array type,
372: * or the same type as {@code type}
373: */
374: private static Type fixGenericArray(Type type) {
375: if (type instanceof GenericArrayType) {
376: Type comp = ((GenericArrayType) type)
377: .getGenericComponentType();
378: comp = fixGenericArray(comp);
379: if (comp instanceof Class) {
380: return Array.newInstance((Class<?>) comp, 0).getClass();
381: }
382: }
383: return type;
384: }
385:
386: /**
387: * Replaces a {@link Class Class} with type parameters
388: * with a {@link ParameterizedType ParameterizedType}
389: * where every parameter is bound to itself.
390: * When calling {@link #resolveInClass} in the context of {@code inClass},
391: * we can't just pass {@code inClass} as the {@code actual} parameter,
392: * because if {@code inClass} has type parameters
393: * that would be interpreted as accessing the raw type,
394: * so we would get unwanted erasure.
395: * This is why we bind each parameter to itself.
396: * If {@code inClass} does have type parameters and has methods
397: * where those parameters appear in the return type or argument types,
398: * we will correctly leave those types alone.
399: *
400: * @param inClass the base class used to resolve
401: * @return a parameterized type for the class,
402: * or the same class as {@code inClass}
403: */
404: private static Type getActualType(Class<?> inClass) {
405: Type[] params = inClass.getTypeParameters();
406: return (params.length == 0) ? inClass : ParameterizedTypeImpl
407: .make(inClass, params, inClass.getEnclosingClass());
408: }
409: }
|