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 "<init>"or "<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