001    package net.sourceforge.retroweaver.runtime.java.lang.reflect;
002    
003    import java.io.IOException;
004    import java.io.InputStream;
005    import java.lang.reflect.Constructor;
006    import java.lang.reflect.Field;
007    import java.lang.reflect.Method;
008    import java.util.HashMap;
009    import java.util.HashSet;
010    import java.util.LinkedList;
011    import java.util.Map;
012    import java.util.Set;
013    import java.util.Stack;
014    
015    import net.sourceforge.retroweaver.runtime.java.lang.TypeNotPresentException;
016    import net.sourceforge.retroweaver.runtime.java.lang.annotation.AIB;
017    
018    import org.objectweb.asm.AnnotationVisitor;
019    import org.objectweb.asm.Attribute;
020    import org.objectweb.asm.ClassReader;
021    import org.objectweb.asm.ClassVisitor;
022    import org.objectweb.asm.FieldVisitor;
023    import org.objectweb.asm.MethodVisitor;
024    import org.objectweb.asm.Opcodes;
025    import org.objectweb.asm.signature.SignatureReader;
026    import org.objectweb.asm.signature.SignatureVisitor;
027    
028    public class ReflectionDescriptor implements ClassVisitor {
029    
030            private static final boolean DEBUG = false;
031    
032            private static final Map<Class, ReflectionDescriptor> descriptors = new HashMap<Class, ReflectionDescriptor>();
033    
034            public static ReflectionDescriptor getReflectionDescriptor(Class class_) {
035                    synchronized (descriptors) {
036                            ReflectionDescriptor d = descriptors.get(class_);
037                            if (d == null) {
038                                    d = new ReflectionDescriptor(class_);
039                                    descriptors.put(class_, d);
040                                    if (DEBUG) d.debugMessage("Adding descriptor");
041                            }
042                            return d;                       
043                    }
044            }
045    
046            private final Class class_;
047    
048            private ReflectionDescriptor(Class class_) {
049                    this.class_ = class_;
050                    String name = class_.getName();
051    
052                    String resource = "/" + name.replace('.', '/') + ".class";
053    if (DEBUG) System.out.println("Reading class file: " + resource);
054                    InputStream classStream = class_.getResourceAsStream(resource);
055                    parseStream(name, classStream);
056            }
057    
058            protected ReflectionDescriptor(String name, InputStream classStream) {
059                    class_ = null;
060                    parseStream(name, classStream);
061            }
062            
063            private void parseStream(String name, InputStream classStream) {
064                    try {
065                            ClassReader r = new ClassReader(classStream);
066                            r.accept(this, ClassReader.SKIP_CODE + ClassReader.SKIP_DEBUG
067                                            + ClassReader.SKIP_FRAMES);
068    
069                    } catch (IOException e) {
070                            // Shouldn't generally happen
071                            throw new TypeNotPresentException(
072                                            "[Retroweaver] Unable to read reflection data for: " + name, e);
073                    } finally {
074                            try {
075                                    if (classStream != null) {
076                                            classStream.close();
077                                    }
078                            } catch (IOException e) { // NOPMD by xlv
079                            }
080                    }
081            }
082    
083            private String internalName;
084    
085            private String enclosingClassName;
086    
087            private String enclosingMethodName;
088    
089            private String enclosingMethodDesc;
090    
091            private HashMap<String, Integer> fieldAccessTable = new HashMap<String, Integer>();
092    
093            private HashMap<String, Integer> methodAccessTable = new HashMap<String, Integer>();
094    
095            public String getEnclosingClassName() {
096                    return enclosingClassName;
097            }
098    
099            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    }