1 | package net.sourceforge.retroweaver.runtime.java.lang.reflect; |
2 | |
3 | import java.io.IOException; |
4 | import java.io.InputStream; |
5 | import java.lang.reflect.Constructor; |
6 | import java.lang.reflect.Field; |
7 | import java.lang.reflect.Method; |
8 | import java.util.HashMap; |
9 | import java.util.HashSet; |
10 | import java.util.LinkedList; |
11 | import java.util.Map; |
12 | import java.util.Set; |
13 | import java.util.Stack; |
14 | |
15 | import net.sourceforge.retroweaver.runtime.java.lang.TypeNotPresentException; |
16 | import net.sourceforge.retroweaver.runtime.java.lang.annotation.AIB; |
17 | |
18 | import org.objectweb.asm.AnnotationVisitor; |
19 | import org.objectweb.asm.Attribute; |
20 | import org.objectweb.asm.ClassReader; |
21 | import org.objectweb.asm.ClassVisitor; |
22 | import org.objectweb.asm.FieldVisitor; |
23 | import org.objectweb.asm.MethodVisitor; |
24 | import org.objectweb.asm.Opcodes; |
25 | import org.objectweb.asm.signature.SignatureReader; |
26 | import org.objectweb.asm.signature.SignatureVisitor; |
27 | |
28 | public class ReflectionDescriptor implements ClassVisitor { |
29 | |
30 | private static final boolean DEBUG = false; |
31 | |
32 | private static final Map<Class, ReflectionDescriptor> descriptors = new HashMap<Class, ReflectionDescriptor>(); |
33 | |
34 | public static ReflectionDescriptor getReflectionDescriptor(Class class_) { |
35 | synchronized (descriptors) { |
36 | ReflectionDescriptor d = descriptors.get(class_); |
37 | if (d == null) { |
38 | d = new ReflectionDescriptor(class_); |
39 | descriptors.put(class_, d); |
40 | if (DEBUG) d.debugMessage("Adding descriptor"); |
41 | } |
42 | return d; |
43 | } |
44 | } |
45 | |
46 | private final Class class_; |
47 | |
48 | private ReflectionDescriptor(Class class_) { |
49 | this.class_ = class_; |
50 | String name = class_.getName(); |
51 | |
52 | String resource = "/" + name.replace('.', '/') + ".class"; |
53 | if (DEBUG) System.out.println("Reading class file: " + resource); |
54 | InputStream classStream = class_.getResourceAsStream(resource); |
55 | parseStream(name, classStream); |
56 | } |
57 | |
58 | protected ReflectionDescriptor(String name, InputStream classStream) { |
59 | class_ = null; |
60 | parseStream(name, classStream); |
61 | } |
62 | |
63 | private void parseStream(String name, InputStream classStream) { |
64 | try { |
65 | ClassReader r = new ClassReader(classStream); |
66 | r.accept(this, ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG |
67 | + ClassReader.SKIP_FRAMES); |
68 | |
69 | } catch (IOException e) { |
70 | // Shouldn't generally happen |
71 | throw new TypeNotPresentException( |
72 | "[Retroweaver] Unable to read reflection data for: " + name, e); |
73 | } finally { |
74 | try { |
75 | if (classStream != null) { |
76 | classStream.close(); |
77 | } |
78 | } catch (IOException e) { // NOPMD by xlv |
79 | } |
80 | } |
81 | } |
82 | |
83 | private String internalName; |
84 | |
85 | private String enclosingClassName; |
86 | |
87 | private String enclosingMethodName; |
88 | |
89 | private String enclosingMethodDesc; |
90 | |
91 | private HashMap<String, Integer> fieldAccessTable = new HashMap<String, Integer>(); |
92 | |
93 | private HashMap<String, Integer> methodAccessTable = new HashMap<String, Integer>(); |
94 | |
95 | public String getEnclosingClassName() { |
96 | return enclosingClassName; |
97 | } |
98 | |
99 | public void debugMessage(String msg) { |
100 | System.out.println(msg + |
101 | "\n\tclass: " + class_.getName() + |
102 | "\n\tenclosingClassName: " + enclosingClassName + |
103 | "\n\tenclosingMethodName: " + enclosingMethodName + ' ' + enclosingMethodDesc); |
104 | } |
105 | |
106 | public Class getEnclosingClass() { |
107 | //debugMessage("getEnclosingClass"); |
108 | if (enclosingClassName == null) { |
109 | return null; |
110 | } |
111 | |
112 | try { |
113 | //debugMessage("getEnclosingClass"); |
114 | String name = enclosingClassName.replace('/', '.'); |
115 | Class c = class_.getClassLoader().loadClass(name); |
116 | |
117 | return c; |
118 | } catch (ClassNotFoundException e) { |
119 | return null; |
120 | } |
121 | } |
122 | |
123 | public Method getEnclosingMethod() { |
124 | //debugMessage("getEnclosingMethod"); |
125 | if (enclosingMethodName == null) { |
126 | return null; |
127 | } |
128 | |
129 | return getMethod(getEnclosingClass(), enclosingMethodName, enclosingMethodDesc); |
130 | } |
131 | |
132 | public Constructor getEnclosingConstructor() { |
133 | //debugMessage("getEnclosingMethod"); |
134 | if (enclosingMethodName == null) { |
135 | return null; |
136 | } |
137 | |
138 | return getConstructor(getEnclosingClass(), enclosingMethodDesc); |
139 | } |
140 | |
141 | public boolean testFieldAccess(Field f, int mask) { |
142 | String name = f.getName(); |
143 | return (fieldAccessTable.get(name).intValue() & mask) != 0; |
144 | } |
145 | |
146 | public boolean testMethodAccess(Method m, int mask) { |
147 | String name = m.getName(); |
148 | String desc = org.objectweb.asm.Type.getMethodDescriptor(m); |
149 | return (methodAccessTable.get(name+desc).intValue() & mask) != 0; |
150 | } |
151 | |
152 | public boolean testConstructorAccess(Constructor c, int mask) { |
153 | String name = "<init>"; |
154 | String desc = org.objectweb.asm.Type.getConstructorDescriptor(c); |
155 | return (methodAccessTable.get(name+desc).intValue() & mask) != 0; |
156 | } |
157 | |
158 | private Method getMethod(Class class_, String name, String desc) { |
159 | org.objectweb.asm.Type[] types = org.objectweb.asm.Type.getArgumentTypes(desc); |
160 | |
161 | outer_loop: |
162 | for (Method m : class_.getDeclaredMethods()) { |
163 | final org.objectweb.asm.Type[] methodTypes = org.objectweb.asm.Type.getArgumentTypes(m); |
164 | if (!m.getName().equals(name) |
165 | || methodTypes.length != types.length) { |
166 | continue; |
167 | } |
168 | for (int i = 0; i < types.length; ++i) { |
169 | if (!types[i].equals(methodTypes[i])) { |
170 | continue outer_loop; |
171 | } |
172 | } |
173 | return m; |
174 | } |
175 | return null; |
176 | } |
177 | |
178 | private Constructor getConstructor(Class class_, String desc) { |
179 | org.objectweb.asm.Type[] types = org.objectweb.asm.Type.getArgumentTypes(desc); |
180 | |
181 | outer_loop: |
182 | for (Constructor c : class_.getDeclaredConstructors()) { |
183 | final Class[] constructorTypes = c.getParameterTypes(); |
184 | if (constructorTypes.length != types.length) { |
185 | continue; |
186 | } |
187 | for (int i = 0; i < types.length; ++i) { |
188 | if (!types[i].equals(org.objectweb.asm.Type.getType(constructorTypes[i]))) { |
189 | continue outer_loop; |
190 | } |
191 | } |
192 | return c; |
193 | } |
194 | return null; |
195 | } |
196 | |
197 | private void parseSignature(String signature, boolean isInterface, String superName, String[] interfaces) { |
198 | if (signature == null) { |
199 | typeParameters = new TypeVariable[0]; |
200 | genericSuperclass = superName==null?null:new ClassTypeImpl(superName.replaceAll("/", ".")); |
201 | if (interfaces == null) { |
202 | genericInterfaces = new Type[0]; |
203 | } else { |
204 | genericInterfaces = new Type[interfaces.length]; |
205 | for(int i = 0; i < interfaces.length; i++) { |
206 | genericInterfaces[i] = new ClassTypeImpl(interfaces[i].replaceAll("/", "."), true); |
207 | } |
208 | } |
209 | } else { |
210 | if (DEBUG) System.out.println("Parsing " + signature); |
211 | SignatureReader r = new SignatureReader(signature); |
212 | ClassTypeImpl currentType = new ClassTypeImpl(internalName.replaceAll("/", "."), isInterface); |
213 | SigVisitor v = new SigVisitor(currentType, false); |
214 | r.accept(v); |
215 | v.endParsing(); |
216 | |
217 | typeParameters = v.typeParameters; |
218 | genericSuperclass = v.genericSuperclass; |
219 | genericInterfaces = v.genericInterfaces; |
220 | } |
221 | if (isInterface) { |
222 | genericSuperclass = null; |
223 | } |
224 | |
225 | } |
226 | |
227 | private TypeVariable[] typeParameters; |
228 | |
229 | private Type genericSuperclass; |
230 | |
231 | private Type[] genericInterfaces; |
232 | |
233 | public TypeVariable[] getTypeParameters() throws GenericSignatureFormatError { |
234 | return typeParameters; |
235 | } |
236 | |
237 | public Type getGenericSuperclass() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException { |
238 | return genericSuperclass; |
239 | } |
240 | |
241 | public Type[] getGenericInterfaces() throws GenericSignatureFormatError, TypeNotPresentException, MalformedParameterizedTypeException { |
242 | return genericInterfaces; |
243 | } |
244 | |
245 | /** |
246 | * Visits the header of the class. |
247 | * |
248 | * @param version the class version. |
249 | * @param access the class's access flags (see {@link Opcodes}). This |
250 | * parameter also indicates if the class is deprecated. |
251 | * @param name the internal name of the class (see |
252 | * {@link Type#getInternalName() getInternalName}). |
253 | * @param signature the signature of this class. May be <tt>null</tt> if |
254 | * the class is not a generic one, and does not extend or implement |
255 | * generic classes or interfaces. |
256 | * @param superName the internal of name of the super class (see |
257 | * {@link Type#getInternalName() getInternalName}). For interfaces, |
258 | * the super class is {@link Object}. May be <tt>null</tt>, but |
259 | * only for the {@link Object} class. |
260 | * @param interfaces the internal names of the class's interfaces (see |
261 | * {@link Type#getInternalName() getInternalName}). May be |
262 | * <tt>null</tt>. |
263 | */ |
264 | public void visit( |
265 | int version, |
266 | int access, |
267 | String name, |
268 | String signature, |
269 | String superName, |
270 | String[] interfaces) { |
271 | internalName = name; |
272 | boolean isInterface = ( access & Opcodes.ACC_INTERFACE ) == Opcodes.ACC_INTERFACE; |
273 | parseSignature(signature, isInterface, superName, interfaces); |
274 | } |
275 | |
276 | public void visitSource(String source, String debug) {} |
277 | |
278 | /** |
279 | * Visits the enclosing class of the class. This method must be called only |
280 | * if the class has an enclosing class. |
281 | * |
282 | * @param owner internal name of the enclosing class of the class. |
283 | * @param name the name of the method that contains the class, or |
284 | * <tt>null</tt> if the class is not enclosed in a method of its |
285 | * enclosing class. |
286 | * @param desc the descriptor of the method that contains the class, or |
287 | * <tt>null</tt> if the class is not enclosed in a method of its |
288 | * enclosing class. |
289 | */ |
290 | public void visitOuterClass(String owner, String name, String desc) { |
291 | enclosingClassName = owner; |
292 | enclosingMethodName = name; |
293 | enclosingMethodDesc = desc; |
294 | //debugMessage("visitOuterClass"); |
295 | } |
296 | |
297 | /** |
298 | * Visits information about an inner class. This inner class is not |
299 | * necessarily a member of the class being visited. |
300 | * |
301 | * @param name the internal name of an inner class (see |
302 | * {@link Type#getInternalName() getInternalName}). |
303 | * @param outerName the internal name of the class to which the inner class |
304 | * belongs (see {@link Type#getInternalName() getInternalName}). May |
305 | * be <tt>null</tt>. |
306 | * @param innerName the (simple) name of the inner class inside its |
307 | * enclosing class. May be <tt>null</tt> for anonymous inner |
308 | * classes. |
309 | * @param access the access flags of the inner class as originally declared |
310 | * in the enclosing class. |
311 | */ |
312 | public void visitInnerClass( |
313 | String name, |
314 | String outerName, |
315 | String innerName, |
316 | int access) { |
317 | if (name.equals(internalName)) { |
318 | if (outerName != null) { |
319 | enclosingClassName = outerName; |
320 | } |
321 | } |
322 | //debugMessage("visitInnerClass"); |
323 | } |
324 | |
325 | public AnnotationVisitor visitAnnotation(String desc, boolean visible) { |
326 | return AIB.EMPTY_VISITOR; |
327 | } |
328 | |
329 | public void visitAttribute(Attribute attr) {} |
330 | |
331 | public FieldVisitor visitField( |
332 | int access, |
333 | String name, |
334 | String desc, |
335 | String signature, |
336 | Object value) { |
337 | fieldAccessTable.put(name, access); |
338 | return null; |
339 | } |
340 | |
341 | public MethodVisitor visitMethod( |
342 | int access, |
343 | String name, |
344 | String desc, |
345 | String signature, |
346 | String[] exceptions) { |
347 | methodAccessTable.put(name+desc, access); |
348 | return null; |
349 | } |
350 | |
351 | public void visitEnd() {} |
352 | |
353 | public static void main(String args[]) { |
354 | String signature = "<E:Ljava/lang/String;>Ljava/util/LinkedList<TE;>;Ljava/io/Serializable;Ljava/lang/Comparable<TE;>;"; |
355 | String internalName = "blah.TopLevel"; |
356 | |
357 | System.out.println("Parsing " + signature); |
358 | SignatureReader r = new SignatureReader(signature); |
359 | ClassTypeImpl currentType = new ClassTypeImpl(internalName.replaceAll("/", "."), false); |
360 | SigVisitor v = new SigVisitor(currentType, false); |
361 | r.accept(v); |
362 | v.endParsing(); |
363 | |
364 | System.out.println(v.genericInterfaces.length); |
365 | for(Type t: v.genericInterfaces) { |
366 | System.out.println(t); |
367 | } |
368 | } |
369 | |
370 | private static class SigVisitor implements SignatureVisitor { |
371 | protected TypeVariable[] typeParameters; |
372 | protected Type genericSuperclass; |
373 | protected Type[] genericInterfaces; |
374 | |
375 | private Stack<Type> stack = new Stack<Type>(); |
376 | |
377 | private Set<TypeVariableImpl> typeVariables = new HashSet<TypeVariableImpl>(); |
378 | |
379 | private LinkedList<TypeVariableImpl> formalTypeParameters = new LinkedList<TypeVariableImpl>(); |
380 | |
381 | private StringBuffer declaration; |
382 | |
383 | private boolean isInterface; |
384 | |
385 | private ClassTypeImpl currentType; |
386 | |
387 | private boolean seenFormalParameter; |
388 | |
389 | private boolean seenInterfaceBound; |
390 | |
391 | private boolean seenParameter; |
392 | |
393 | private boolean seenInterface; |
394 | |
395 | private StringBuffer returnType; |
396 | |
397 | private StringBuffer exceptions; |
398 | |
399 | /** |
400 | * Stack used to keep track of class types that have arguments. Each element |
401 | * of this stack is a boolean encoded in one bit. The top of the stack is |
402 | * the lowest order bit. Pushing false = *2, pushing true = *2+1, popping = |
403 | * /2. |
404 | */ |
405 | private int argumentStack; |
406 | |
407 | private Stack<Integer> argumentStackPosition = new Stack<Integer>(); |
408 | |
409 | /** |
410 | * Stack used to keep track of array class types. Each element of this stack |
411 | * is a boolean encoded in one bit. The top of the stack is the lowest order |
412 | * bit. Pushing false = *2, pushing true = *2+1, popping = /2. |
413 | */ |
414 | private int arrayStack; |
415 | |
416 | private String separator = ""; |
417 | |
418 | public SigVisitor(final ClassTypeImpl currentType, final boolean isInterface) { |
419 | this.isInterface = isInterface; |
420 | this.declaration = new StringBuffer(); |
421 | this.currentType = currentType; |
422 | } |
423 | |
424 | private SigVisitor(final StringBuffer buf) { |
425 | this.declaration = buf; |
426 | } |
427 | |
428 | /** |
429 | * Visits a formal type parameter. |
430 | * |
431 | * @param name the name of the formal parameter. |
432 | */ |
433 | public void visitFormalTypeParameter(final String name) { |
434 | if (seenFormalParameter) { |
435 | endFormal(); |
436 | } |
437 | TypeVariableImpl t = new TypeVariableImpl(name); |
438 | typeVariables.add(t); |
439 | formalTypeParameters.add(t); |
440 | if (DEBUG) System.out.println("pushing visitFormalTypeParameter " + t); |
441 | |
442 | declaration.append(seenFormalParameter ? ", " : "<").append(name); |
443 | seenFormalParameter = true; |
444 | seenInterfaceBound = false; |
445 | } |
446 | |
447 | /** |
448 | * Visits the class bound of the last visited formal type parameter. |
449 | * |
450 | * @return a non null visitor to visit the signature of the class bound. |
451 | */ |
452 | public SignatureVisitor visitClassBound() { |
453 | separator = " extends "; |
454 | startType(); |
455 | return this; |
456 | } |
457 | |
458 | /** |
459 | * Visits an interface bound of the last visited formal type parameter. |
460 | * |
461 | * @return a non null visitor to visit the signature of the interface bound. |
462 | */ |
463 | public SignatureVisitor visitInterfaceBound() { |
464 | separator = seenInterfaceBound ? ", " : " extends "; |
465 | seenInterfaceBound = true; |
466 | startType(); |
467 | return this; |
468 | } |
469 | |
470 | /** |
471 | * Visits the type of the super class. |
472 | * |
473 | * @return a non null visitor to visit the signature of the super class |
474 | * type. |
475 | */ |
476 | public SignatureVisitor visitSuperclass() { |
477 | endFormals(); |
478 | separator = " extends "; |
479 | startType(); |
480 | return this; |
481 | } |
482 | |
483 | /** |
484 | * Visits the type of an interface implemented by the class. |
485 | * |
486 | * @return a non null visitor to visit the signature of the interface type. |
487 | */ |
488 | public SignatureVisitor visitInterface() { |
489 | if (!seenInterface) { |
490 | endGenericSuperclass(); |
491 | } |
492 | separator = seenInterface ? ", " : isInterface |
493 | ? " extends " |
494 | : " implements "; |
495 | seenInterface = true; |
496 | startType(); |
497 | return this; |
498 | } |
499 | |
500 | /** |
501 | * Visits the type of a method parameter. |
502 | * |
503 | * @return a non null visitor to visit the signature of the parameter type. |
504 | */ |
505 | public SignatureVisitor visitParameterType() { |
506 | endFormals(); |
507 | if (!seenParameter) { |
508 | seenParameter = true; |
509 | declaration.append('('); |
510 | } else { |
511 | declaration.append(", "); |
512 | } |
513 | startType(); |
514 | return this; |
515 | } |
516 | |
517 | /** |
518 | * Visits the return type of the method. |
519 | * |
520 | * @return a non null visitor to visit the signature of the return type. |
521 | */ |
522 | public SignatureVisitor visitReturnType() { |
523 | endFormals(); |
524 | if (!seenParameter) { |
525 | declaration.append('('); |
526 | } else { |
527 | seenParameter = false; |
528 | } |
529 | declaration.append(')'); |
530 | returnType = new StringBuffer(); |
531 | return new SigVisitor(returnType); |
532 | } |
533 | |
534 | /** |
535 | * Visits the type of a method exception. |
536 | * |
537 | * @return a non null visitor to visit the signature of the exception type. |
538 | */ |
539 | public SignatureVisitor visitExceptionType() { |
540 | if (exceptions == null) { |
541 | exceptions = new StringBuffer(); |
542 | } else { |
543 | exceptions.append(", "); |
544 | } |
545 | // startType(); |
546 | return new SigVisitor(exceptions); |
547 | } |
548 | |
549 | /** |
550 | * Visits a signature corresponding to a primitive type. |
551 | * |
552 | * @param descriptor the descriptor of the primitive type, or 'V' for |
553 | * <tt>void</tt>. |
554 | */ |
555 | public void visitBaseType(final char descriptor) { |
556 | if (DEBUG) System.out.println("visitBaseType " + descriptor); |
557 | switch (descriptor) { |
558 | case 'V': |
559 | declaration.append("void"); |
560 | break; |
561 | case 'B': |
562 | declaration.append("byte"); |
563 | break; |
564 | case 'J': |
565 | declaration.append("long"); |
566 | break; |
567 | case 'Z': |
568 | declaration.append("boolean"); |
569 | break; |
570 | case 'I': |
571 | declaration.append("int"); |
572 | break; |
573 | case 'S': |
574 | declaration.append("short"); |
575 | break; |
576 | case 'C': |
577 | declaration.append("char"); |
578 | break; |
579 | case 'F': |
580 | declaration.append("float"); |
581 | break; |
582 | // case 'D': |
583 | default: |
584 | declaration.append("double"); |
585 | break; |
586 | } |
587 | endType(); |
588 | } |
589 | |
590 | /** |
591 | * Visits a signature corresponding to a type variable. |
592 | * |
593 | * @param name the name of the type variable. |
594 | */ |
595 | public void visitTypeVariable(final String name) { |
596 | if (DEBUG) System.out.println("visitTypeVariable " + name); |
597 | TypeVariableImpl t = new TypeVariableImpl(name); |
598 | typeVariables.add(t); |
599 | stack.push(t); |
600 | declaration.append(name); |
601 | endType(); |
602 | } |
603 | |
604 | /** |
605 | * Visits a signature corresponding to an array type. |
606 | * |
607 | * @return a non null visitor to visit the signature of the array element |
608 | * type. |
609 | */ |
610 | public SignatureVisitor visitArrayType() { |
611 | startType(); |
612 | arrayStack |= 1; |
613 | return this; |
614 | } |
615 | |
616 | /** |
617 | * Starts the visit of a signature corresponding to a class or interface |
618 | * type. |
619 | * |
620 | * @param name the internal name of the class or interface. |
621 | */ |
622 | public void visitClassType(final String name) { |
623 | ClassTypeImpl t = new ClassTypeImpl(name.replace('/', '.')); |
624 | stack.push(t); |
625 | if (DEBUG) System.out.println("visitClassType " + name.replace('/', '.')); |
626 | |
627 | if (!"java/lang/Object".equals(name)) { |
628 | declaration.append(separator).append(name.replace('/', '.')); |
629 | } else { |
630 | // Map<java.lang.Object,java.util.List> |
631 | // or |
632 | // abstract public V get(Object key); (seen in Dictionary.class) |
633 | // should have Object |
634 | // but java.lang.String extends java.lang.Object is unnecessary |
635 | boolean needObjectClass = argumentStack % 2 != 0 || seenParameter; |
636 | if (needObjectClass) { |
637 | declaration.append(separator).append(name.replace('/', '.')); |
638 | } |
639 | } |
640 | separator = ""; |
641 | argumentStack *= 2; |
642 | argumentStackPosition.push(stack.size()); |
643 | } |
644 | |
645 | /** |
646 | * Visits an inner class. |
647 | * |
648 | * @param name the local name of the inner class in its enclosing class. |
649 | */ |
650 | public void visitInnerClassType(final String name) { |
651 | if (DEBUG) System.out.println("visitInnerClassType " + name); |
652 | if (argumentStack % 2 != 0) { |
653 | declaration.append('>'); |
654 | } |
655 | argumentStack /= 2; |
656 | argumentStackPosition.pop(); |
657 | declaration.append('.'); |
658 | declaration.append(separator).append(name.replace('/', '.')); |
659 | separator = ""; |
660 | argumentStack *= 2; |
661 | argumentStackPosition.push(stack.size()); |
662 | } |
663 | |
664 | /** |
665 | * Visits an unbounded type argument of the last visited class or inner |
666 | * class type. |
667 | */ |
668 | public void visitTypeArgument() { |
669 | if (DEBUG) System.out.println("visitTypeArgument"); |
670 | if (argumentStack % 2 == 0) { |
671 | ++argumentStack; |
672 | declaration.append('<'); |
673 | } else { |
674 | declaration.append(", "); |
675 | } |
676 | declaration.append('?'); |
677 | } |
678 | |
679 | /** |
680 | * Visits a type argument of the last visited class or inner class type. |
681 | * |
682 | * @param wildcard '+', '-' or '='. |
683 | * @return a non null visitor to visit the signature of the type argument. |
684 | */ |
685 | public SignatureVisitor visitTypeArgument(final char tag) { |
686 | if (argumentStack % 2 == 0) { |
687 | ++argumentStack; |
688 | declaration.append('<'); |
689 | } else { |
690 | declaration.append(", "); |
691 | } |
692 | |
693 | if (tag == SignatureVisitor.EXTENDS) { |
694 | declaration.append("? extends "); |
695 | } else if (tag == SignatureVisitor.SUPER) { |
696 | declaration.append("? super "); |
697 | } |
698 | |
699 | startType(); |
700 | return this; |
701 | } |
702 | |
703 | /** |
704 | * Ends the visit of a signature corresponding to a class or interface type. |
705 | */ |
706 | public void visitEnd() { |
707 | if (DEBUG) System.out.println("visitEnd"); |
708 | if (DEBUG) System.out.println("\t" + declaration); |
709 | if (argumentStack % 2 != 0) { |
710 | int stackPos = argumentStackPosition.peek().intValue() - 1; |
711 | |
712 | Type raw = stack.elementAt(stackPos); |
713 | Type owner = null; // FIXME |
714 | |
715 | int l = stack.size() - stackPos - 1; |
716 | Type args[] = new Type[l]; |
717 | for(int i = l-1; i >= 0; i--) { |
718 | args[i] = stack.pop(); |
719 | } |
720 | stack.pop(); |
721 | ParameterizedTypeImpl t = new ParameterizedTypeImpl(owner, args, raw); |
722 | stack.push(t); |
723 | declaration.append('>'); |
724 | } |
725 | argumentStack /= 2; |
726 | argumentStackPosition.pop(); |
727 | endType(); |
728 | } |
729 | |
730 | public String getDeclaration() { |
731 | return declaration.toString(); |
732 | } |
733 | |
734 | public String getReturnType() { |
735 | return returnType == null ? null : returnType.toString(); |
736 | } |
737 | |
738 | public String getExceptions() { |
739 | return exceptions == null ? null : exceptions.toString(); |
740 | } |
741 | |
742 | // ----------------------------------------------- |
743 | |
744 | private void endFormal() { |
745 | Type bounds[] = stack.toArray(new Type[stack.size()]); |
746 | stack.removeAllElements(); |
747 | formalTypeParameters.getLast().setBounds(bounds); |
748 | } |
749 | |
750 | private void endGenericSuperclass() { |
751 | genericSuperclass = stack.pop(); |
752 | } |
753 | |
754 | public void endParsing() { |
755 | if (!seenInterface) { |
756 | endGenericSuperclass(); |
757 | genericInterfaces = new Type[0]; |
758 | } else { |
759 | genericInterfaces = stack.toArray(new Type[stack.size()]); |
760 | stack.removeAllElements(); |
761 | for(Type t: genericInterfaces) { |
762 | if (t instanceof ParameterizedTypeImpl) { |
763 | ParameterizedTypeImpl p = (ParameterizedTypeImpl) t; |
764 | t = p.raw; |
765 | } |
766 | if (t instanceof ClassTypeImpl) { |
767 | ClassTypeImpl c = (ClassTypeImpl) t; |
768 | c.isInterface = true; |
769 | } |
770 | } |
771 | } |
772 | currentType.setTypeParameters(typeParameters); |
773 | for(TypeVariableImpl t: typeVariables) { |
774 | t.setGenericDeclaration(currentType); |
775 | } |
776 | } |
777 | |
778 | private void endFormals() { |
779 | if (seenFormalParameter) { |
780 | endFormal(); |
781 | declaration.append('>'); |
782 | seenFormalParameter = false; |
783 | } |
784 | typeParameters = formalTypeParameters.toArray(new TypeVariable[formalTypeParameters.size()]); |
785 | } |
786 | |
787 | private void startType() { |
788 | arrayStack *= 2; |
789 | } |
790 | |
791 | private void endType() { |
792 | if (arrayStack % 2 != 0) { |
793 | while (arrayStack % 2 != 0) { |
794 | Type t = stack.pop(); |
795 | stack.push(new GenericArrayTypeImpl(t)); |
796 | arrayStack /= 2; |
797 | declaration.append("[]"); |
798 | } |
799 | } else { |
800 | arrayStack /= 2; |
801 | } |
802 | } |
803 | } |
804 | |
805 | public static class ClassTypeImpl implements Type, GenericDeclaration { |
806 | private final String name; |
807 | private boolean isInterface; |
808 | private TypeVariable<?>[] typeParameters; |
809 | public ClassTypeImpl(String name) { |
810 | this.name = name; |
811 | isInterface = false; |
812 | } |
813 | public ClassTypeImpl(String name, boolean isInterface) { |
814 | this.name = name; |
815 | this.isInterface = isInterface; |
816 | } |
817 | public String toString() { return (isInterface?"interface ":"class ") + name; } |
818 | public TypeVariable<?>[] getTypeParameters() { |
819 | return typeParameters; |
820 | } |
821 | public void setTypeParameters(TypeVariable<?>[] typeParameters) { |
822 | this.typeParameters = typeParameters; |
823 | } |
824 | } |
825 | |
826 | public static class GenericArrayTypeImpl implements GenericArrayType { |
827 | public GenericArrayTypeImpl(Type genericComponentType) { |
828 | this.genericComponentType = genericComponentType; |
829 | } |
830 | private Type genericComponentType; |
831 | public Type getGenericComponentType() throws TypeNotPresentException, MalformedParameterizedTypeException { |
832 | return genericComponentType; |
833 | } |
834 | } |
835 | |
836 | public static class ParameterizedTypeImpl implements ParameterizedType { |
837 | public ParameterizedTypeImpl(Type owner, Type args[], Type raw) { |
838 | this.owner = owner; |
839 | this.args = args; |
840 | this.raw = raw; |
841 | } |
842 | private Type owner, args[], raw; |
843 | |
844 | public Type[] getActualTypeArguments() throws TypeNotPresentException, MalformedParameterizedTypeException { |
845 | return args; |
846 | } |
847 | public Type getOwnerType() { |
848 | return owner; |
849 | } |
850 | public Type getRawType() { |
851 | return raw; |
852 | } |
853 | public String toString() { |
854 | StringBuffer sb = new StringBuffer(); |
855 | String s = raw.toString(); |
856 | if (s.startsWith("class ")) { |
857 | s = s.substring(6); |
858 | } else if (s.startsWith("interface ")) { |
859 | s = s.substring(10); |
860 | } |
861 | sb.append(s); |
862 | if (args.length != 0) { |
863 | sb.append('<'); |
864 | boolean first = true; |
865 | for(Type t: args) { |
866 | if (!first) { |
867 | sb.append(", "); |
868 | } |
869 | first = false; |
870 | s = t.toString(); |
871 | if (s.startsWith("class ")) { |
872 | s = s.substring(6); |
873 | } |
874 | sb.append(s); |
875 | } |
876 | sb.append('>'); |
877 | } |
878 | return sb.toString(); |
879 | } |
880 | } |
881 | |
882 | public static class TypeVariableImpl<D extends GenericDeclaration> implements TypeVariable { |
883 | private final String name; |
884 | |
885 | public TypeVariableImpl(String name) { |
886 | this.name = name; |
887 | } |
888 | |
889 | private Type[] bounds; |
890 | private D genericDeclaration; |
891 | |
892 | protected void setBounds(Type[] bounds) { |
893 | this.bounds = bounds; |
894 | } |
895 | public Type[] getBounds() throws TypeNotPresentException, MalformedParameterizedTypeException { |
896 | return bounds; |
897 | } |
898 | |
899 | protected void setGenericDeclaration(D d) { |
900 | genericDeclaration = d; |
901 | } |
902 | public D getGenericDeclaration() { |
903 | return genericDeclaration; |
904 | } |
905 | |
906 | public String getName() { |
907 | return name; |
908 | } |
909 | |
910 | public String toString() { return name; } |
911 | } |
912 | |
913 | public static class WildcardTypeImpl implements WildcardType { |
914 | public Type[] getLowerBounds() throws TypeNotPresentException, MalformedParameterizedTypeException { |
915 | throw new UnsupportedOperationException("NotImplemented"); |
916 | } |
917 | |
918 | public Type[] getUpperBounds() throws TypeNotPresentException, MalformedParameterizedTypeException { |
919 | throw new UnsupportedOperationException("NotImplemented"); |
920 | } |
921 | } |
922 | |
923 | } |