001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.harmony.lang.reflect.support;
019:
020: import java.lang.reflect.GenericDeclaration;
021: import java.lang.reflect.Field;
022: import java.lang.reflect.Method;
023: import java.lang.reflect.Constructor;
024: import java.lang.reflect.TypeVariable;
025: import org.apache.harmony.lang.reflect.parser.InterimParameterizedType;
026: import org.apache.harmony.lang.reflect.repository.TypeVariableRepository;
027:
028: import org.apache.harmony.lang.reflect.parser.*;
029:
030: /**
031: * @author Serguei S. Zapreyev
032: * @version $Revision: 1.1.2.1 $
033: */
034:
035: /**
036: * Finder provides kinds of finding.
037: */
038:
039: /*
040: * ------------------------------------------------------------------------------------------------
041: * TODO list:
042: * 1. Maybe, the work with TypeVariableRepository (at least in this class) will be removed at all
043: * if it will be so inefficient as now (see the marked on left by /STARSTAR/ code introduced on Junuary 25, 2006
044: * ------------------------------------------------------------------------------------------------
045: */
046: public final class AuxiliaryFinder {
047:
048: /**
049: * This method returns the generic class declaration which a parameterized type is derived from.
050: *
051: * @param fldType a parsered information produced from a parameterized type signature.
052: * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search
053: * of a type variable declaration place.
054: * @return the found generic declaration for this type variable definition or null
055: * if a generic declaration for this type variable does not exist at all.
056: */
057: public static Class findGenericClassDeclarationForParameterizedType(
058: InterimParameterizedType fldType, Object startPoint)
059: throws ClassNotFoundException {
060: Class klass = null;
061: if ((klass = verifyParameterizedType(fldType, startPoint)) != null)
062: return klass;
063: //############################################################################################################################################
064: // The below fragment seems not to work after verifyParameterizedType implementation and the just above code line insertion
065: // but it should be retained until being 100% aware (just though the incorrect basing on $ is used here):
066: //FRAGMENT START V
067: InterimType ownerType = fldType.ownerType;
068: String binaryClassName = null;
069: String tmp = fldType.rawType.classTypeName.substring(1)
070: .replace('/', '.'); // cut the first "L" (reference symbol) and change "/" by "."
071: int ind;
072: if ((ind = tmp.lastIndexOf('$')) != -1) {
073: binaryClassName = tmp.substring(ind + 1);
074: } else {
075: binaryClassName = tmp;
076: }
077: while (ownerType != null
078: && ownerType instanceof InterimParameterizedType) {
079: tmp = ((InterimParameterizedType) ownerType).rawType.classTypeName
080: .substring(1).replace('/', '.'); // cut the first "L" (reference symbol) and change "/" by "."
081: if ((ind = tmp.lastIndexOf('$')) != -1) {
082: tmp = tmp.substring(ind + 1);
083: } else {
084: }
085: binaryClassName = tmp + "$" + binaryClassName;
086: ownerType = ((InterimParameterizedType) ownerType).ownerType;
087: }
088: if (ownerType != null && ownerType instanceof InterimClassType) {
089: tmp = ((InterimClassType) ownerType).classTypeName
090: .substring(1).replace('/', '.'); // cut the first "L" (reference symbol) and change "/" by "."
091: binaryClassName = tmp + "$" + binaryClassName;
092: } else if (ownerType != null) { // BUG
093: int i = 0, j = 1;
094: i = j / i;
095: }
096: klass = AuxiliaryLoader.findClass(binaryClassName, startPoint); // XXX: should we propagate the class loader of initial user's request (Field.getGenericType()) or use this one?
097: return klass; //it may be null
098: //FRAGMENT FINISH ^
099: //############################################################################################################################################
100: }
101:
102: /**
103: * This method returns generic declaration where a type variable is defined in.
104: *
105: * @param typeVariableName a name of a type variable.
106: * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search
107: * of a type variable declaration place.
108: * @return the found generic declaration for this type variable definition or null
109: * if a generic declaration for this type variable does not exist at all.
110: */
111: public static GenericDeclaration findGenericDeclarationForTypeVariable(
112: String typeVariableName, Object startPoint) {
113: // XXX: redesign after debugging to join all the common places below:
114: if (startPoint instanceof Field) {
115: Class klass = ((Field) startPoint).getDeclaringClass();
116: TypeVariable va[] = klass.getTypeParameters();
117: if (va != null) {
118: for (int i = 0; i < va.length; i++) {
119: if (va[i].getName().equals(typeVariableName)) {
120: return (GenericDeclaration) klass;
121: }
122: }
123: } else {
124: while (klass != null) {
125: klass = klass.getDeclaringClass();
126: va = klass.getTypeParameters();
127: if (va != null) {
128: for (int i = 0; i < va.length; i++) {
129: if (va[i].getName()
130: .equals(typeVariableName)) {
131: return (GenericDeclaration) klass;
132: }
133: }
134: }
135: }
136: return null;
137: }
138: } else if (startPoint instanceof Method
139: || startPoint instanceof Constructor) {
140: TypeVariable va[] = (startPoint instanceof Method ? (Method) startPoint
141: : (Constructor) startPoint).getTypeParameters();
142: if (va != null) {
143: for (int i = 0; i < va.length; i++) {
144: if (va[i].getName().equals(typeVariableName)) {
145: return (GenericDeclaration) startPoint;
146: }
147: }
148: } else {
149: Class klass = (startPoint instanceof Method) ? ((Method) startPoint)
150: .getDeclaringClass()
151: : ((Constructor) startPoint)
152: .getDeclaringClass();
153: va = klass.getTypeParameters();
154: if (va != null) {
155: for (int i = 0; i < va.length; i++) {
156: if (va[i].getName().equals(typeVariableName)) {
157: return (GenericDeclaration) klass;
158: }
159: }
160: } else {
161: while (klass != null) {
162: klass = klass.getDeclaringClass();
163: va = klass.getTypeParameters();
164: if (va != null) {
165: for (int i = 0; i < va.length; i++) {
166: if (va[i].getName().equals(
167: typeVariableName)) {
168: return (GenericDeclaration) klass;
169: }
170: }
171: }
172: }
173: return null;
174: }
175: }
176: } else if (startPoint instanceof Class) {
177: Class klass = (Class) startPoint;
178: TypeVariable va[] = klass.getTypeParameters();
179: if (va != null) {
180: for (int i = 0; i < va.length; i++) {
181: if (va[i].getName().equals(typeVariableName)) {
182: return (GenericDeclaration) klass;
183: }
184: }
185: } else {
186: while (klass != null) {
187: klass = klass.getDeclaringClass();
188: va = klass.getTypeParameters();
189: if (va != null) {
190: for (int i = 0; i < va.length; i++) {
191: if (va[i].getName()
192: .equals(typeVariableName)) {
193: return (GenericDeclaration) klass;
194: }
195: }
196: }
197: }
198: return null;
199: }
200: }
201: return null;
202: }
203:
204: /**
205: * This method returns TypeVariable corresponding to the name of type variable in the current scope.
206: *
207: * @param typeVariableName a name of a type variable.
208: * @param startPoint an instance of the Class, Method, Constructor or Field type to start the search
209: * of a type variable declaration place.
210: * @return the found type variable.
211: */
212: public static TypeVariable findTypeVariable(
213: String typeVariableName, Object startPoint) {
214: // XXX: redesign after debugging to join all the common places below:
215: if (startPoint instanceof Field) {
216: Class klass = ((Field) startPoint).getDeclaringClass();
217: TypeVariable va[] = klass.getTypeParameters();
218: if (va != null) {
219: for (int i = 0; i < va.length; i++) {
220: if (va[i].getName().equals(typeVariableName)) {
221: /**/if (TypeVariableRepository
222: .findTypeVariable(typeVariableName,
223: klass) == null) { // Yes, it may be very inefficient now (for example, klass.getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but
224: /**/// after all the TV-repository's functionality implementation
225: /**/// it will be time to improvement.
226: /**/TypeVariableRepository
227: .registerTypeVariable(va[i],
228: typeVariableName, klass); // So, it was placed in repository just after an TV-instance creation but then
229: /**/// it was removed (since we did not find it into the invoking method of this method look there at line with
230: /**/// TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition).
231: /**/// As a consequence, we should reregistry it again as long as it become so popular again
232: /**/}
233: return va[i];
234: }
235: }
236: }
237: while (klass != null) {
238: klass = klass.getDeclaringClass();
239: /**/java.lang.reflect.TypeVariable variable = TypeVariableRepository
240: .findTypeVariable(typeVariableName, klass);
241: /**/if (variable != null) {
242: /**/return variable;
243: /**/}
244: va = klass.getTypeParameters();
245: if (va != null) {
246: for (int i = 0; i < va.length; i++) {
247: if (va[i].getName().equals(typeVariableName)) {
248: /**/if (TypeVariableRepository
249: .findTypeVariable(typeVariableName,
250: klass) == null) { // Yes, it may be very inefficient now (for example, klass.getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but
251: /**/// after all the TV-repository's functionality implementation
252: /**/// it will be time to improvement.
253: /**/TypeVariableRepository
254: .registerTypeVariable(va[i],
255: typeVariableName, klass); // So, it was placed in repository just after an TV-instance creation but then
256: /**/// it was removed (since we did not find it into the invoking method of this method look there at line with
257: /**/// TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition).
258: /**/// As a consequence, we should reregistry it again as long as it become so popular again
259: /**/}
260: return va[i];
261: }
262: }
263: }
264: }
265: return null;
266: } else if (startPoint instanceof Method
267: || startPoint instanceof Constructor) {
268: TypeVariable va[];
269: if (startPoint instanceof Method) {
270: va = ((Method) startPoint).getTypeParameters();
271: } else {
272: va = ((Constructor) startPoint).getTypeParameters();
273: }
274: if (va != null) {
275: for (int i = 0; i < va.length; i++) {
276: if (va[i].getName().equals(
277: transform(typeVariableName))) {
278: /**/if (TypeVariableRepository
279: .findTypeVariable(typeVariableName,
280: startPoint) == null) { // Yes, it may be very inefficient now (for example, ((Constructor/Method)startPoint).getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but
281: /**/// after all the TV-repository's functionality implementation
282: /**/// it will be time to improvement.
283: /**/TypeVariableRepository
284: .registerTypeVariable(va[i],
285: typeVariableName,
286: startPoint); // So, it was placed in repository just after an TV-instance creation but then
287: /**/// it was removed (since we did not find it into the invoking method of this method look there at line with
288: /**/// TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition).
289: /**/// As a consequence, we should reregistry it again as long as it become so popular again
290: /**/}
291: return va[i];
292: }
293: }
294: }
295: Class klass = (startPoint instanceof Method) ? ((Method) startPoint)
296: .getDeclaringClass()
297: : ((Constructor) startPoint).getDeclaringClass();
298: if (startPoint instanceof Method) {
299: klass = ((Method) startPoint).getDeclaringClass();
300: } else {
301: klass = ((Constructor) startPoint).getDeclaringClass();
302: }
303: /**/java.lang.reflect.TypeVariable variable = TypeVariableRepository
304: .findTypeVariable(typeVariableName, klass);
305: /**/if (variable != null) {
306: /**/return variable;
307: /**/}
308: va = klass.getTypeParameters();
309: if (va != null) {
310: for (int i = 0; i < va.length; i++) {
311: if (va[i].getName().equals(
312: transform(typeVariableName))) {
313: /**/if (TypeVariableRepository
314: .findTypeVariable(typeVariableName,
315: klass) == null) { // Yes, it may be very inefficient now (for example, klass.getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but
316: /**/// after all the TV-repository's functionality implementation
317: /**/// it will be time to improvement.
318: /**/TypeVariableRepository
319: .registerTypeVariable(va[i],
320: typeVariableName, klass); // So, it was placed in repository just after an TV-instance creation but then
321: /**/// it was removed (since we did not find it into the invoking method of this method look there at line with
322: /**/// TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition).
323: /**/// As a consequence, we should reregistry it again as long as it become so popular again
324: /**/}
325: return va[i];
326: }
327: }
328: }
329: while (klass != null) {
330: klass = klass.getDeclaringClass();
331: /**/variable = TypeVariableRepository
332: .findTypeVariable(typeVariableName, klass);
333: /**/if (variable != null) {
334: /**/return variable;
335: /**/}
336: va = klass.getTypeParameters();
337: if (va != null) {
338: for (int i = 0; i < va.length; i++) {
339: if (va[i].getName().equals(
340: transform(typeVariableName))) {
341: /**/if (TypeVariableRepository
342: .findTypeVariable(typeVariableName,
343: klass) == null) { // Yes, it may be very inefficient now (for example, klass.getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but
344: /**/// after all the TV-repository's functionality implementation
345: /**/// it will be time to improvement.
346: /**/TypeVariableRepository
347: .registerTypeVariable(va[i],
348: typeVariableName, klass); // So, it was placed in repository just after an TV-instance creation but then
349: /**/// it was removed (since we did not find it into the invoking method of this method look there at line with
350: /**/// TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition).
351: /**/// As a consequence, we should reregistry it again as long as it become so popular again
352: /**/}
353: return va[i];
354: }
355: }
356: }
357: }
358: return null;
359: } else if (startPoint instanceof Class) {
360: Class klass = (Class) startPoint;
361: TypeVariable va[] = klass.getTypeParameters();
362: if (va != null) {
363: for (int i = 0; i < va.length; i++) {
364: if (va[i].getName().equals(typeVariableName)) {
365: /**/if (TypeVariableRepository
366: .findTypeVariable(typeVariableName,
367: klass) == null) { // Yes, it may be very inefficient now (for example, klass.getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but
368: /**/// after all the TV-repository's functionality implementation
369: /**/// it will be time to improvement.
370: /**/TypeVariableRepository
371: .registerTypeVariable(va[i],
372: typeVariableName, klass); // So, it was placed in repository just after an TV-instance creation but then
373: /**/// it was removed (since we did not find it into the invoking method of this method look there at line with
374: /**/// TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition).
375: /**/// As a consequence, we should reregistry it again as long as it become so popular again
376: /**/}
377: return va[i];
378: }
379: }
380: }
381: while ((klass = klass.getDeclaringClass()) != null) {
382: /**/java.lang.reflect.TypeVariable variable = TypeVariableRepository
383: .findTypeVariable(typeVariableName, klass);
384: /**/if (variable != null) {
385: /**/return variable;
386: /**/}
387: va = klass.getTypeParameters();
388: if (va != null) {
389: for (int i = 0; i < va.length; i++) {
390: if (va[i].getName().equals(typeVariableName)) {
391: /**/if (TypeVariableRepository
392: .findTypeVariable(typeVariableName,
393: klass) == null) { // Yes, it may be very inefficient now (for example, klass.getTypeParameters() invokation above can just registry a TV but we need to recheck it in this line) but
394: /**/// after all the TV-repository's functionality implementation
395: /**/// it will be time to improvement.
396: /**/TypeVariableRepository
397: .registerTypeVariable(va[i],
398: typeVariableName, klass); // So, it was placed in repository just after an TV-instance creation but then
399: /**/// it was removed (since we did not find it into the invoking method of this method look there at line with
400: /**/// TypeVariableRepository.findTypeVariable(...) method invokation and also we did not find it in just above if-condition).
401: /**/// As a consequence, we should reregistry it again as long as it become so popular again
402: /**/}
403: return va[i];
404: }
405: }
406: }
407: }
408: return null;
409: }
410: return null;
411: }
412:
413: /**
414: * This method transforms String with Utf8 to String without Utf8.
415: *
416: * @return the transformed string.
417: */
418: public static String transform(String ini) {
419: int ind;
420: if ((ind = ini.indexOf("\\")) != -1) {
421: String res = ind == 0 ? "" : ini.substring(0, ind);
422: String di1 = ini.substring(ind + 2, ind + 2 + 2); // to ommit \0
423: String di2 = ini.substring(ind + 6, ind + 6 + 2); // to ommit the following \0
424: String di3;
425: if (Integer.parseInt(di1.substring(0, 1), 16) < 0xE) { // range 0x0080 - 0x07ff , for example: \0ce\091
426: res = res
427: + new String(
428: new char[] { (char) (((Integer
429: .parseInt(di1, 16) & 0x1f) << 6) + (Integer
430: .parseInt(di2, 16) & 0x3f)) });
431: return res + transform(ini.substring(ind + 8));
432: } else if (Integer.parseInt(di1.substring(0, 1), 16) < 0xd800
433: || Integer.parseInt(di1.substring(0, 1), 16) > 0xdfff) { // range 0x0800 - 0xffff , for example: \0ef\0bf\08f
434: di3 = ini.substring(ind + 10, ind + 10 + 2); // to ommit the following \0
435: res = res
436: + new String(
437: new char[] { (char) (((Integer
438: .parseInt(di1, 16) & 0xf) << 12)
439: + ((Integer.parseInt(di2, 16) & 0x3f) << 6) + (Integer
440: .parseInt(di3, 16) & 0x3f)) });
441: return res + transform(ini.substring(ind + 12));
442: } else { // range 0x10000 - 0x10FFFF (high-surrogates range = 0xd800-0xdbff; low-surrogates range = 0xdc00-0xdfff; ) , for example: \0ed\0a0\0b5\0ed\0be\0af
443: di3 = ini.substring(ind + 10, ind + 10 + 2); // to ommit the following \0
444: String di5 = ini.substring(ind + 18, ind + 18 + 2); // to ommit the following \0
445: String di6 = ini.substring(ind + 22, ind + 22 + 2); // to ommit the following \0
446: res = res
447: + new String(
448: new char[] { (char) ((((Integer
449: .parseInt(di2, 16) & 0xf) + ((Integer
450: .parseInt(di2, 16) & 0xf) != 0 ? 1
451: : 0)) << 16)
452: + ((Integer.parseInt(di3, 16) & 0x3f) << 10)
453: + ((Integer.parseInt(di5, 16) & 0xf) << 6) + (Integer
454: .parseInt(di6, 16) & 0x3f)) });
455: return res + transform(ini.substring(ind + 24));
456: }
457: }
458: return ini;
459: }
460:
461: /**
462: * To use in findGenericClassDeclarationForParameterizedType method.
463: */
464: private static Class verifyParameterizedType(
465: InterimParameterizedType fldType, Object startPoint)
466: throws ClassNotFoundException {
467: Class klass = AuxiliaryLoader.findClass(
468: fldType.rawType.classTypeName.substring(1).replace('/',
469: '.')/*fldType.rawType.classTypeName*/,
470: startPoint);
471: if (fldType.currentClauseName != null
472: && fldType.currentClauseName.length() > 0) {
473: return klass; // has been verified
474: }
475:
476: if (!klass.isLocalClass() && !klass.isMemberClass()) {
477: return klass;
478: }
479: String snm = klass.getSimpleName(); // It must not be anonymous because it is the parameterised one.
480: int i = fldType.rawType.classTypeName.lastIndexOf("$" + snm);
481: if (i == -1) {
482: return klass;
483: }
484: String rtnm = fldType.rawType.classTypeName.substring(0, i);
485: InterimParameterizedType newPT = null;
486:
487: if (fldType.ownerType == null) {
488: try {
489: if (AuxiliaryLoader.findClass(rtnm.substring(1)
490: .replace('/', '.'), startPoint) != null) {
491: // telescoping a final unit:
492: InterimClassType newCT = new InterimClassType();
493: newCT.classTypeName = rtnm;
494: fldType.ownerType = (InterimType) newCT;
495: }
496: } catch (ClassNotFoundException _) {
497: return null;
498: }
499: return klass;
500: } else {
501: if (!rtnm
502: .equals((fldType.ownerType instanceof InterimParameterizedType ? ((InterimParameterizedType) fldType.ownerType).rawType.classTypeName
503: : ((InterimClassType) fldType.ownerType).classTypeName))) {
504: try {
505: if (AuxiliaryLoader.findClass(rtnm.substring(1)
506: .replace('/', '.'), startPoint) != null) {
507: // telescoping an intermediate unit:
508: newPT = new InterimParameterizedType();
509: /* ### */newPT.signature = fldType.signature
510: .substring(0, fldType.signature
511: .lastIndexOf("$" + snm)); //XXX: ???
512: newPT.currentClauseName = snm;
513: newPT.parameters = null;
514: newPT.rawType = new InterimClassType();
515: newPT.rawType.classTypeName = rtnm;
516: newPT.ownerType = fldType.ownerType;
517: verifyParameterizedType(newPT, startPoint);
518: fldType.ownerType = newPT;
519: }
520: } catch (ClassNotFoundException _) {
521: return null;
522: }
523: }
524: return klass;
525: }
526: }
527: }
|