Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: openjava/mop/OJClass.java


1   /*
2    * OJClass.java
3    *
4    * comments here.
5    *
6    * @author   Michiaki Tatsubori
7    * @version  %VERSION% %DATE%
8    * @see      java.lang.Object
9    *
10   * COPYRIGHT 1999 by Michiaki Tatsubori, ALL RIGHTS RESERVED.
11   */
12  package openjava.mop;
13  
14  import java.io.IOException;
15  import java.io.InputStream;
16  import java.io.Writer;
17  import java.lang.reflect.Constructor;
18  import java.lang.reflect.Field;
19  import java.lang.reflect.InvocationTargetException;
20  import java.lang.reflect.Method;
21  import java.util.Enumeration;
22  import java.util.Hashtable;
23  import java.util.Vector;
24  
25  import openjava.ptree.AllocationExpression;
26  import openjava.ptree.ArrayAccess;
27  import openjava.ptree.ArrayAllocationExpression;
28  import openjava.ptree.AssignmentExpression;
29  import openjava.ptree.CastExpression;
30  import openjava.ptree.ClassDeclaration;
31  import openjava.ptree.ConstructorDeclaration;
32  import openjava.ptree.Expression;
33  import openjava.ptree.FieldAccess;
34  import openjava.ptree.FieldDeclaration;
35  import openjava.ptree.MemberDeclaration;
36  import openjava.ptree.MemberDeclarationList;
37  import openjava.ptree.MemberInitializer;
38  import openjava.ptree.MethodCall;
39  import openjava.ptree.MethodDeclaration;
40  import openjava.ptree.ParseTree;
41  import openjava.ptree.ParseTreeException;
42  import openjava.ptree.Statement;
43  import openjava.ptree.StatementList;
44  import openjava.ptree.TypeName;
45  import openjava.ptree.VariableDeclaration;
46  import openjava.ptree.util.PartialParser;
47  import openjava.ptree.util.TypeNameQualifier;
48  import openjava.syntax.SyntaxRule;
49  import openjava.tools.DebugOut;
50  
51  /**
52   * The <code>OJClass</code> class represents a class metaobject.  If
53   * the class has its valid .class file in CLASSPATH, the metaobject can
54   * behave like <code>java.lang.Class</code>.  If the class has its
55   * valid .oj file in the packages where some classes are being compiled
56   * by OpenJava system, or in the packages explicitly specified by
57   * something like OpenJava compiler option or environment variable, the
58   * metaobject can have information about source code just as
59   * stamements, expressions, and etc.
60   * <p>
61   * Additionaly, you can overrides the methods for introspection.
62   * <pre>
63   *     OJClass[] getDeclaredClasses()
64   *     OJMethod[] getDeclaredMethods()
65   *     OJField[] getDeclaredFields()
66   *     OJConstructor[] getDeclaredConstructors()
67   *     OJMethod getAcceptableMethod(OJClass,String,OJClass[])
68   *     OJMethod getAcceptableConstructor(OJClass,String,OJClass[])
69   * </pre>
70   *
71   * @author   Michiaki Tatsubori
72   * @version  1.0
73   * @since    $Id: OJClass.java,v 1.2 2003/02/19 02:55:01 tatsubori Exp $
74   * @see java.lang.Class
75   * @see openjava.mop.OJMethod
76   * @see openjava.mop.OJField
77   * @see openjava.mop.OJConstructor
78   *
79   **/
80  public class OJClass implements OJMember {
81  
82    private OJClassImp substance;
83  
84    /* -- constructors -- */
85  
86    /**
87     * Generates a metaobject from source code.
88     * <p>
89     * This constructor will be invoked by the OpenJava system.
90     * In inheriting this class, you must call this consturctor
91     * from a constructor with the same signature in your class.
92     * <p>
93     * For example, in defining a subclass <code>YourClass</code>
94     * derived from this class, at least you have to write as follows:
95     * <pre>
96     * public YourClass( Environment outer_env, OJClass declarer,
97     *                   ClassDeclaration ptree ) {
98     *     super( outer_env, declarer, ptree );
99     * }
100    * </pre>
101    *
102    * @param  outer_env  environment of this class metaobject
103    * @param  declarer  the class metaobject declaring this
104    *         class metaobject.
105    * @param  ptree  the parse tree representing this class metaobject.
106    */
107   public OJClass(
108     Environment outer_env,
109     OJClass declarer,
110     ClassDeclaration ptree) {
111     substance = new OJClassSourceCode(this, outer_env, declarer, ptree);
112   }
113 
114   /**
115    * Generates a metaobject from byte code.
116    * <p>
117    * This constructor will be invoked only by the OpenJava system.
118    * In inheriting this class, you must call this consturctor
119    * from a constructor with the same signature in your class.
120    * <p>
121    * For example, in defining a subclass <code>YourClass</code>
122    * derived from this class, at least you have to write as follows:
123    * <pre>
124    * public YourClass( Class java_class, MetaInfo metainfo ) {
125    *     super( java_class, metainfo );
126    * }
127    * </pre>
128    *
129    * @param  outer_env  environment of this class metaobject
130    * @param  declarer  the class metaobject declaring this
131    *         class metaobject.
132    * @param  ptree  the parse tree representing this class metaobject.
133    */
134   public OJClass(Class java_class, MetaInfo metainfo) {
135     substance = new OJClassByteCode(java_class, metainfo);
136   }
137 
138   /**
139    * For arrays
140    */
141   private OJClass(OJClass componentType) {
142     substance = new OJClassArray(componentType);
143   }
144 
145   /**
146    * For dummy type of null object.
147    * This should be called only once by OJSystem.initConstants().
148    */
149   OJClass() {
150     substance = new OJClassNull();
151   }
152 
153   /* -- Introspection Part -- */
154 
155   /**
156    * Returns the <code>OJClass</code> object associated with the class
157    * with the given string name.
158    * Given the fully-qualified name for a class or interface, this
159    * method attempts to locate, load and link the class.  If it
160    * succeeds, returns the Class object representing the class.  If
161    * it fails, the method throws a OJClassNotFoundException.
162    * <p>
163    * For example, the following code fragment returns the runtime
164    * <code>OJClass</code> descriptor for the class named
165    * <code>java.lang.Thread</code>:
166    * <ul><code>
167    *     OJClass t = OJClass.forName( "java.lang.Thread" );
168    * </code></ul>
169    *
170    * @param  class_name  the fully qualified name of the desired class.
171    * @return  the <code>OJClass</code> descriptor for the class with
172    *    the specified name.
173    * @exception  OJClassNotFoundException  if the class could not be found.
174    */
175   public static OJClass forName(String name)
176     throws OJClassNotFoundException {
177     DebugOut.println("OJClass.forName(\"" + name.toString() + "\")");
178 
179     name = nameForJavaClassName(name);
180 
181     OJClass result;
182 
183     result = OJSystem.env.lookupClass(name);
184     if (result != null)
185       return result;
186 
187     if (isArrayName(name)) {
188       OJClass component = forName(stripBrackets(name));
189       result = new OJClass(component);
190       OJSystem.env.record(name, result);
191       return result;
192     }
193 
194     result = lookupFromByteCode(nameToJavaClassName(name));
195     if (result != null) {
196       OJSystem.env.record(name, result);
197       return result;
198     }
199 
200     throw new OJClassNotFoundException(name);
201   }
202 
203   private static final OJClass lookupFromByteCode(String name) {
204     OJClass result = null;
205     try {
206       Class javaClass = Class.forName(name);
207       result = forClass(javaClass);
208       if (result != null) {
209         OJSystem.env.record(name, result);
210         return result;
211       }
212     } catch (ClassNotFoundException e) {
213       int dot = name.lastIndexOf('.');
214       if (dot == -1)
215         return null;
216       String innername = replaceDotWithDoller(name, dot);
217       result = lookupFromByteCode(innername);
218     }
219     return result;
220   }
221 
222   private static final String replaceDotWithDoller(String base, int i) {
223     return base.substring(0, i) + '$' + base.substring(i + 1);
224   }
225 
226   private static final boolean isArrayName(String name) {
227     return (name.startsWith("[") || name.endsWith("[]"));
228   }
229 
230   private static final String stripBrackets(String ojcname) {
231     return ojcname.substring(0, ojcname.length() - 2);
232   }
233 
234   private static final String nameForJavaClassName(String jcname) {
235     return Toolbox.nameForJavaClassName(jcname);
236   }
237 
238   private static final String nameToJavaClassName(String ojcname) {
239     return Toolbox.nameToJavaClassName(ojcname);
240   }
241 
242   static OJClass[] arrayForClasses(Class[] jclasses) {
243     OJClass[] result = new OJClass[jclasses.length];
244     for (int i = 0; i < result.length; ++i) {
245       result[i] = forClass(jclasses[i]);
246     }
247     return result;
248   }
249 
250   static Class[] toClasses(OJClass[] classes) {
251     Class[] result = new Class[classes.length];
252     for (int i = 0; i < result.length; ++i) {
253       result[i] = classes[i].getCompatibleJavaClass();
254     }
255     return result;
256   }
257 
258   /**
259    * Converts a <code>OJClass</code> object to an <code>OJClass</code>
260    * object.
261    * <p>
262    * This method returns the same <code>OJClass</code> object
263    * whenever it is invoked for the same <code>Class</code>object.
264    * It gurantees one-to-one correspondence between <code>Class</code>
265    * and <code>OJClass</code>.
266    */
267   public static OJClass forClass(Class javaClass) {
268     if (javaClass == null)
269       return null;
270 
271     String name = nameForJavaClassName(javaClass.getName());
272 
273     OJClass result = OJSystem.env.lookupClass(name);
274     if (result != null)
275       return result;
276 
277     if (isArrayName(name)) {
278       try {
279         OJClass component = forName(stripBrackets(name));
280         result = new OJClass(component);
281         OJSystem.env.record(name, result);
282         return result;
283       } catch (Exception e) {
284         System.err.println("OJClass.forClass(" + name + ") : " + e);
285         /* continue as a non array */
286       }
287     }
288 
289     result = lookupFromMetaInfo(javaClass);
290     OJSystem.env.record(name, result);
291 
292     return result;
293   }
294 
295   private static final OJClass lookupFromMetaInfo(Class javaClass) {
296     MetaInfo metainfo = new MetaInfo(javaClass);
297     String mcname = metainfo.get("instantiates");
298     DebugOut.println(javaClass + " is an instance of " + mcname);
299     try {
300       Class metaclazz = Class.forName(mcname);
301       Class[] paramtypes = new Class[] { Class.class, MetaInfo.class };
302       Constructor constr = metaclazz.getConstructor(paramtypes);
303       Object[] args = new Object[] { javaClass, metainfo };
304       return (OJClass) constr.newInstance(args);
305     } catch (ClassNotFoundException e) {
306       System.err.println(
307         "metaclass "
308           + mcname
309           + " for "
310           + javaClass
311           + " not found."
312           + " substituted by default metaclass.");
313       metainfo = new MetaInfo(javaClass.getName());
314       return new OJClass(javaClass, metainfo);
315     } catch (Exception e) {
316       System.err.println(
317         "metaclass "
318           + mcname
319           + " doesn't provide"
320           + " proper constructor for bytecode."
321           + " substituted by default metaclass. : "
322           + e);
323       metainfo = new MetaInfo(javaClass.getName());
324       return new OJClass(javaClass, metainfo);
325     }
326   }
327 
328   /**
329    * Converts <code>ParseTree</code> objects to an <code>OJClass</code>
330    * object.  The generated <code>OJClass</code> object is to be
331    * registered as globally asscessible class but not to appear as
332    * generated source code.
333    * <p>
334    */
335   public static OJClass forParseTree(
336     Environment env,
337     OJClass declaringClass,
338     ClassDeclaration ptree)
339     throws AmbiguousClassesException, ClassNotFoundException {
340     String qname;
341     if (declaringClass == null) {
342       qname = env.toQualifiedName(ptree.getName());
343     } else {
344       qname = env.currentClassName() + "." + ptree.getName();
345     }
346 
347     Class metaclazz = null;
348     if (ptree.getMetaclass() != null) {
349       String mcname = env.toQualifiedName(ptree.getMetaclass());
350       metaclazz = Class.forName(mcname);
351     } else {
352       metaclazz = OJSystem.getMetabind(qname);
353     }
354 
355     OJClass result;
356     try {
357       Constructor constr =
358         metaclazz.getConstructor(
359           new Class[] {
360             Environment.class,
361             OJClass.class,
362             ClassDeclaration.class });
363       Object[] args = new Object[] { env, declaringClass, ptree };
364       result = (OJClass) constr.newInstance(args);
365     } catch (NoSuchMethodException ex) {
366       System.err.println(
367         "errors during gererating a metaobject for "
368           + ptree.getName()
369           + " : "
370           + ex);
371       result = new OJClass(env, declaringClass, ptree);
372     } catch (InvocationTargetException ex) {
373       System.err.println(
374         "errors during gererating a metaobject for "
375           + ptree.getName()
376           + " : "
377           + ex.getTargetException());
378       ex.printStackTrace();
379       result = new OJClass(env, declaringClass, ptree);
380     } catch (Exception ex) {
381       System.err.println(
382         "errors during gererating a metaobject for "
383           + ptree.getName()
384           + " : "
385           + ex);
386       result = new OJClass(env, declaringClass, ptree);
387     }
388 
389     OJClass existing = OJSystem.env.lookupClass(qname);
390 
391     if (existing != null) {
392       throw new AmbiguousClassesException(qname);
393     }
394 
395     OJSystem.env.record(qname, result);
396     return result;
397   }
398 
399   /**
400    * Generates a expression parse tree from a given
401    * <code>String</code> object under the given environment.
402    *
403    * @param  env  an environment for the source code.
404    * @param  str  a fragment of source code representing an expression.
405    * @return an expression parse tree
406    */
407   protected static final Expression makeExpression(
408     Environment env,
409     String str)
410     throws MOPException {
411     return PartialParser.makeExpression(env, str);
412   }
413 
414   /**
415    * Generates an expression parse tree from a given
416    * <code>String</code> object under the environment of
417    * this class object.
418    *
419    * @param  str  a fragment of source code representing an expression.
420    * @return an expression parse tree
421    */
422   protected final Expression makeExpression(String str) throws MOPException {
423     return makeExpression(getEnvironment(), str);
424   }
425 
426   /**
427    * Generates a statement parse tree from a given
428    * <code>String</code> object under the given environment.
429    *
430    * @param  env  an environment for the source code.
431    * @param  str  a fragment of source code representing a statement.
432    * @return a statement parse tree
433    */
434   protected static final Statement makeStatement(Environment env, String str)
435     throws MOPException {
436     return PartialParser.makeStatement(env, str);
437   }
438 
439   /**
440    * Generates a statement parse tree from a given
441    * <code>String</code> object under the environment of
442    * this class object.
443    *
444    * @param  str  a fragment of source code representing a statement.
445    * @return a statement parse tree
446    */
447   protected final Statement makeStatement(String str) throws MOPException {
448     return makeStatement(getEnvironment(), str);
449   }
450 
451   /**
452    * Generates a statement list parse tree from a given
453    * <code>String</code> object under the given environment.
454    *
455    * @param  env  an environment for the source code.
456    * @param  str  a fragment of source code representing a statement list.
457    * @return a statement list parse tree
458    */
459   protected static final StatementList makeStatementList(
460     Environment env,
461     String str)
462     throws MOPException {
463     return PartialParser.makeStatementList(env, str);
464   }
465 
466   /**
467    * Generates a statement list parse tree from a given
468    * <code>String</code> object under the environment of
469    * this class object.
470    *
471    * @param  str  a fragment of source code representing a statement list.
472    * @return a statement list parse tree
473    */
474   protected final StatementList makeStatementList(String str)
475     throws MOPException {
476     return makeStatementList(getEnvironment(), str);
477   }
478 
479   /**
480    * Converts the object to a string. The string representation is
481    * the string "class" or "interface", followed by a space, and then
482    * by the fully qualified name of the class in the format returned
483    * by <code>getName</code>.  If this <code>OJClass</code> object
484    * represents a primitive type, this method returns the name of the
485    * primitive type.  If this <code>OJClass</code> object represents
486    * void this method returns "void".
487    *
488    * @return a string representation of this class object.
489    */
490   public String toString() {
491     return substance.toString();
492   }
493 
494   /**
495    * Obtains an environment of this class object.
496    * This environment has information about members and outr
497    * environments such as packages but not local information like
498    * local variable in methods of this class.
499    *
500    * @return  an environment of this class object.
501    */
502   public Environment getEnvironment() {
503     return substance.getEnvironment();
504   }
505 
506   /**
507    * Determines if the class or interface represented by this
508    * <code>OJClass</code> object is either the same as, or is a
509    * superclass or superinterface of, the class or interface
510    * represented by the specified <code>OJClass</code> parameter. It
511    * returns <code>true</code> if so; otherwise it returns
512    * <code>false</code>. If this <code>OJClass</code> object
513    * represents a primitive type, this method returns
514    * <code>true</code> if the type represented by this
515    * <code>OJClass</code> object can accept the type represented by
516    * the specified <code>OJClass</code> parameter; otherwise it
517    * returns <code>false</code>.
518    *
519    * <p> Specifically, this method tests whether the type
520    * represented by the specified <code>OJClass</code> parameter can
521    * be converted to the type represented by this
522    * <code>OJClass</code> object via an identity conversion or via a
523    * widening reference/primitive conversion.  <p> The behavior
524    * about primitive types is different from the method of the same
525    * name of <code>java.lang.Class</code>.
526    *
527    * @exception NullPointerException if the specified class parameter is
528    *            null.
529    */
530   public boolean isAssignableFrom(OJClass clazz) {
531     if (clazz.toString() == OJSystem.NULLTYPE_NAME)
532       return true;
533     if (clazz == this) {
534       /* if it is exactly the same type */
535       return true;
536     }
537     if (this.isPrimitive()) {
538       /* the java.lang.Class's returns always false */
539       if (!clazz.isPrimitive())
540         return false;
541       if (clazz == OJSystem.CHAR) {
542         return (
543           primitiveTypeWidth(this)
544             > primitiveTypeWidth(OJSystem.SHORT));
545       }
546       if (primitiveTypeWidth(this) > primitiveTypeWidth(OJSystem.VOID)) {
547         return (primitiveTypeWidth(this) > primitiveTypeWidth(clazz));
548       }
549       return false;
550     } else {
551       if (clazz.isPrimitive())
552         return false;
553     }
554     /* now class is a reference type */
555     if (this == OJSystem.OBJECT)
556       return true;
557     if (this.isArray()) {
558       if (!clazz.isArray())
559         return false;
560       OJClass comp = this.getComponentType();
561       return comp.isAssignableFrom(clazz.getComponentType());
562     } else {
563       if (clazz.isArray())
564         return false;
565     }
566     /* getInterfaces() returns only the declared intefaces
567      * So the interfaces of the superclasses should be checked.
568      */
569     if (this.isInterface()) {
570       /* for an assigning class which is either interface or class */
571       OJClass[] faces = clazz.getInterfaces();
572       for (int i = 0; i < faces.length; ++i) {
573         if (isAssignableFrom(faces[i]))
574           return true;
575       }
576     }
577     /* now this is a class */
578     if (clazz.isInterface())
579       return false;
580     OJClass base = clazz.getSuperclass();
581     return (base == null) ? false : isAssignableFrom(base);
582   }
583 
584   private static int primitiveTypeWidth(OJClass ptype) {
585     if (ptype == OJSystem.BYTE)
586       return 1;
587     if (ptype == OJSystem.SHORT)
588       return 2;
589     if (ptype == OJSystem.INT)
590       return 3;
591     if (ptype == OJSystem.LONG)
592       return 4;
593     if (ptype == OJSystem.FLOAT)
594       return 5;
595     if (ptype == OJSystem.DOUBLE)
596       return 5;
597     return -1;
598   }
599 
600   /**
601    * Determines if the specified <code>OJClass</code> object represents
602    * an interface type.
603    *
604    * @return  <code>true</code> if this object represents an interface;
605    *          <code>false</code> otherwise.
606    */
607   public boolean isInterface() {
608     return substance.isInterface();
609   }
610 
611   /**
612    * Determines if this <code>OJClass</code> object represents an
613    * array class.
614    *
615    * @return  <code>true</code> if this object represents an array class;
616    *          <code>false</code> otherwise.
617    */
618   public boolean isArray() {
619     return substance.isArray();
620   }
621 
622   /**
623    * Determines if the specified <code>OJClass</code> object represents a
624    * primitive type.
625    *
626    * <p> There are nine predefined <code>OJClass</code> objects to represent
627    * the eight primitive types and void.  These are created by the Java
628    * Virtual Machine, and have the same names as the primitive types that
629    * they represent, namely <code>boolean</code>, <code>byte</code>,
630    * <code>char</code>, <code>short</code>, <code>int</code>,
631    * <code>long</code>, <code>float</code>, and <code>double</code>.
632    *
633    * <p> These objects may be accessed via the following public static
634    * final variables, and are the only <code>OJClass</code> objects for
635    * which this method returns <code>true</code>.
636    *
637    * @see     openjava.mop.OJSystem#BOOLEAN
638    * @see     openjava.mop.OJSystem#CHAR
639    * @see     openjava.mop.OJSystem#BYTE
640    * @see     openjava.mop.OJSystem#SHORT
641    * @see     openjava.mop.OJSystem#INT
642    * @see     openjava.mop.OJSystem#LONG
643    * @see     openjava.mop.OJSystem#FLOAT
644    * @see     openjava.mop.OJSystem#DOUBLE
645    * @see     openjava.mop.OJSystem#VOID
646    *
647    * @return  <code>true</code> if this object represents a primitive type;
648    *          <code>false</code> otherwise.
649    */
650   public boolean isPrimitive() {
651     return substance.isPrimitive();
652   }
653 
654   /**
655    * Determines if the specified <code>OJClass</code> object represents a
656    * wrapper class for a primitive type.
657    *
658    * @return  <code>true</code> if this object represents a wrapper class
659    *          for a primitive type; <code>false</code> otherwise.
660    */
661   public boolean isPrimitiveWrapper() {
662     return (this != unwrappedPrimitive());
663   }
664 
665   /**
666    * Obtains the wrapper class if this class represents a primitive
667    * type.
668    * <p>
669    * For example this method returns java.lang.Integer for int.
670    *
671    * @return The wrapper class for this primitive type.
672    *         <code>null</code> for void.
673    */
674   public OJClass primitiveWrapper() {
675     if (this == OJSystem.VOID)
676       return null;
677     if (this == OJSystem.BOOLEAN)
678       return OJClass.forClass(java.lang.Boolean.class);
679     if (this == OJSystem.BYTE)
680       return OJClass.forClass(java.lang.Byte.class);
681     if (this == OJSystem.CHAR)
682       return OJClass.forClass(java.lang.Character.class);
683     if (this == OJSystem.SHORT)
684       return OJClass.forClass(java.lang.Short.class);
685     if (this == OJSystem.INT)
686       return OJClass.forClass(java.lang.Integer.class);
687     if (this == OJSystem.LONG)
688       return OJClass.forClass(java.lang.Long.class);
689     if (this == OJSystem.FLOAT)
690       return OJClass.forClass(java.lang.Float.class);
691     if (this == OJSystem.DOUBLE)
692       return OJClass.forClass(java.lang.Double.class);
693     //otherwise returns as is
694     return this;
695   }
696 
697   /**
698    * Obtains the real type class if this class represents a primitive
699    * wrapper type.
700    * <p>
701    * For example this method returns int for java.lang.Integer.
702    *
703    * @return The real primitive type for this primitive wrapper class.
704    */
705   public OJClass unwrappedPrimitive() {
706     if (this == OJClass.forClass(java.lang.Boolean.class))
707       return OJSystem.BOOLEAN;
708     if (this == OJClass.forClass(java.lang.Byte.class))
709       return OJSystem.BYTE;
710     if (this == OJClass.forClass(java.lang.Character.class))
711       return OJSystem.CHAR;
712     if (this == OJClass.forClass(java.lang.Short.class))
713       return OJSystem.SHORT;
714     if (this == OJClass.forClass(java.lang.Integer.class))
715       return OJSystem.INT;
716     if (this == OJClass.forClass(java.lang.Long.class))
717       return OJSystem.LONG;
718     if (this == OJClass.forClass(java.lang.Float.class))
719       return OJSystem.FLOAT;
720     if (this == OJClass.forClass(java.lang.Double.class))
721       return OJSystem.DOUBLE;
722     //otherwise returns as is
723     return this;
724   }
725 
726   /**
727    * Returns the fully-qualified name of the entity (class,
728    * interface, array class, primitive type, or void) represented by
729    * this <code>OJClass</code> object, as a <code>String</code>.
730    *
731    * <p> If this <code>OJClass</code> object represents a class of
732    * arrays, then the internal form of the name consists of the name
733    * of the element type in Java signature format, followed by one
734    * or more "<tt>[]</tt>" characters representing the depth of array
735    * nesting. This representation differs from that of
736    * <code>java.lang.Class.forName()</code>. Thus:
737    *
738    * <blockquote><pre>
739    * OJClass.forClass( (new int[3][4]).getClass() ).getName()
740    * </pre></blockquote>
741    *
742    * returns "<code>java.lang.Object[]</code>" and:
743    *
744    * <blockquote><pre>
745    * OJClass.forClass( (new int[3][4]).getClass() ).getName()
746    * </pre></blockquote>
747    *
748    * returns "<code>int[][]</code>".
749    *
750    * <p> The class or interface name <tt><i>classname</i></tt> is
751    * given in fully qualified form as shown in the example above.
752    *
753    * @return  the fully qualified name of the class or interface
754    *          represented by this object.
755    */
756   public String getName() {
757     return substance.getName();
758   }
759 
760   /**
761    * Returns the simple name of the class, interface or array class
762    * represented by this <code>OJClass</code> object, as a
763    * <code>String</code>.  Thus:
764    *
765    * <blockquote><pre>
766    * OJClass.forClass( (new Object[3]).getClass() ).getName()
767    * </pre></blockquote>
768    *
769    * returns "<code>Object</code>".
770    *
771    * @return  the simple name of the class or interface
772    *          represented by this object.
773    */
774   public String getSimpleName() {
775     return Environment.toSimpleName(getName());
776   }
777 
778   /**
779    * Gets the package name for this class as a <code>String</code>.
780    * Null is returned if its package was not specified in source code of
781    * this class.
782    *
783    * @return the package name of the class, or null if its package
784    *         was not specified in source code.
785    */
786   public String getPackage() {
787     int last = getName().lastIndexOf('.');
788     if (last == -1)
789       return null;
790     return getName().substring(0, last);
791   }
792 
793   /**
794    * Determines if the specified class object is in the same package
795    * as this class object.
796    *
797    * <p>If null is given, this method returns alway false.
798    *
799    * @param c the class object to test against this class object.
800    * @return true in case that both class is is the sample package.
801    */
802   public boolean isInSamePackage(OJClass c) {
803     if (c == null)
804       return false;
805     String pack = c.getPackage();
806     if (pack == null)
807       return (getPackage() == null);
808     return pack.equals(getPackage());
809   }
810 
811   /**
812    * Returns the <code>OJClass</code> representing the superclass of
813    * the entity (class, interface, primitive type or void)
814    * represented by this <code>OJClass</code>.  If this
815    * <code>OJClass</code> represents either the
816    * <code>java.lang.Object</code> class, an interface, a primitive
817    * type, or void, then null is returned.  If this object
818    * represents an array class then the <code>OJClass</code> object
819    * representing the <code>java.lang.Object</code> class is
820    * returned.
821    *
822    * @return  the superclass of the class represented by this object.
823    */
824   public OJClass getSuperclass() {
825     return substance.getSuperclass();
826   }
827 
828   /**
829    * Determines the interfaces implemented by the class or interface
830    * represented by this object.
831    *
832    * <p> If this object represents a class, the return value is an array
833    * containing objects representing all interfaces implemented by the
834    * class. The order of the interface objects in the array corresponds to
835    * the order of the interface names in the <code>implements</code> clause
836    * of the declaration of the class represented by this object. For
837    * example, given the declaration:
838    * <blockquote><pre>
839    * class Shimmer implements FloorWax, DessertTopping { ... }
840    * </pre></blockquote>
841    * suppose the value of <code>clazz</code> is an class object for
842    * the class <code>Shimmer</code>; the value of the expression:
843    * <blockquote><pre>
844    * clazz.getInterfaces()[0]
845    * </pre></blockquote>
846    * is the <code>OJClass</code> object that represents interface
847    * <code>FloorWax</code>; and the value of:
848    * <blockquote><pre>
849    * clazz.getInterfaces()[1]
850    * </pre></blockquote>
851    * is the <code>OJClass</code> object that represents interface
852    * <code>DessertTopping</code>.
853    *
854    * <p> If this object represents an interface, the array contains
855    * objects representing all interfaces extended by the
856    * interface. The order of the interface objects in the array
857    * corresponds to the order of the interface names in the
858    * <code>extends</code> clause of the declaration of the interface
859    * represented by this object.
860    *
861    * <p> If this object represents a class or interface that
862    * implements no interfaces, the method returns an array of length
863    * 0.
864    *
865    * <p> If this object represents a primitive type or void, the
866    * method returns an array of length 0.
867    *
868    * <p> To be <code>getDeclaredInterfaces()<code>.
869    *
870    * @return an array of interfaces implemented by this class object.
871    */
872   public OJClass[] getInterfaces() {
873     return substance.getInterfaces();
874   }
875 
876   /**
877    * Returns the <code>OJClass</code> representing the component type of an
878    * array.  If this class does not represent an array class this method
879    * returns null.
880    *
881    * @return the class object representing the type of component of this
882    *         array.
883    */
884   public OJClass getComponentType() {
885     return substance.getComponentType();
886   }
887 
888   /**
889    * Returns the Java language modifiers and the user defined modifiers
890    * for this class or interface, as a <code>OJModifier</code> object.
891    *
892    * <p> If the underlying class is an array class, then its
893    * <code>public</code>, <code>private</code> and <code>protected</code>
894    * modifiers are the same as those of its component type.  If this
895    * <code>OJClass</code> represents a primitive type or void, its
896    * <code>public</code> modifier is always <code>true</code>, and its
897    * <code>protected</code> and <code>private</code> modifers are always
898    * <code>false</code>. If this object represents an array class, a
899    * primitive type or void, then its <code>final</code> modifier is always
900    * <code>true</code> and its interface modifer is always
901    * <code>false</code>. The values of its other modifiers are not determined
902    * by this specification.
903    *
904    * @see     openjava.mop.OJModifier
905    *
906    * @return the OJModifier object representing the modifiers of this class
907    *         object
908    */
909   public OJModifier getModifiers() {
910     return substance.getModifiers();
911   }
912 
913   /**
914    * Obtains an parse tree of suffix in extended syntax starting
915    * with the specified keyword.  Returned
916    * <code>openjava.ptree.ParseTree</code> object has a structure
917    * built by an <code>openjava.syntax.SyntaxRule</code> object
918    * returned via the method <code>getDeclSuffixRule(String)</code>.
919    *
920    * @see openjava.mop.OJClass#getDeclSuffixRule(String)
921    * @see openjava.syntax.SyntaxRule
922    *
923    * @return the parse tree
924    */
925   public ParseTree getSuffix(String keyword) {
926     return substance.getSuffix(keyword);
927   }
928 
929   /**
930    * If the class or interface represented by this
931    * <code>OJClass</code> object is a member of another class,
932    * returns the <code>OJClass</code> object representing the class
933    * in which it was declared.  This method returns null if this
934    * class or interface is not a member of any other class.  If this
935    * <code>OJClass</code> object represents an array class, a
936    * primitive type, or void, then this method returns null.
937    *
938    * @return  the class object declaring this class object.
939    */
940   public OJClass getDeclaringClass() {
941     return substance.getDeclaringClass();
942   }
943 
944   public final OJClass[] getAllClasses() {
945     return overridesOn(getDeclaredClasses(), getInheritedClasses());
946   }
947 
948   public final OJField[] getAllFields() {
949     return overridesOn(getDeclaredFields(), getInheritedFields());
950   }
951 
952   public final OJMethod[] getAllMethods() {
953     return overridesOn(getDeclaredMethods(), getInheritedMethods());
954   }
955 
956   public OJClass[] getInheritedClasses() {
957     OJClass base = getSuperclass();
958     if (base == null) {
959       return new OJClass[0];
960     } else {
961       return base.getInheritableClasses(this);
962     }
963   }
964 
965   public OJField[] getInheritedFields() {
966     OJClass base = getSuperclass();
967     OJField[] base_f;
968     if (base == null) {
969       base_f = new OJField[0];
970     } else {
971       base_f = base.getInheritableFields(this);
972     }
973     int len = base_f.length;
974     OJClass[] faces = getInterfaces();
975     OJField[][] face_fs = new OJField[faces.length][];
976     for (int i = 0; i < faces.length; ++i) {
977       face_fs[i] = faces[i].getInheritableFields(this);
978       len += face_fs[i].length;
979     }
980     OJField[] result = new OJField[len];
981     int count = 0;
982     for (int i = 0; i < faces.length; ++i) {
983       System.arraycopy(face_fs[i], 0, result, count, face_fs[i].length);
984       count += face_fs[i].length;
985     }
986     System.arraycopy(base_f, 0, result, count, base_f.length);
987     return result;
988   }
989 
990   public final OJMethod[] getInheritedMethods() {
991     OJClass base = getSuperclass();
992     OJMethod[] base_m;
993     if (base == null) {
994       base_m = new OJMethod[0];
995     } else {
996       base_m = base.getInheritableMethods(this);
997     }
998     int len = base_m.length;
999     OJClass[] faces = getInterfaces();
1000    OJMethod[][] face_ms = new OJMethod[faces.length][];
1001    for (int i = 0; i < faces.length; ++i) {
1002      face_ms[i] = faces[i].getInheritableMethods(this);
1003      len += face_ms[i].length;
1004    }
1005    OJMethod[] result = new OJMethod[len];
1006    int count = 0;
1007    for (int i = 0; i < faces.length; ++i) {
1008      System.arraycopy(face_ms[i], 0, result, count, face_ms[i].length);
1009      count += face_ms[i].length;
1010    }
1011    System.arraycopy(base_m, 0, result, count, base_m.length);
1012    return result;
1013  }
1014
1015  /**
1016   * Use <code>getInheritableClasses(OJClass)</code>
1017   * @deprecated
1018   * @see getInheritableClasses(OJClass)
1019   */
1020  public final OJClass[] getInheritableClasses() {
1021    OJClass[] nonprivates = removeThePrivates(getAllClasses());
1022    return removeTheDefaults(nonprivates);
1023  }
1024
1025  /**
1026   * Use <code>getInheritableFields(OJClass)</code>
1027   * @deprecated
1028   * @see getInheritableFields(OJClass)
1029   */
1030  public final OJField[] getInheritableFields() {
1031    OJField[] nonprivates = removeThePrivates(getAllFields());
1032    return removeTheDefaults(nonprivates);
1033  }
1034
1035  /**
1036   * Use <code>getInheritableMethods(OJClass)</code>
1037   * @deprecated
1038   * @see getInheritableMethodss(OJClass)
1039   */
1040  public final OJMethod[] getInheritableMethods() {
1041    OJMethod[] nonprivates = removeThePrivates(getAllMethods());
1042    return removeTheDefaults(nonprivates);
1043  }
1044
1045  public OJClass[] getInheritableClasses(OJClass situation) {
1046    OJClass[] result = removeThePrivates(getAllClasses());
1047    if (isInSamePackage(situation))
1048      return result;
1049    return removeTheDefaults(result);
1050  }
1051
1052  public OJField[] getInheritableFields(OJClass situation) {
1053    OJField[] result = removeThePrivates(getAllFields());
1054    if (isInSamePackage(situation))
1055      return result;
1056    return removeTheDefaults(result);
1057  }
1058
1059  public OJMethod[] getInheritableMethods(OJClass situation) {
1060    OJMethod[] result = removeThePrivates(getAllMethods());
1061    if (isInSamePackage(situation))
1062      return result;
1063    return removeTheDefaults(result);
1064  }
1065
1066  public OJConstructor[] getInheritableConstructors(OJClass situation) {
1067    OJConstructor[] result = removeThePrivates(getDeclaredConstructors());
1068    if (isInSamePackage(situation))
1069      return result;
1070    return removeTheDefaults(result);
1071  }
1072
1073  private static final OJClass[] overridesOn(
1074    OJClass[] declareds,
1075    OJClass[] bases) {
1076    return Toolbox.overridesOn(declareds, bases);
1077  }
1078
1079  private static final OJField[] overridesOn(
1080    OJField[] declareds,
1081    OJField[] bases) {
1082    return Toolbox.overridesOn(declareds, bases);
1083  }
1084
1085  private static final OJMethod[] overridesOn(
1086    OJMethod[] declareds,
1087    OJMethod[] bases) {
1088    return Toolbox.overridesOn(declareds, bases);
1089  }
1090
1091  private static final OJClass[] removeThePrivates(OJClass[] src_classes) {
1092    return Toolbox.removeThePrivates(src_classes);
1093  }
1094
1095  private static final OJField[] removeThePrivates(OJField[] src_fields) {
1096    return Toolbox.removeThePrivates(src_fields);
1097  }
1098
1099  private static final OJMethod[] removeThePrivates(OJMethod[] src_methods) {
1100    return Toolbox.removeThePrivates(src_methods);
1101  }
1102
1103  private static final OJConstructor[] removeThePrivates(OJConstructor[] src_constrs) {
1104    return Toolbox.removeThePrivates(src_constrs);
1105  }
1106
1107  private static final OJClass[] removeTheDefaults(OJClass[] src_classes) {
1108    return Toolbox.removeTheDefaults(src_classes);
1109  }
1110
1111  private static final OJField[] removeTheDefaults(OJField[] src_fields) {
1112    return Toolbox.removeTheDefaults(src_fields);
1113  }
1114
1115  private static final OJMethod[] removeTheDefaults(OJMethod[] src_methods) {
1116    return Toolbox.removeTheDefaults(src_methods);
1117  }
1118
1119  private static final OJConstructor[] removeTheDefaults(OJConstructor[] src_constrs) {
1120    return Toolbox.removeTheDefaults(src_constrs);
1121  }
1122
1123  private static final OJClass[] removeTheNonPublics(OJClass[] src_classes) {
1124    return Toolbox.removeTheNonPublics(src_classes);
1125  }
1126
1127  private static final OJField[] removeTheNonPublics(OJField[] src_fields) {
1128    return Toolbox.removeTheNonPublics(src_fields);
1129  }
1130
1131  private static final OJMethod[] removeTheNonPublics(OJMethod[] src_methods) {
1132    return Toolbox.removeTheNonPublics(src_methods);
1133  }
1134
1135  private static final OJConstructor[] removeTheNonPublics(OJConstructor[] src_constrs) {
1136    return Toolbox.removeTheNonPublics(src_constrs);
1137  }
1138
1139  private static final OJMethod[] pickupMethodsByName(
1140    OJMethod[] src_methods,
1141    String name) {
1142    return Toolbox.pickupMethodsByName(src_methods, name);
1143  }
1144
1145  private static final OJField pickupField(
1146    OJField[] src_fields,
1147    String name) {
1148    return Toolbox.pickupField(src_fields, name);
1149  }
1150
1151  private static final OJMethod pickupMethod(
1152    OJMethod[] src_methods,
1153    String name,
1154    OJClass[] parameterTypes) {
1155    return Toolbox.pickupMethod(src_methods, name, parameterTypes);
1156  }
1157
1158  private static final OJConstructor pickupConstructor(
1159    OJConstructor[] src_constrs,
1160    OJClass[] parameterTypes) {
1161    return Toolbox.pickupConstructor(src_constrs, parameterTypes);
1162  }
1163
1164  private static final OJMethod pickupAcceptableMethod(
1165    OJMethod[] src_methods,
1166    String name,
1167    OJClass[] parameterTypes) {
1168    return Toolbox.pickupAcceptableMethod(
1169      src_methods,
1170      name,
1171      parameterTypes);
1172  }
1173
1174  private static final OJConstructor pickupAcceptableConstructor(
1175    OJConstructor[] src_constrs,
1176    OJClass[] parameterTypes) {
1177    return Toolbox.pickupAcceptableConstructor(src_constrs, parameterTypes);
1178  }
1179
1180  /**
1181   * Returns an array containing <code>OJClass</code> objects
1182   * representing all the <em>public</em> classes and interfaces
1183   * that are members of the class represented by this
1184   * <code>OJClass</code> object.  This includes public class and
1185   * interface members inherited from superclasses and public class
1186   * and interface members declared by the class.  This method
1187   * returns an array of length 0 if this <code>OJClass</code>
1188   * object has no public member classes or interfaces.  This method
1189   * also returns an array of length 0 if this <code>OJClass</code>
1190   * object represents a primitive type, an array class, or void.
1191   *
1192   */
1193  public OJClass[] getClasses() {
1194    return removeTheNonPublics(getAllClasses());
1195  }
1196
1197  /**
1198   * Returns an array containing <code>OJField</code> objects
1199   * reflecting all the accessible <em>public</em> fields of the
1200   * class or interface represented by this <code>OJClass</code>
1201   * object.  The elements in the array returned are not sorted and
1202   * are not in any particular order.  This method returns an array
1203   * of length 0 if the class or interface has no accessible public
1204   * fields, or if it represents an array class, a primitive type,
1205   * or void.
1206   *
1207   * <p> Specifically, if this <code>OJClass</code> object
1208   * represents a class, this method returns the public fields of
1209   * this class and of all its superclasses.  If this
1210   * <code>OJClass</code> object represents an interface, this
1211   * method returns the fields of this interface and of all its
1212   * superinterfaces.
1213   *
1214   * <p> The implicit length field for array classs is reflected by this
1215   * method.
1216   *
1217   * @see openjava.mop.OJField
1218   */
1219  public OJField[] getFields() {
1220    return removeTheNonPublics(getAllFields());
1221  }
1222
1223  /**
1224   * Returns an array containing <code>OJMethod</code> objects
1225   * reflecting all the <em>public</em> member methods of the class
1226   * or interface represented by this <code>OJClass</code> object,
1227   * including those declared by the class or interface and and
1228   * those inherited from superclasses and superinterfaces.  The
1229   * elements in the array returned are not sorted and are not in
1230   * any particular order.  This method returns an array of length 0
1231   * if this <code>OJClass</code> object represents a class or
1232   * interface that has no public member methods, or if this
1233   * <code>OJClass</code> object represents an array class, primitive
1234   * type, or void.
1235   *
1236   * @see       openjava.mop.OJMethod
1237   */
1238  public OJMethod[] getMethods() {
1239    return removeTheNonPublics(getAllMethods());
1240  }
1241
1242  /**
1243   * Returns an array containing <code>OJConstructor</code> objects
1244   * reflecting all the <em>public</em> constructors of the class
1245   * represented by this <code>OJClass</code> object.  An array of
1246   * length 0 is returned if the class has no public constructors,
1247   * or if the class is an array class, or if the class reflects a
1248   * primitive type or void.
1249   *
1250   * @see openjava.mop.OJConstructor
1251   */
1252  public OJConstructor[] getConstructors() {
1253    return removeTheNonPublics(getDeclaredConstructors());
1254  }
1255
1256  /**
1257   * Returns a <code>OJField</code> object that reflects the
1258   * specified <em>public</em> member field of the class or
1259   * interface represented by this <code>OJClass</code> object. The
1260   * <code>name</code> parameter is a <code>String</code> specifying
1261   * the simple name of the desired field.
1262   *
1263   * @exception NoSuchMemberException if a field with the specified name is
1264   *              not found.
1265   * @see openjava.mop.OJField
1266   */
1267  public OJField getField(String name) throws NoSuchMemberException {
1268    OJField field = pickupField(getFields(), name);
1269    if (field != null)
1270      return field;
1271    throw new NoSuchMemberException(name);
1272  }
1273
1274  /**
1275   * Returns a <code>OJMethod</code> object that reflects the
1276   * specified public member method of the class or interface
1277   * represented by this <code>OJClass</code> object. The
1278   * <code>name</code> parameter is a <code>String</code> specifying
1279   * the simple name the desired method. The
1280   * <code>parameterTypes</code> parameter is an array of
1281   * <code>OJClass</code> objects that identify the method's formal
1282   * parameter types, in declared order. If
1283   * <code>parameterTypes</code> is <code>null</code>, it is treated
1284   * as if it were an empty array.
1285   *
1286   * @exception NoSuchMemberException if a matching method is not found
1287   *            or if then name is "&lt;init>"or "&lt;clinit>".
1288   * @see openjava.mop.OJMethod
1289   */
1290  public OJMethod getMethod(String name, OJClass[] parameterTypes)
1291    throws NoSuchMemberException {
1292    OJMethod method = pickupMethod(getMethods(), name, parameterTypes);
1293    if (method != null)
1294      return method;
1295    Signature sign = new Signature(name, parameterTypes);
1296    throw new NoSuchMemberException(sign.toString());
1297  }
1298
1299  /**
1300   * Returns a <code>OJConstructor</code> object that reflects the
1301   * specified public constructor of the class represented by this
1302   * <code>OJClass</code> object. The <code>parameterTypes</code>
1303   * parameter is an array of <code>OJClass</code> objects that
1304   * identify the constructor's formal parameter types, in declared
1305   * order.
1306   *
1307   * <p> The constructor to reflect is the public constructor of the
1308   * class represented by this <code>OJClass</code> object whose
1309   * formal parameter types match those specified by
1310   * <code>parameterTypes</code>.
1311   *
1312   * @exception NoSuchMemberException if a matching method is not found.
1313   * @see openjava.mop.OJConstructor
1314   */
1315  public OJConstructor getConstructor(OJClass[] parameterTypes)
1316    throws NoSuchMemberException {
1317    OJConstructor constr =
1318      pickupConstructor(getConstructors(), parameterTypes);
1319    if (constr != null)
1320      return constr;
1321    Signature sign = new Signature(parameterTypes);
1322    throw new NoSuchMemberException(sign.toString());
1323  }
1324
1325  /**
1326   * Returns an array containing <code>OJClass</code> objects
1327   * representing all the classes and interfaces which are members
1328   * of the class represented by this <code>OJClass</code> object,
1329   * accessible from the situation represented by the given
1330   * <code>OJClass</code> object.  This includes class and interface
1331   * members inherited from superclasses and declared class and
1332   * interface members accessible from the given situation.  This
1333   * method returns an array of length 0 if this
1334   * <code>OJClass</cod