History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/com/sun/beans/TypeResolver.java (1 of 18352 files). Show all

Unified · Split

java/pkg/com/sun/beans/TypeResolver.java+410−0
@@ -0,0 +1,410 @@
1+/*
2+ * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
8+ * particular file as subject to the "Classpath" exception as provided
9+ * by Oracle in the LICENSE file that accompanied this code.
10+ *
11+ * This code is distributed in the hope that it will be useful, but WITHOUT
12+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14+ * version 2 for more details (a copy is included in the LICENSE file that
15+ * accompanied this code).
16+ *
17+ * You should have received a copy of the GNU General Public License version
18+ * 2 along with this work; if not, write to the Free Software Foundation,
19+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20+ *
21+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22+ * or visit www.oracle.com if you need additional information or have any
23+ * questions.
24+ */
25+package com.sun.beans;
26+
27+import java.lang.reflect.Array;
28+import java.lang.reflect.GenericArrayType;
29+import java.lang.reflect.ParameterizedType;
30+import java.lang.reflect.Type;
31+import java.lang.reflect.TypeVariable;
32+import java.lang.reflect.WildcardType;
33+import java.util.HashMap;
34+import java.util.Map;
35+
36+import sun.reflect.generics.reflectiveObjects.GenericArrayTypeImpl;
37+import sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl;
38+
39+/**
40+ * This is utility class to resolve types.
41+ *
42+ * @since 1.7
43+ *
44+ * @author Eamonn McManus
45+ * @author Sergey Malenkov
46+ */
47+public final class TypeResolver {
48+ /**
49+ * Replaces the given {@code type} in an inherited method
50+ * with the actual type it has in the given {@code inClass}.
51+ *
52+ * <p>Although type parameters are not inherited by subclasses in the Java
53+ * language, they <em>are</em> effectively inherited when using reflection.
54+ * For example, if you declare an interface like this...</p>
55+ *
56+ * <pre>
57+ * public interface StringToIntMap extends Map&lt;String,Integer> {}
58+ * </pre>
59+ *
60+ * <p>...then StringToIntMap.class.getMethods() will show that it has methods
61+ * like put(K,V) even though StringToIntMap has no type parameters. The K
62+ * and V variables are the ones declared by Map, so
63+ * {@link TypeVariable#getGenericDeclaration()} will return Map.class.</p>
64+ *
65+ * <p>The purpose of this method is to take a Type from a possibly-inherited
66+ * method and replace it with the correct Type for the inheriting class.
67+ * So given parameters of K and StringToIntMap.class in the above example,
68+ * this method will return String.</p>
69+ *
70+ * @param inClass the base class used to resolve
71+ * @param type the type to resolve
72+ * @return a resolved type
73+ *
74+ * @see #getActualType(Class)
75+ * @see #resolve(Type,Type)
76+ */
77+ public static Type resolveInClass(Class<?> inClass, Type type) {
78+ return resolve(getActualType(inClass), type);
79+ }
80+
81+ /**
82+ * Replaces all {@code types} in the given array
83+ * with the actual types they have in the given {@code inClass}.
84+ *
85+ * @param inClass the base class used to resolve
86+ * @param types the array of types to resolve
87+ * @return an array of resolved types
88+ *
89+ * @see #getActualType(Class)
90+ * @see #resolve(Type,Type[])
91+ */
92+ public static Type[] resolveInClass(Class<?> inClass, Type[] types) {
93+ return resolve(getActualType(inClass), types);
94+ }
95+
96+ /**
97+ * Replaces type variables of the given {@code formal} type
98+ * with the types they stand for in the given {@code actual} type.
99+ *
100+ * <p>A ParameterizedType is a class with type parameters, and the values
101+ * of those parameters. For example, Map&lt;K,V> is a generic class, and
102+ * a corresponding ParameterizedType might look like
103+ * Map&lt;K=String,V=Integer>. Given such a ParameterizedType, this method
104+ * will replace K with String, or List&lt;K> with List&ltString;, or
105+ * List&lt;? super K> with List&lt;? super String>.</p>
106+ *
107+ * <p>The {@code actual} argument to this method can also be a Class.
108+ * In this case, either it is equivalent to a ParameterizedType with
109+ * no parameters (for example, Integer.class), or it is equivalent to
110+ * a "raw" ParameterizedType (for example, Map.class). In the latter
111+ * case, every type parameter declared or inherited by the class is replaced
112+ * by its "erasure". For a type parameter declared as &lt;T>, the erasure
113+ * is Object. For a type parameter declared as &lt;T extends Number>,
114+ * the erasure is Number.</p>
115+ *
116+ * <p>Although type parameters are not inherited by subclasses in the Java
117+ * language, they <em>are</em> effectively inherited when using reflection.
118+ * For example, if you declare an interface like this...</p>
119+ *
120+ * <pre>
121+ * public interface StringToIntMap extends Map&lt;String,Integer> {}
122+ * </pre>
123+ *
124+ * <p>...then StringToIntMap.class.getMethods() will show that it has methods
125+ * like put(K,V) even though StringToIntMap has no type parameters. The K
126+ * and V variables are the ones declared by Map, so
127+ * {@link TypeVariable#getGenericDeclaration()} will return {@link Map Map.class}.</p>
128+ *
129+ * <p>For this reason, this method replaces inherited type parameters too.
130+ * Therefore if this method is called with {@code actual} being
131+ * StringToIntMap.class and {@code formal} being the K from Map,
132+ * it will return {@link String String.class}.</p>
133+ *
134+ * <p>In the case where {@code actual} is a "raw" ParameterizedType, the
135+ * inherited type parameters will also be replaced by their erasures.
136+ * The erasure of a Class is the Class itself, so a "raw" subinterface of
137+ * StringToIntMap will still show the K from Map as String.class. But
138+ * in a case like this...
139+ *
140+ * <pre>
141+ * public interface StringToIntListMap extends Map&lt;String,List&lt;Integer>> {}
142+ * public interface RawStringToIntListMap extends StringToIntListMap {}
143+ * </pre>
144+ *
145+ * <p>...the V inherited from Map will show up as List&lt;Integer> in
146+ * StringToIntListMap, but as plain List in RawStringToIntListMap.</p>
147+ *
148+ * @param actual the type that supplies bindings for type variables
149+ * @param formal the type where occurrences of the variables
150+ * in {@code actual} will be replaced by the corresponding bound values
151+ * @return a resolved type
152+ *
153+ * @see #TypeResolver(Type)
154+ * @see #resolve(Type)
155+ */
156+ public static Type resolve(Type actual, Type formal) {
157+ return new TypeResolver(actual).resolve(formal);
158+ }
159+
160+ /**
161+ * Replaces type variables of all formal types in the given array
162+ * with the types they stand for in the given {@code actual} type.
163+ *
164+ * @param actual the type that supplies bindings for type variables
165+ * @param formals the array of types to resolve
166+ * @return an array of resolved types
167+ *
168+ * @see #TypeResolver(Type)
169+ * @see #resolve(Type[])
170+ */
171+ public static Type[] resolve(Type actual, Type[] formals) {
172+ return new TypeResolver(actual).resolve(formals);
173+ }
174+
175+ /**
176+ * Converts the given {@code type} to the corresponding class.
177+ * This method implements the concept of type erasure,
178+ * that is described in section 4.6 of
179+ * <cite>The Java&trade; Language Specification</cite>.
180+ *
181+ * @param type the array of types to convert
182+ * @return a corresponding class
183+ */
184+ public static Class<?> erase(Type type) {
185+ if (type instanceof Class) {
186+ return (Class<?>) type;
187+ }
188+ if (type instanceof ParameterizedType) {
189+ ParameterizedType pt = (ParameterizedType) type;
190+ return (Class<?>) pt.getRawType();
191+ }
192+ if (type instanceof TypeVariable) {
193+ TypeVariable tv = (TypeVariable)type;
194+ Type[] bounds = tv.getBounds();
195+ return (0 < bounds.length)
196+ ? 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)
203+ ? erase(bounds[0])
204+ : Object.class;
205+ }
206+ if (type instanceof GenericArrayType) {
207+ GenericArrayType gat = (GenericArrayType)type;
208+ return Array.newInstance(erase(gat.getGenericComponentType()), 0).getClass();
209+ }
210+ throw new IllegalArgumentException("Unknown Type kind: " + type.getClass());
211+ }
212+
213+ /**
214+ * Converts all {@code types} in the given array
215+ * to the corresponding classes.
216+ *
217+ * @param types the array of types to convert
218+ * @return an array of corresponding classes
219+ *
220+ * @see #erase(Type)
221+ */
222+ public static Class[] erase(Type[] types) {
223+ int length = types.length;
224+ Class[] classes = new Class[length];
225+ for (int i = 0; i < length; i++) {
226+ classes[i] = TypeResolver.erase(types[i]);
227+ }
228+ return classes;
229+ }
230+
231+
232+ private final Map<TypeVariable<?>, Type> map
233+ = new HashMap<TypeVariable<?>, Type>();
234+
235+ /**
236+ * Constructs the type resolver for the given actual type.
237+ *
238+ * @param actual the type that supplies bindings for type variables
239+ *
240+ * @see #prepare(Type)
241+ */
242+ private TypeResolver(Type actual) {
243+ prepare(actual);
244+ }
245+
246+ /**
247+ * Fills the map from type parameters
248+ * to types as seen by the given {@code type}.
249+ * The method is recursive because the {@code type}
250+ * inherits mappings from its parent classes and interfaces.
251+ * The {@code type} can be either a {@link Class Class}
252+ * or a {@link ParameterizedType ParameterizedType}.
253+ * If it is a {@link Class Class}, it is either equivalent
254+ * to a {@link ParameterizedType ParameterizedType} with no parameters,
255+ * or it represents the erasure of a {@link ParameterizedType ParameterizedType}.
256+ *
257+ * @param type the next type in the hierarchy
258+ */
259+ private void prepare(Type type) {
260+ Class<?> raw = (Class<?>)((type instanceof Class<?>)
261+ ? type
262+ : ((ParameterizedType)type).getRawType());
263+
264+ TypeVariable<?>[] formals = raw.getTypeParameters();
265+
266+ Type[] actuals = (type instanceof Class<?>)
267+ ? formals
268+ : ((ParameterizedType)type).getActualTypeArguments();
269+
270+ assert formals.length == actuals.length;
271+ for (int i = 0; i < formals.length; i++) {
272+ this.map.put(formals[i], actuals[i]);
273+ }
274+ Type gSuperclass = raw.getGenericSuperclass();
275+ if (gSuperclass != null) {
276+ prepare(gSuperclass);
277+ }
278+ for (Type gInterface : raw.getGenericInterfaces()) {
279+ prepare(gInterface);
280+ }
281+ // If type is the raw version of a parameterized class, we type-erase
282+ // all of its type variables, including inherited ones.
283+ if (type instanceof Class<?> && formals.length > 0) {
284+ for (Map.Entry<TypeVariable<?>, Type> entry : this.map.entrySet()) {
285+ entry.setValue(erase(entry.getValue()));
286+ }
287+ }
288+ }
289+
290+ /**
291+ * Replaces the given {@code formal} type
292+ * with the type it stand for in this type resolver.
293+ *
294+ * @param formal the array of types to resolve
295+ * @return a resolved type
296+ */
297+ private Type resolve(Type formal) {
298+ if (formal instanceof Class) {
299+ return formal;
300+ }
301+ if (formal instanceof GenericArrayType) {
302+ Type comp = ((GenericArrayType)formal).getGenericComponentType();
303+ comp = resolve(comp);
304+ return (comp instanceof Class)
305+ ? Array.newInstance((Class<?>)comp, 0).getClass()
306+ : GenericArrayTypeImpl.make(comp);
307+ }
308+ if (formal instanceof ParameterizedType) {
309+ ParameterizedType fpt = (ParameterizedType)formal;
310+ Type[] actuals = resolve(fpt.getActualTypeArguments());
311+ return ParameterizedTypeImpl.make(
312+ (Class<?>)fpt.getRawType(), actuals, fpt.getOwnerType());
313+ }
314+ if (formal instanceof WildcardType) {
315+ WildcardType fwt = (WildcardType)formal;
316+ Type[] upper = resolve(fwt.getUpperBounds());
317+ Type[] lower = resolve(fwt.getLowerBounds());
318+ return new WildcardTypeImpl(upper, lower);
319+ }
320+ if (!(formal instanceof TypeVariable)) {
321+ throw new IllegalArgumentException("Bad Type kind: " + 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/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).getGenericComponentType();
377+ comp = fixGenericArray(comp);
378+ if (comp instanceof Class) {
379+ return Array.newInstance((Class<?>)comp, 0).getClass();
380+ }
381+ }
382+ return type;
383+ }
384+
385+ /**
386+ * Replaces a {@link Class Class} with type parameters
387+ * with a {@link ParameterizedType ParameterizedType}
388+ * where every parameter is bound to itself.
389+ * When calling {@link #resolveInClass} in the context of {@code inClass},
390+ * we can't just pass {@code inClass} as the {@code actual} parameter,
391+ * because if {@code inClass} has type parameters
392+ * that would be interpreted as accessing the raw type,
393+ * so we would get unwanted erasure.
394+ * This is why we bind each parameter to itself.
395+ * If {@code inClass} does have type parameters and has methods
396+ * where those parameters appear in the return type or argument types,
397+ * we will correctly leave those types alone.
398+ *
399+ * @param inClass the base class used to resolve
400+ * @return a parameterized type for the class,
401+ * or the same class as {@code inClass}
402+ */
403+ private static Type getActualType(Class<?> inClass) {
404+ Type[] params = inClass.getTypeParameters();
405+ return (params.length == 0)
406+ ? inClass
407+ : ParameterizedTypeImpl.make(
408+ inClass, params, inClass.getEnclosingClass());
409+ }
410+}