001: /*
002: * Janino - An embedded Java[TM] compiler
003: *
004: * Copyright (c) 2006, Arno Unkrig
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * 1. Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * 2. Redistributions in binary form must reproduce the above
014: * copyright notice, this list of conditions and the following
015: * disclaimer in the documentation and/or other materials
016: * provided with the distribution.
017: * 3. The name of the author may not be used to endorse or promote
018: * products derived from this software without specific prior
019: * written permission.
020: *
021: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
022: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
023: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
024: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
025: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
026: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
027: * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
028: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
029: * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
030: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
031: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
032: */
033:
034: package org.codehaus.janino;
035:
036: import java.util.*;
037:
038: /**
039: * A simplified equivalent to "java.lang.reflect".
040: */
041: public abstract class IClass {
042: private static final boolean DEBUG = false;
043:
044: public static final IClass VOID = new PrimitiveIClass(
045: Descriptor.VOID);
046: public static final IClass BYTE = new PrimitiveIClass(
047: Descriptor.BYTE);
048: public static final IClass CHAR = new PrimitiveIClass(
049: Descriptor.CHAR);
050: public static final IClass DOUBLE = new PrimitiveIClass(
051: Descriptor.DOUBLE);
052: public static final IClass FLOAT = new PrimitiveIClass(
053: Descriptor.FLOAT);
054: public static final IClass INT = new PrimitiveIClass(Descriptor.INT);
055: public static final IClass LONG = new PrimitiveIClass(
056: Descriptor.LONG);
057: public static final IClass SHORT = new PrimitiveIClass(
058: Descriptor.SHORT);
059: public static final IClass BOOLEAN = new PrimitiveIClass(
060: Descriptor.BOOLEAN);
061:
062: private static class PrimitiveIClass extends IClass {
063: private final String fieldDescriptor;
064:
065: public PrimitiveIClass(String fieldDescriptor) {
066: this .fieldDescriptor = fieldDescriptor;
067: }
068:
069: protected IClass getComponentType2() {
070: return null;
071: }
072:
073: protected IClass[] getDeclaredIClasses2() {
074: return new IClass[0];
075: }
076:
077: protected IConstructor[] getDeclaredIConstructors2() {
078: return new IConstructor[0];
079: }
080:
081: protected IField[] getDeclaredIFields2() {
082: return new IField[0];
083: }
084:
085: protected IMethod[] getDeclaredIMethods2() {
086: return new IMethod[0];
087: }
088:
089: protected IClass getDeclaringIClass2() {
090: return null;
091: }
092:
093: protected String getDescriptor2() {
094: return this .fieldDescriptor;
095: }
096:
097: protected IClass[] getInterfaces2() {
098: return new IClass[0];
099: }
100:
101: protected IClass getOuterIClass2() {
102: return null;
103: }
104:
105: protected IClass getSuperclass2() {
106: return null;
107: }
108:
109: public boolean isAbstract() {
110: return false;
111: }
112:
113: public boolean isArray() {
114: return false;
115: }
116:
117: public boolean isFinal() {
118: return true;
119: }
120:
121: public boolean isInterface() {
122: return false;
123: }
124:
125: public boolean isPrimitive() {
126: return true;
127: }
128:
129: public boolean isPrimitiveNumeric() {
130: return Descriptor.isPrimitiveNumeric(this .fieldDescriptor);
131: }
132:
133: public Access getAccess() {
134: return Access.PUBLIC;
135: }
136: }
137:
138: /**
139: * Returns all the constructors declared by the class represented by the
140: * type. If the class has a default constructor, it is included.
141: * <p>
142: * Returns an array with zero elements for an interface, array, primitive type or
143: * "void".
144: */
145: public final IConstructor[] getDeclaredIConstructors() {
146: if (this .declaredIConstructors == null) {
147: this .declaredIConstructors = this
148: .getDeclaredIConstructors2();
149: }
150: return this .declaredIConstructors;
151: }
152:
153: private IConstructor[] declaredIConstructors = null;
154:
155: protected abstract IConstructor[] getDeclaredIConstructors2();
156:
157: /**
158: * Returns the methods of the class or interface (but not inherited
159: * methods).<br>
160: * Returns an empty array for an array, primitive type or "void".
161: */
162: public final IMethod[] getDeclaredIMethods() {
163: if (this .declaredIMethods == null) {
164: this .declaredIMethods = this .getDeclaredIMethods2();
165: }
166: return this .declaredIMethods;
167: }
168:
169: protected IMethod[] declaredIMethods = null;
170:
171: protected abstract IMethod[] getDeclaredIMethods2();
172:
173: /**
174: * Returns all methods with the given name declared in the class or
175: * interface (but not inherited methods).<br>
176: * Returns an empty array if no methods with that name are declared.
177: *
178: * @return an array of {@link IMethod}s that must not be modified
179: */
180: public final IMethod[] getDeclaredIMethods(String methodName) {
181: if (this .declaredIMethodCache == null) {
182: Map m = new HashMap();
183:
184: // Fill the map with "IMethod"s and "List"s.
185: IMethod[] dims = this .getDeclaredIMethods();
186: for (int i = 0; i < dims.length; i++) {
187: IMethod dim = dims[i];
188: String mn = dim.getName();
189: Object o = m.get(mn);
190: if (o == null) {
191: m.put(mn, dim);
192: } else if (o instanceof IMethod) {
193: List l = new ArrayList();
194: l.add(o);
195: l.add(dim);
196: m.put(mn, l);
197: } else {
198: ((List) o).add(dim);
199: }
200: }
201:
202: // Convert "IMethod"s and "List"s to "IMethod[]"s.
203: for (Iterator it = m.entrySet().iterator(); it.hasNext();) {
204: Map.Entry me = (Map.Entry) it.next();
205: Object v = me.getValue();
206: if (v instanceof IMethod) {
207: me.setValue(new IMethod[] { (IMethod) v });
208: } else {
209: List l = (List) v;
210: me.setValue(l.toArray(new IMethod[l.size()]));
211: }
212: }
213: this .declaredIMethodCache = m;
214: }
215:
216: IMethod[] methods = (IMethod[]) this .declaredIMethodCache
217: .get(methodName);
218: return methods == null ? IClass.NO_IMETHODS : methods;
219: }
220:
221: /*package*/Map declaredIMethodCache = null;
222: public static final IMethod[] NO_IMETHODS = new IMethod[0];
223:
224: /**
225: * Returns the fields of a class or interface (but not inherited
226: * fields).<br>
227: * Returns an empty array for an array, primitive type or "void".
228: */
229: public final IField[] getDeclaredIFields() {
230: if (this .declaredIFields == null) {
231: this .declaredIFields = this .getDeclaredIFields2();
232: }
233: return this .declaredIFields;
234: }
235:
236: protected IField[] declaredIFields = null;
237:
238: protected abstract IField[] getDeclaredIFields2();
239:
240: /**
241: * Returns the synthetic fields of an anonymous or local class, in
242: * the order in which they are passed to all constructors.
243: */
244: public IField[] getSyntheticIFields() {
245: return new IField[0];
246: }
247:
248: /**
249: * Returns the classes and interfaces declared as members of the class
250: * (but not inherited classes and interfaces).<br>
251: * Returns an empty array for an array, primitive type or "void".
252: */
253: public final IClass[] getDeclaredIClasses() throws CompileException {
254: if (this .declaredIClasses == null) {
255: this .declaredIClasses = this .getDeclaredIClasses2();
256: }
257: return this .declaredIClasses;
258: }
259:
260: private IClass[] declaredIClasses = null;
261:
262: protected abstract IClass[] getDeclaredIClasses2()
263: throws CompileException;
264:
265: /**
266: * If this class is a member class, return the declaring class, otherwise return
267: * <code>null</code>.
268: */
269: public final IClass getDeclaringIClass() throws CompileException {
270: if (!this .declaringIClassIsCached) {
271: this .declaringIClass = this .getDeclaringIClass2();
272: this .declaringIClassIsCached = true;
273: }
274: return this .declaringIClass;
275: }
276:
277: private boolean declaringIClassIsCached = false;
278: private IClass declaringIClass = null;
279:
280: protected abstract IClass getDeclaringIClass2()
281: throws CompileException;
282:
283: /**
284: * The following types have an "outer class":
285: * <ul>
286: * <li>Anonymous classes declared in a non-static method of a class
287: * <li>Local classes declared in a non-static method of a class
288: * <li>Non-static member classes
289: * </ul>
290: */
291: public final IClass getOuterIClass() throws CompileException {
292: if (!this .outerIClassIsCached) {
293: this .outerIClass = this .getOuterIClass2();
294: this .outerIClassIsCached = true;
295: }
296: return this .outerIClass;
297: }
298:
299: private boolean outerIClassIsCached = false;
300: private IClass outerIClass = null;
301:
302: protected abstract IClass getOuterIClass2() throws CompileException;
303:
304: /**
305: * Returns the superclass of the class.<br>
306: * Returns "null" for class "Object", interfaces, arrays, primitive types
307: * and "void".
308: */
309: public final IClass getSuperclass() throws CompileException {
310: if (!this .super classIsCached) {
311: this .super class = this .getSuperclass2();
312: this .super classIsCached = true;
313: if (this .super class != null
314: && this .super class.isSubclassOf(this ))
315: throw new CompileException(
316: "Class circularity detected for \""
317: + Descriptor.toClassName(this
318: .getDescriptor()) + "\"", null);
319: }
320: return this .super class;
321: }
322:
323: private boolean super classIsCached = false;
324: private IClass super class = null;
325:
326: protected abstract IClass getSuperclass2() throws CompileException;
327:
328: public abstract Access getAccess();
329:
330: /**
331: * Whether subclassing is allowed (JVMS 4.1 access_flags)
332: * @return <code>true</code> if subclassing is prohibited
333: */
334: public abstract boolean isFinal();
335:
336: /**
337: * Returns the interfaces implemented by the class.<br>
338: * Returns the superinterfaces of the interface.<br>
339: * Returns "Cloneable" and "Serializable" for arrays.<br>
340: * Returns an empty array for primitive types and "void".
341: */
342: public final IClass[] getInterfaces() throws CompileException {
343: if (this .interfaces == null) {
344: this .interfaces = this .getInterfaces2();
345: for (int i = 0; i < this .interfaces.length; ++i) {
346: if (this .interfaces[i].implements Interface(this ))
347: throw new CompileException(
348: "Interface circularity detected for \""
349: + Descriptor.toClassName(this
350: .getDescriptor()) + "\"",
351: null);
352: }
353: }
354: return this .interfaces;
355: }
356:
357: private IClass[] interfaces = null;
358:
359: protected abstract IClass[] getInterfaces2()
360: throws CompileException;
361:
362: /**
363: * Whether the class may be instantiated (JVMS 4.1 access_flags)
364: * @return <code>true</code> if instantiation is prohibited
365: */
366: public abstract boolean isAbstract();
367:
368: /**
369: * Returns the field descriptor for the type as defined by JVMS 4.3.2.
370: */
371: public final String getDescriptor() {
372: if (this .descriptor == null) {
373: this .descriptor = this .getDescriptor2();
374: }
375: return this .descriptor;
376: }
377:
378: private String descriptor = null;
379:
380: protected abstract String getDescriptor2();
381:
382: /**
383: * Convenience method that determines the field descriptors of an array of {@link IClass}es.
384: * @see #getDescriptor()
385: */
386: public static String[] getDescriptors(IClass[] iClasses) {
387: String[] descriptors = new String[iClasses.length];
388: for (int i = 0; i < iClasses.length; ++i)
389: descriptors[i] = iClasses[i].getDescriptor();
390: return descriptors;
391: }
392:
393: /**
394: * Returns "true" if this type represents an interface.
395: */
396: public abstract boolean isInterface();
397:
398: /**
399: * Returns "true" if this type represents an array.
400: */
401: public abstract boolean isArray();
402:
403: /**
404: * Returns "true" if this type represents a primitive type or "void".
405: */
406: public abstract boolean isPrimitive();
407:
408: /**
409: * Returns "true" if this type represents "byte", "short", "int", "long",
410: * "char", "float" or "double".
411: */
412: public abstract boolean isPrimitiveNumeric();
413:
414: /**
415: * Returns the component type of the array.<br>
416: * Returns "null" for classes, interfaces, primitive types and "void".
417: */
418: public final IClass getComponentType() {
419: if (!this .componentTypeIsCached) {
420: this .componentType = this .getComponentType2();
421: this .componentTypeIsCached = true;
422: }
423: return this .componentType;
424: }
425:
426: private boolean componentTypeIsCached = false;
427: private IClass componentType = null;
428:
429: protected abstract IClass getComponentType2();
430:
431: /**
432: * Returns a string representation for this object.
433: */
434: public String toString() {
435: return Descriptor.toClassName(this .getDescriptor());
436: }
437:
438: /**
439: * Determine if "this" is assignable from "that". This is true if "this"
440: * is identical with "that" (JLS2 5.1.1), or if "that" is
441: * widening-primitive-convertible to "this" (JLS2 5.1.2), or if "that" is
442: * widening-reference-convertible to "this" (JLS2 5.1.4).
443: */
444: public boolean isAssignableFrom(IClass that)
445: throws CompileException {
446:
447: // Identity conversion, JLS2 5.1.1
448: if (this == that)
449: return true;
450:
451: // Widening primitive conversion, JLS2 5.1.2
452: {
453: String ds = that.getDescriptor() + this .getDescriptor();
454: if (ds.length() == 2
455: && IClass.PRIMITIVE_WIDENING_CONVERSIONS
456: .contains(ds))
457: return true;
458: }
459:
460: // Widening reference conversion, JLS2 5.1.4
461: {
462:
463: // JLS 5.1.4.1: Target type is superclass of source class type.
464: if (that.isSubclassOf(this ))
465: return true;
466:
467: // JLS 5.1.4.2: Source class type implements target interface type.
468: // JLS 5.1.4.4: Source interface type implements target interface type.
469: if (that.implements Interface(this ))
470: return true;
471:
472: // JLS 5.1.4.3 Convert "null" literal to any reference type.
473: if (that == IClass.VOID && !this .isPrimitive())
474: return true;
475:
476: // JLS 5.1.4.5: From any interface to type "Object".
477: if (that.isInterface()
478: && this .getDescriptor().equals(Descriptor.OBJECT))
479: return true;
480:
481: if (that.isArray()) {
482:
483: // JLS 5.1.4.6: From any array type to type "Object".
484: if (this .getDescriptor().equals(Descriptor.OBJECT))
485: return true;
486:
487: // JLS 5.1.4.7: From any array type to type "Cloneable".
488: if (this .getDescriptor().equals(Descriptor.CLONEABLE))
489: return true;
490:
491: // JLS 5.1.4.8: From any array type to type "java.io.Serializable".
492: if (this .getDescriptor()
493: .equals(Descriptor.SERIALIZABLE))
494: return true;
495:
496: // JLS 5.1.4.9: From SC[] to TC[] while SC if widening reference convertible to TC.
497: if (this .isArray()) {
498: IClass this CT = this .getComponentType();
499: IClass thatCT = that.getComponentType();
500: if (!this CT.isPrimitive()
501: && this CT.isAssignableFrom(thatCT))
502: return true;
503: }
504: }
505: }
506: return false;
507: }
508:
509: private static final Set PRIMITIVE_WIDENING_CONVERSIONS = new HashSet();
510: static {
511: String[] pwcs = new String[] {
512: Descriptor.BYTE + Descriptor.SHORT,
513:
514: Descriptor.BYTE + Descriptor.INT,
515: Descriptor.SHORT + Descriptor.INT,
516: Descriptor.CHAR + Descriptor.INT,
517:
518: Descriptor.BYTE + Descriptor.LONG,
519: Descriptor.SHORT + Descriptor.LONG,
520: Descriptor.CHAR + Descriptor.LONG,
521: Descriptor.INT + Descriptor.LONG,
522:
523: Descriptor.BYTE + Descriptor.FLOAT,
524: Descriptor.SHORT + Descriptor.FLOAT,
525: Descriptor.CHAR + Descriptor.FLOAT,
526: Descriptor.INT + Descriptor.FLOAT,
527:
528: Descriptor.LONG + Descriptor.FLOAT,
529:
530: Descriptor.BYTE + Descriptor.DOUBLE,
531: Descriptor.SHORT + Descriptor.DOUBLE,
532: Descriptor.CHAR + Descriptor.DOUBLE,
533: Descriptor.INT + Descriptor.DOUBLE,
534:
535: Descriptor.LONG + Descriptor.DOUBLE,
536:
537: Descriptor.FLOAT + Descriptor.DOUBLE, };
538: for (int i = 0; i < pwcs.length; ++i)
539: IClass.PRIMITIVE_WIDENING_CONVERSIONS.add(pwcs[i]);
540: }
541:
542: /**
543: * Returns <code>true</code> if this class is an immediate or non-immediate
544: * subclass of <code>that</code> class.
545: */
546: public boolean isSubclassOf(IClass that) throws CompileException {
547: for (IClass sc = this .getSuperclass(); sc != null; sc = sc
548: .getSuperclass()) {
549: if (sc == that)
550: return true;
551: }
552: return false;
553: }
554:
555: /**
556: * If <code>this</code> represents a class: Return <code>true</code> if this class
557: * directly or indirectly implements <code>that</code> interface.
558: * <p>
559: * If <code>this</code> represents an interface: Return <code>true</code> if this
560: * interface directly or indirectly extends <code>that</code> interface.
561: */
562: public boolean implements Interface(IClass that)
563: throws CompileException {
564: for (IClass c = this ; c != null; c = c.getSuperclass()) {
565: IClass[] tis = c.getInterfaces();
566: for (int i = 0; i < tis.length; ++i) {
567: IClass ti = tis[i];
568: if (ti == that || ti.implements Interface(that))
569: return true;
570: }
571: }
572: return false;
573: }
574:
575: /**
576: * Get an {@link IClass} that represents an n-dimensional array of this type.
577: *
578: * @param n dimension count
579: * @param objectType Required because the superclass of an array class is {@link Object} by definition
580: */
581: public IClass getArrayIClass(int n, IClass objectType) {
582: IClass result = this ;
583: for (int i = 0; i < n; ++i)
584: result = result.getArrayIClass(objectType);
585: return result;
586: }
587:
588: /**
589: * Get an {@link IClass} that represents an array of this type.
590: *
591: * @param objectType Required because the superclass of an array class is {@link Object} by definition
592: */
593: public IClass getArrayIClass(IClass objectType) {
594: if (this .arrayIClass == null)
595: this .arrayIClass = this .getArrayIClass2(objectType);
596: return this .arrayIClass;
597: }
598:
599: private IClass arrayIClass = null;
600:
601: private IClass getArrayIClass2(final IClass objectType) {
602: final IClass componentType = this ;
603: return new IClass() {
604: public IClass.IConstructor[] getDeclaredIConstructors2() {
605: return new IClass.IConstructor[0];
606: }
607:
608: public IClass.IMethod[] getDeclaredIMethods2() {
609: return new IClass.IMethod[0];
610: }
611:
612: public IClass.IField[] getDeclaredIFields2() {
613: return new IClass.IField[0];
614: }
615:
616: public IClass[] getDeclaredIClasses2() {
617: return new IClass[0];
618: }
619:
620: public IClass getDeclaringIClass2() {
621: return null;
622: }
623:
624: public IClass getOuterIClass2() {
625: return null;
626: }
627:
628: public IClass getSuperclass2() {
629: return objectType;
630: }
631:
632: public IClass[] getInterfaces2() {
633: return new IClass[0];
634: }
635:
636: public String getDescriptor2() {
637: return '[' + componentType.getDescriptor();
638: }
639:
640: public Access getAccess() {
641: return componentType.getAccess();
642: }
643:
644: public boolean isFinal() {
645: return true;
646: }
647:
648: public boolean isInterface() {
649: return false;
650: }
651:
652: public boolean isAbstract() {
653: return false;
654: }
655:
656: public boolean isArray() {
657: return true;
658: }
659:
660: public boolean isPrimitive() {
661: return false;
662: }
663:
664: public boolean isPrimitiveNumeric() {
665: return false;
666: }
667:
668: public IClass getComponentType2() {
669: return componentType;
670: }
671:
672: public String toString() {
673: return componentType.toString() + "[]";
674: }
675: };
676: }
677:
678: /**
679: * If <code>optionalName</code> is <code>null</code>, find all {@link IClass}es visible in the
680: * scope of the current class.
681: * <p>
682: * If <code>optionalName</code> is not <code>null</code>, find the member {@link IClass}es
683: * that has the given name. If the name is ambiguous (i.e. if more than one superclass,
684: * interface of enclosing type declares a type with that name), then the size of the
685: * returned array is greater than one.
686: * <p>
687: * Examines superclasses, interfaces and enclosing type declarations.
688: * @return an array of {@link IClass}es in unspecified order, possibly of length zero
689: */
690: IClass[] findMemberType(String optionalName)
691: throws CompileException {
692: IClass[] res = (IClass[]) this .memberTypeCache
693: .get(optionalName);
694: if (res == null) {
695:
696: // Notice: A type may be added multiply to the result set because we are in its scope
697: // multiply. E.g. the type is a member of a superclass AND a member of an enclosing type.
698: Set s = new HashSet(); // IClass
699: this .findMemberType(optionalName, s);
700: res = s.isEmpty() ? IClass.ZERO_ICLASSES : (IClass[]) s
701: .toArray(new IClass[s.size()]);
702:
703: this .memberTypeCache.put(optionalName, res);
704: }
705:
706: return res;
707: }
708:
709: private final Map memberTypeCache = new HashMap(); // String name => IClass[]
710: private static final IClass[] ZERO_ICLASSES = new IClass[0];
711:
712: private void findMemberType(String optionalName, Collection result)
713: throws CompileException {
714:
715: // Search for a type with the given name in the current class.
716: IClass[] memberTypes = this .getDeclaredIClasses();
717: if (optionalName == null) {
718: result.addAll(Arrays.asList(memberTypes));
719: } else {
720: String memberDescriptor = Descriptor
721: .fromClassName(Descriptor.toClassName(this
722: .getDescriptor())
723: + '$' + optionalName);
724: for (int i = 0; i < memberTypes.length; ++i) {
725: final IClass mt = memberTypes[i];
726: if (mt.getDescriptor().equals(memberDescriptor)) {
727: result.add(mt);
728: return;
729: }
730: }
731: }
732:
733: // Examine superclass.
734: {
735: IClass super class = this .getSuperclass();
736: if (super class != null)
737: super class.findMemberType(optionalName, result);
738: }
739:
740: // Examine interfaces.
741: {
742: IClass[] ifs = this .getInterfaces();
743: for (int i = 0; i < ifs.length; ++i)
744: ifs[i].findMemberType(optionalName, result);
745: }
746:
747: // Examine enclosing type declarations.
748: {
749: IClass declaringIClass = this .getDeclaringIClass();
750: IClass outerIClass = this .getOuterIClass();
751: if (declaringIClass != null) {
752: declaringIClass.findMemberType(optionalName, result);
753: }
754: if (outerIClass != null && outerIClass != declaringIClass) {
755: outerIClass.findMemberType(optionalName, result);
756: }
757: }
758: }
759:
760: public interface IMember {
761:
762: /**
763: * @return One of {@link Access#PRIVATE}, {@link Access#PROTECTED},
764: * {@link Access#DEFAULT} and {@link Access#PUBLIC}.
765: */
766: Access getAccess();
767:
768: /**
769: * Returns the {@link IClass} that declares this {@link IClass.IMember}.
770: */
771: IClass getDeclaringIClass();
772: }
773:
774: public abstract class IInvocable implements IMember {
775:
776: // Implement IMember.
777: public abstract Access getAccess();
778:
779: public IClass getDeclaringIClass() {
780: return IClass.this ;
781: }
782:
783: public abstract IClass[] getParameterTypes()
784: throws CompileException;
785:
786: public abstract String getDescriptor() throws CompileException;
787:
788: public abstract IClass[] getThrownExceptions()
789: throws CompileException;
790:
791: public boolean isMoreSpecificThan(IInvocable that)
792: throws CompileException {
793: if (IClass.DEBUG)
794: System.out
795: .print("\"" + this + "\".isMoreSpecificThan(\""
796: + that + "\") => ");
797: if (!that.getDeclaringIClass().isAssignableFrom(
798: this .getDeclaringIClass())) {
799: if (IClass.DEBUG)
800: System.out.println("falsE");
801: return false;
802: }
803: IClass[] this ParameterTypes = this .getParameterTypes();
804: IClass[] thatParameterTypes = that.getParameterTypes();
805: int i;
806: for (i = 0; i < this ParameterTypes.length; ++i) {
807: if (!thatParameterTypes[i]
808: .isAssignableFrom(this ParameterTypes[i])) {
809: if (IClass.DEBUG)
810: System.out.println("false");
811: return false;
812: }
813: }
814: if (IClass.DEBUG)
815: System.out.println("true");
816: return true;
817: }
818:
819: public boolean isLessSpecificThan(IInvocable that)
820: throws CompileException {
821: return that.isMoreSpecificThan(this );
822: }
823:
824: public abstract String toString();
825: }
826:
827: public abstract class IConstructor extends IInvocable {
828:
829: /**
830: * Opposed to {@link java.lang.reflect.Constructor#getParameterTypes()}, the
831: * return value of this method does not include the optionally leading "synthetic
832: * parameters".
833: */
834: public abstract IClass[] getParameterTypes()
835: throws CompileException;
836:
837: /**
838: * Opposed to {@link #getParameterTypes()}, the method descriptor returned by this
839: * method does include the optionally leading synthetic parameters.
840: */
841: public String getDescriptor() throws CompileException {
842: return new MethodDescriptor(IClass.getDescriptors(this
843: .getParameterTypes()), Descriptor.VOID).toString();
844: }
845:
846: public String toString() {
847: StringBuffer sb = new StringBuffer(this
848: .getDeclaringIClass().toString());
849: sb.append('(');
850: try {
851: IClass[] parameterTypes = this .getParameterTypes();
852: for (int i = 0; i < parameterTypes.length; ++i) {
853: if (i > 0)
854: sb.append(", ");
855: sb.append(parameterTypes[i].toString());
856: }
857: } catch (CompileException ex) {
858: sb.append("<invalid type>");
859: }
860: sb.append(')');
861: return sb.toString();
862: }
863: }
864:
865: public abstract class IMethod extends IInvocable {
866: public abstract boolean isStatic();
867:
868: public abstract boolean isAbstract();
869:
870: public abstract IClass getReturnType() throws CompileException;
871:
872: public abstract String getName();
873:
874: public String getDescriptor() throws CompileException {
875: return new MethodDescriptor(IClass.getDescriptors(this
876: .getParameterTypes()), this .getReturnType()
877: .getDescriptor()).toString();
878: }
879:
880: public String toString() {
881: StringBuffer sb = new StringBuffer();
882: try {
883: sb.append(this .getReturnType().toString());
884: } catch (CompileException ex) {
885: sb.append("<invalid type>");
886: }
887: sb.append(' ');
888: sb.append(this .getDeclaringIClass().toString());
889: sb.append('.');
890: sb.append(this .getName());
891: sb.append('(');
892: try {
893: IClass[] parameterTypes = this .getParameterTypes();
894: for (int i = 0; i < parameterTypes.length; ++i) {
895: if (i > 0)
896: sb.append(", ");
897: sb.append(parameterTypes[i].toString());
898: }
899: } catch (CompileException ex) {
900: sb.append("<invalid type>");
901: }
902: sb.append(')');
903: try {
904: IClass[] tes = this .getThrownExceptions();
905: if (tes.length > 0) {
906: sb.append(" throws ").append(tes[0]);
907: for (int i = 1; i < tes.length; ++i)
908: sb.append(", ").append(tes[i]);
909: }
910: } catch (CompileException ex) {
911: sb.append("<invalid thrown exception type>");
912: }
913: return sb.toString();
914: }
915: }
916:
917: public abstract class IField implements IMember {
918:
919: // Implement IMember.
920: public abstract Access getAccess();
921:
922: public IClass getDeclaringIClass() {
923: return IClass.this ;
924: }
925:
926: public abstract boolean isStatic();
927:
928: public abstract IClass getType() throws CompileException;
929:
930: public abstract String getName();
931:
932: public String getDescriptor() throws CompileException {
933: return this .getType().getDescriptor();
934: }
935:
936: /**
937: * Returns the value of the field if it is a compile-time constant
938: * value, i.e. the field is FINAL and its initializer is a constant
939: * expression (JLS2 15.28, bullet 12).
940: */
941: public abstract Object getConstantValue()
942: throws CompileException;
943:
944: public String toString() {
945: return this.getName();
946: }
947: }
948: }
|