| /* |
| * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| package com.sun.beans; |
| |
| import java.lang.reflect.Array; |
| import java.lang.reflect.GenericArrayType; |
| import java.lang.reflect.ParameterizedType; |
| import java.lang.reflect.Type; |
| import java.lang.reflect.TypeVariable; |
| import java.lang.reflect.WildcardType; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl; |
| import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl; |
| |
| /** |
| * This is utility class to resolve types. |
| * |
| * @since 1.7 |
| * |
| * @author Eamonn McManus |
| * @author Sergey Malenkov |
| */ |
| public final class TypeResolver { |
| /** |
| * Replaces the given {@code type} in an inherited method |
| * with the actual type it has in the given {@code inClass}. |
| * |
| * <p>Although type parameters are not inherited by subclasses in the Java |
| * language, they <em>are</em> effectively inherited when using reflection. |
| * For example, if you declare an interface like this...</p> |
| * |
| * <pre> |
| * public interface StringToIntMap extends Map<String,Integer> {} |
| * </pre> |
| * |
| * <p>...then StringToIntMap.class.getMethods() will show that it has methods |
| * like put(K,V) even though StringToIntMap has no type parameters. The K |
| * and V variables are the ones declared by Map, so |
| * {@link TypeVariable#getGenericDeclaration()} will return Map.class.</p> |
| * |
| * <p>The purpose of this method is to take a Type from a possibly-inherited |
| * method and replace it with the correct Type for the inheriting class. |
| * So given parameters of K and StringToIntMap.class in the above example, |
| * this method will return String.</p> |
| * |
| * @param inClass the base class used to resolve |
| * @param type the type to resolve |
| * @return a resolved type |
| * |
| * @see #getActualType(Class) |
| * @see #resolve(Type,Type) |
| */ |
| public static Type resolveInClass(Class<?> inClass, Type type) { |
| return resolve(getActualType(inClass), type); |
| } |
| |
| /** |
| * Replaces all {@code types} in the given array |
| * with the actual types they have in the given {@code inClass}. |
| * |
| * @param inClass the base class used to resolve |
| * @param types the array of types to resolve |
| * @return an array of resolved types |
| * |
| * @see #getActualType(Class) |
| * @see #resolve(Type,Type[]) |
| */ |
| public static Type[] resolveInClass(Class<?> inClass, Type[] types) { |
| return resolve(getActualType(inClass), types); |
| } |
| |
| /** |
| * Replaces type variables of the given {@code formal} type |
| * with the types they stand for in the given {@code actual} type. |
| * |
| * <p>A ParameterizedType is a class with type parameters, and the values |
| * of those parameters. For example, Map<K,V> is a generic class, and |
| * a corresponding ParameterizedType might look like |
| * Map<K=String,V=Integer>. Given such a ParameterizedType, this method |
| * will replace K with String, or List<K> with List<String;, or |
| * List<? super K> with List<? super String>.</p> |
| * |
| * <p>The {@code actual} argument to this method can also be a Class. |
| * In this case, either it is equivalent to a ParameterizedType with |
| * no parameters (for example, Integer.class), or it is equivalent to |
| * a "raw" ParameterizedType (for example, Map.class). In the latter |
| * case, every type parameter declared or inherited by the class is replaced |
| * by its "erasure". For a type parameter declared as <T>, the erasure |
| * is Object. For a type parameter declared as <T extends Number>, |
| * the erasure is Number.</p> |
| * |
| * <p>Although type parameters are not inherited by subclasses in the Java |
| * language, they <em>are</em> effectively inherited when using reflection. |
| * For example, if you declare an interface like this...</p> |
| * |
| * <pre> |
| * public interface StringToIntMap extends Map<String,Integer> {} |
| * </pre> |
| * |
| * <p>...then StringToIntMap.class.getMethods() will show that it has methods |
| * like put(K,V) even though StringToIntMap has no type parameters. The K |
| * and V variables are the ones declared by Map, so |
| * {@link TypeVariable#getGenericDeclaration()} will return {@link Map Map.class}.</p> |
| * |
| * <p>For this reason, this method replaces inherited type parameters too. |
| * Therefore if this method is called with {@code actual} being |
| * StringToIntMap.class and {@code formal} being the K from Map, |
| * it will return {@link String String.class}.</p> |
| * |
| * <p>In the case where {@code actual} is a "raw" ParameterizedType, the |
| * inherited type parameters will also be replaced by their erasures. |
| * The erasure of a Class is the Class itself, so a "raw" subinterface of |
| * StringToIntMap will still show the K from Map as String.class. But |
| * in a case like this... |
| * |
| * <pre> |
| * public interface StringToIntListMap extends Map<String,List<Integer>> {} |
| * public interface RawStringToIntListMap extends StringToIntListMap {} |
| * </pre> |
| * |
| * <p>...the V inherited from Map will show up as List<Integer> in |
| * StringToIntListMap, but as plain List in RawStringToIntListMap.</p> |
| * |
| * @param actual the type that supplies bindings for type variables |
| * @param formal the type where occurrences of the variables |
| * in {@code actual} will be replaced by the corresponding bound values |
| * @return a resolved type |
| * |
| * @see #TypeResolver(Type) |
| * @see #resolve(Type) |
| */ |
| public static Type resolve(Type actual, Type formal) { |
| return getTypeResolver(actual).resolve(formal); |
| } |
| |
| /** |
| * Replaces type variables of all formal types in the given array |
| * with the types they stand for in the given {@code actual} type. |
| * |
| * @param actual the type that supplies bindings for type variables |
| * @param formals the array of types to resolve |
| * @return an array of resolved types |
| * |
| * @see #TypeResolver(Type) |
| * @see #resolve(Type[]) |
| */ |
| public static Type[] resolve(Type actual, Type[] formals) { |
| return getTypeResolver(actual).resolve(formals); |
| } |
| |
| /** |
| * Converts the given {@code type} to the corresponding class. |
| * This method implements the concept of type erasure, |
| * that is described in section 4.6 of |
| * <cite>The Java™ Language Specification</cite>. |
| * |
| * @param type the array of types to convert |
| * @return a corresponding class |
| */ |
| public static Class<?> erase(Type type) { |
| if (type instanceof Class) { |
| return (Class<?>) type; |
| } |
| if (type instanceof ParameterizedType) { |
| ParameterizedType pt = (ParameterizedType) type; |
| return (Class<?>) pt.getRawType(); |
| } |
| if (type instanceof TypeVariable) { |
| TypeVariable tv = (TypeVariable)type; |
| Type[] bounds = tv.getBounds(); |
| return (0 < bounds.length) |
| ? erase(bounds[0]) |
| : Object.class; |
| } |
| if (type instanceof WildcardType) { |
| WildcardType wt = (WildcardType)type; |
| Type[] bounds = wt.getUpperBounds(); |
| return (0 < bounds.length) |
| ? erase(bounds[0]) |
| : Object.class; |
| } |
| if (type instanceof GenericArrayType) { |
| GenericArrayType gat = (GenericArrayType)type; |
| return Array.newInstance(erase(gat.getGenericComponentType()), 0).getClass(); |
| } |
| throw new IllegalArgumentException("Unknown Type kind: " + type.getClass()); |
| } |
| |
| /** |
| * Converts all {@code types} in the given array |
| * to the corresponding classes. |
| * |
| * @param types the array of types to convert |
| * @return an array of corresponding classes |
| * |
| * @see #erase(Type) |
| */ |
| public static Class[] erase(Type[] types) { |
| int length = types.length; |
| Class[] classes = new Class[length]; |
| for (int i = 0; i < length; i++) { |
| classes[i] = TypeResolver.erase(types[i]); |
| } |
| return classes; |
| } |
| |
| public static TypeResolver getTypeResolver(Type type) { |
| synchronized (CACHE) { |
| TypeResolver resolver = CACHE.get(type); |
| if (resolver == null) { |
| resolver = new TypeResolver(type); |
| CACHE.put(type, resolver); |
| } |
| return resolver; |
| } |
| } |
| |
| private static final WeakCache<Type, TypeResolver> CACHE = new WeakCache<>(); |
| |
| private final Map<TypeVariable<?>, Type> map = new HashMap<>(); |
| |
| /** |
| * Constructs the type resolver for the given actual type. |
| * |
| * @param actual the type that supplies bindings for type variables |
| * |
| * @see #prepare(Type) |
| */ |
| private TypeResolver(Type actual) { |
| prepare(actual); |
| } |
| |
| /** |
| * Fills the map from type parameters |
| * to types as seen by the given {@code type}. |
| * The method is recursive because the {@code type} |
| * inherits mappings from its parent classes and interfaces. |
| * The {@code type} can be either a {@link Class Class} |
| * or a {@link ParameterizedType ParameterizedType}. |
| * If it is a {@link Class Class}, it is either equivalent |
| * to a {@link ParameterizedType ParameterizedType} with no parameters, |
| * or it represents the erasure of a {@link ParameterizedType ParameterizedType}. |
| * |
| * @param type the next type in the hierarchy |
| */ |
| private void prepare(Type type) { |
| Class<?> raw = (Class<?>)((type instanceof Class<?>) |
| ? type |
| : ((ParameterizedType)type).getRawType()); |
| |
| TypeVariable<?>[] formals = raw.getTypeParameters(); |
| |
| Type[] actuals = (type instanceof Class<?>) |
| ? formals |
| : ((ParameterizedType)type).getActualTypeArguments(); |
| |
| assert formals.length == actuals.length; |
| for (int i = 0; i < formals.length; i++) { |
| this.map.put(formals[i], actuals[i]); |
| } |
| Type gSuperclass = raw.getGenericSuperclass(); |
| if (gSuperclass != null) { |
| prepare(gSuperclass); |
| } |
| for (Type gInterface : raw.getGenericInterfaces()) { |
| prepare(gInterface); |
| } |
| // If type is the raw version of a parameterized class, we type-erase |
| // all of its type variables, including inherited ones. |
| if (type instanceof Class<?> && formals.length > 0) { |
| for (Map.Entry<TypeVariable<?>, Type> entry : this.map.entrySet()) { |
| entry.setValue(erase(entry.getValue())); |
| } |
| } |
| } |
| |
| /** |
| * Replaces the given {@code formal} type |
| * with the type it stand for in this type resolver. |
| * |
| * @param formal the array of types to resolve |
| * @return a resolved type |
| */ |
| private Type resolve(Type formal) { |
| if (formal instanceof Class) { |
| return formal; |
| } |
| if (formal instanceof GenericArrayType) { |
| Type comp = ((GenericArrayType)formal).getGenericComponentType(); |
| comp = resolve(comp); |
| return (comp instanceof Class) |
| ? Array.newInstance((Class<?>)comp, 0).getClass() |
| : GenericArrayTypeImpl.make(comp); |
| } |
| if (formal instanceof ParameterizedType) { |
| ParameterizedType fpt = (ParameterizedType)formal; |
| Type[] actuals = resolve(fpt.getActualTypeArguments()); |
| return ParameterizedTypeImpl.make( |
| (Class<?>)fpt.getRawType(), actuals, fpt.getOwnerType()); |
| } |
| if (formal instanceof WildcardType) { |
| WildcardType fwt = (WildcardType)formal; |
| Type[] upper = resolve(fwt.getUpperBounds()); |
| Type[] lower = resolve(fwt.getLowerBounds()); |
| return new WildcardTypeImpl(upper, lower); |
| } |
| if (!(formal instanceof TypeVariable)) { |
| throw new IllegalArgumentException("Bad Type kind: " + formal.getClass()); |
| } |
| Type actual = this.map.get((TypeVariable) formal); |
| if (actual == null || actual.equals(formal)) { |
| return formal; |
| } |
| actual = fixGenericArray(actual); |
| return resolve(actual); |
| // A variable can be bound to another variable that is itself bound |
| // to something. For example, given: |
| // class Super<T> {...} |
| // class Mid<X> extends Super<T> {...} |
| // class Sub extends Mid<String> |
| // the variable T is bound to X, which is in turn bound to String. |
| // So if we have to resolve T, we need the tail recursion here. |
| } |
| |
| /** |
| * Replaces all formal types in the given array |
| * with the types they stand for in this type resolver. |
| * |
| * @param formals the array of types to resolve |
| * @return an array of resolved types |
| * |
| * @see #resolve(Type) |
| */ |
| private Type[] resolve(Type[] formals) { |
| int length = formals.length; |
| Type[] actuals = new Type[length]; |
| for (int i = 0; i < length; i++) { |
| actuals[i] = resolve(formals[i]); |
| } |
| return actuals; |
| } |
| |
| /** |
| * Replaces a {@link GenericArrayType GenericArrayType} |
| * with plain array class where it is possible. |
| * Bug <a href="http://bugs.sun.com/view_bug.do?bug_id=5041784">5041784</a> |
| * is that arrays of non-generic type sometimes show up |
| * as {@link GenericArrayType GenericArrayType} when using reflection. |
| * For example, a {@code String[]} might show up |
| * as a {@link GenericArrayType GenericArrayType} |
| * where {@link GenericArrayType#getGenericComponentType getGenericComponentType} |
| * is {@code String.class}. This violates the specification, |
| * which says that {@link GenericArrayType GenericArrayType} |
| * is used when the component type is a type variable or parameterized type. |
| * We fit the specification here. |
| * |
| * @param type the type to fix |
| * @return a corresponding type for the generic array type, |
| * or the same type as {@code type} |
| */ |
| private static Type fixGenericArray(Type type) { |
| if (type instanceof GenericArrayType) { |
| Type comp = ((GenericArrayType)type).getGenericComponentType(); |
| comp = fixGenericArray(comp); |
| if (comp instanceof Class) { |
| return Array.newInstance((Class<?>)comp, 0).getClass(); |
| } |
| } |
| return type; |
| } |
| |
| /** |
| * Replaces a {@link Class Class} with type parameters |
| * with a {@link ParameterizedType ParameterizedType} |
| * where every parameter is bound to itself. |
| * When calling {@link #resolveInClass} in the context of {@code inClass}, |
| * we can't just pass {@code inClass} as the {@code actual} parameter, |
| * because if {@code inClass} has type parameters |
| * that would be interpreted as accessing the raw type, |
| * so we would get unwanted erasure. |
| * This is why we bind each parameter to itself. |
| * If {@code inClass} does have type parameters and has methods |
| * where those parameters appear in the return type or argument types, |
| * we will correctly leave those types alone. |
| * |
| * @param inClass the base class used to resolve |
| * @return a parameterized type for the class, |
| * or the same class as {@code inClass} |
| */ |
| private static Type getActualType(Class<?> inClass) { |
| Type[] params = inClass.getTypeParameters(); |
| return (params.length == 0) |
| ? inClass |
| : ParameterizedTypeImpl.make( |
| inClass, params, inClass.getEnclosingClass()); |
| } |
| } |