KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > alt > jiapi > reflect > JiapiClass


1 /*
2  * Copyright (C) 2001 Mika Riekkinen, Joni Suominen
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  */

18
19 package alt.jiapi.reflect;
20
21 import java.io.IOException JavaDoc;
22 import java.io.OutputStream JavaDoc;
23 import java.io.ByteArrayInputStream JavaDoc;
24 import java.lang.reflect.Modifier JavaDoc;
25 import java.net.URL JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.LinkedList JavaDoc;
31 import java.util.Map JavaDoc;
32
33 import org.apache.log4j.Category;
34
35 import alt.jiapi.InstrumentationContext;
36 import alt.jiapi.JiapiException;
37 import alt.jiapi.Runtime;
38
39 import alt.jiapi.file.Attribute;
40 import alt.jiapi.file.ClassFile;
41 import alt.jiapi.file.ConstantPool;
42 import alt.jiapi.file.Field;
43 import alt.jiapi.file.Interface;
44 import alt.jiapi.file.Method;
45
46 /**
47  * This class represents a bytecode of a Class.
48  * It contains methods to add and remove <code>JiapiMethod</code>s and
49  * <code>JiapiField</code>s.
50  * <p>
51  * JiapiClass is an abstract class. Concrete classes are loaded
52  * using Loader.
53  * <blockquote>
54  * <code>
55  * Loader loader = new Loader();
56  * JiapiClass clazz = loader.loadClass(className);
57  * </code>
58  * </blockquote>
59  *
60  * @author Mika Riekkinen
61  * @author Joni Suominen
62  * @version $Revision: 1.30 $ $Date: 2005/05/24 12:10:26 $
63  * @see Loader
64  */

65 public class JiapiClass {
66     // Used in Collection.toArray(fieldArrayTemplate)
67
private static final JiapiField[] fieldArrayTemplate = new JiapiField[0];
68     private static final JiapiMethod[] methodArrayTemplate =new JiapiMethod[0];
69
70     private static Category log = Runtime.getLogCategory(JiapiClass.class);
71
72     private Loader loader; // Loader that loaded this JiapiClass
73
private ClassBuilder builder;
74     private ClassFile clazz;
75
76     private List JavaDoc jiapiMethods;
77     private List JavaDoc jiapiFields;
78
79     // Used for testing
80
public static void main(String JavaDoc[] args) throws Exception JavaDoc {
81         Loader l = new Loader();
82         JiapiClass jc = l.loadClass(args[0]);
83         System.out.println(jc);
84     }
85
86
87     /**
88      * Create empty JiapiClass.
89      * Created JiapiClass has all internal datastructures initialized so,
90      * that when dumped to byte[], it is a valid java class file.
91      * It has not methods, fields etc.
92      *
93      * @param name Name of the JiapiClass to create
94      * @return an instance of JiapiClass
95      */

96     public static JiapiClass createClass(String JavaDoc name) {
97         ClassFile cf = new ClassFile(name);
98         return new JiapiClass(cf);
99     }
100
101
102     /**
103      * Parses byte[] for a class definition.
104      */

105     public static JiapiClass parseClass(byte[] bytes) throws IOException JavaDoc {
106     ByteArrayInputStream JavaDoc bais = new ByteArrayInputStream JavaDoc(bytes);
107
108         ClassFile cf = ClassFile.parse(bais);
109         return new JiapiClass(cf);
110     }
111
112
113     private JiapiClass() {
114     }
115
116
117     JiapiClass(ClassFile classFile) {
118         this.clazz = classFile;
119         this.builder = new ClassBuilder(classFile);
120     this.loader = new Loader();
121
122         jiapiMethods = new LinkedList JavaDoc();
123         jiapiFields = new LinkedList JavaDoc();
124
125         List JavaDoc methods = clazz.getMethods();
126         Iterator JavaDoc i = methods.iterator();
127         while(i.hasNext()) {
128             Method m = (Method)i.next();
129
130             JiapiMethod jm = new JiapiMethod(m);
131             jm.setDeclaringClass(this);
132
133             jiapiMethods.add(jm);
134         }
135
136
137         List JavaDoc fields = clazz.getFields();
138         i = fields.iterator();
139         while(i.hasNext()) {
140             Field f = (Field)i.next();
141
142             JiapiField jf = new JiapiField(f);
143             jf.setDeclaringClass(this);
144
145             jiapiFields.add(jf);
146         }
147     }
148
149
150     /**
151      * Dumps bytecodes of this JiapiClass to OutputStream given.
152      * @param out OutputStream to use
153      */

154     public void dump(OutputStream JavaDoc out) throws IOException JavaDoc {
155         out.write(getByteCode());
156     }
157
158     
159     /**
160      * Gets the Loader, that loaded this JiapiClass.
161      *
162      * @return Loader
163      */

164     public Loader getLoader() {
165         return loader;
166     }
167
168
169     /**
170      * Get name of a class.
171      *
172      * @return name of a class
173      */

174     public String JavaDoc getName() {
175         return clazz.getClassName();
176     }
177
178     /**
179      * Get the package where this class is defined.
180      *
181      * @return a package name of a class, or null if this class does
182      * not belong to any package.
183      */

184     public String JavaDoc getPackageName() {
185         String JavaDoc cName = getName();
186         int idx = cName.lastIndexOf('.'); // NOTE: InnerClasses ???
187
if (idx == -1) {
188             return null;
189         }
190
191         return cName.substring(0, idx);
192     }
193
194     /**
195      * Get the byte-code of this class.
196      *
197      * @return an array of bytecodes
198      */

199     public byte[] getByteCode() {
200         // Loop methods for changed bytecode
201
JiapiMethod[] methods = getDeclaredMethods();
202         for(int i = 0; i < methods.length; i++) {
203             methods[i].update();
204         }
205
206         return clazz.toBytes();
207     }
208
209
210     /**
211      * Get all the methods of this JiapiClass and its superclasses.
212      *
213      * @return an array of methods in this class
214      * @see #getDeclaredMethods() getDeclaredMethods() for further info
215      * @exception ClassNotFoundException is thrown if superclass could
216      * not be loaded
217      */

218     public JiapiMethod[] getMethods() throws ClassNotFoundException JavaDoc {
219         ArrayList JavaDoc al = new ArrayList JavaDoc();
220         JiapiClass jc = this;
221
222         do {
223             al.addAll(jc.jiapiMethods);
224         }
225         while((jc = jc.getSuperclass()) != null);
226
227         return (JiapiMethod[])al.toArray(methodArrayTemplate);
228     }
229
230     /**
231      * Get all the methods of this JiapiClass. If this JiapiClass
232      * has no methods, an array of length 0 is returned. A new array is created
233      * each time this method is called, so adding and removing items from array
234      * does not reflect such changes back into JiapiClass.
235      *
236      * @return an array of methods in this class
237      */

238     public JiapiMethod[] getDeclaredMethods() {
239         ArrayList JavaDoc al = new ArrayList JavaDoc();
240         al.addAll(jiapiMethods);
241
242         return (JiapiMethod[])al.toArray(methodArrayTemplate);
243     }
244
245
246     /**
247      * Get a specific method from a class. Parameter type names are given
248      * in simple form. This would be the same as used when programming java
249      * code. Some examples of simple form: <code>java.lang.Object</code>,
250      * <code>int</code>, <code>int[]</code>, <code>my.stuff.Thing[]</code><p>
251      * Example:
252      * <pre>
253      * JiapiClass clazz = ...;
254      * String[] paramTypeNames = new String[] {"java.lang.Object[]", "int"};
255      * JiapiMethod m = clazz.getMethod("foo", paramTypeNames);
256      * </pre>
257      * Would return a method <code>foo(Object[], int)</code>
258      *
259      * @param name Name of the method
260      * @param parameterTypeNames Type names of the parameters
261      * @return a method which matches the given name and parameter types
262      * @exception NoSuchMethodException if matching method is not found
263      */

264     public JiapiMethod getDeclaredMethod(String JavaDoc name,
265                                          String JavaDoc[] parameterTypeNames) throws NoSuchMethodException JavaDoc {
266         Signature otherSignature = new Signature("void", parameterTypeNames);
267
268         Iterator JavaDoc i = jiapiMethods.iterator();
269         while (i.hasNext()) {
270             JiapiMethod jm = (JiapiMethod)i.next();
271             if (jm.getName().equals(name)) {
272                 if (jm.getSignature().equals(otherSignature)) {
273                     return jm;
274                 }
275             }
276         }
277
278         throw new NoSuchMethodException JavaDoc(name + otherSignature.toString());
279     }
280
281     /**
282      * Get a specific method from a class.
283      *
284      * @param parameterTypes An array of JiapiClass, where each element
285      * represents a parameter.
286      * @return a method which matches the given name and parameter types
287      * @exception NoSuchMethodException if matching method is not found
288      */

289     public JiapiMethod getDeclaredMethod(String JavaDoc name,
290                                          JiapiClass[] parameterTypes)
291             throws NoSuchMethodException JavaDoc {
292
293         String JavaDoc[] parameterTypeNames = null;
294         if (parameterTypes != null) {
295             parameterTypeNames = new String JavaDoc[parameterTypes.length];
296             for (int i = 0; i < parameterTypes.length; i++) {
297                 parameterTypeNames[i] = parameterTypes[i].getName();
298             }
299         }
300
301         return getDeclaredMethod(name, parameterTypeNames);
302     }
303
304
305     /**
306      * Get a specific method from a class or any of its superclasses.
307      * Parameter type names are given in simple form. This would be the
308      * same as used when programming java
309      * code. Some examples of simple form: <code>java.lang.Object</code>,
310      * <code>int</code>, <code>int[]</code>, <code>my.stuff.Thing[]</code><p>
311      * Example:
312      * <pre>
313      * JiapiClass clazz = ...;
314      * String[] paramTypeNames = new String[] {"java.lang.Object[]", "int"};
315      * JiapiMethod m = clazz.getMethod("foo", paramTypeNames);
316      * </pre>
317      * Would return a method <code>foo(Object[], int)</code>
318      *
319      * @param name Name of the method
320      * @param parameterTypeNames Type names of the parameters
321      * @return a method which matches the given name and parameter types
322      * @exception NoSuchMethodException if matching method is not found
323      * @exception ClassNotFoundException is thrown if superclass could
324      * not be loaded
325      */

326     public JiapiMethod getMethod(String JavaDoc name, String JavaDoc[] parameterTypeNames)
327             throws NoSuchMethodException JavaDoc, ClassNotFoundException JavaDoc {
328         JiapiClass jc = this;
329         JiapiMethod method = null;
330
331         do {
332             try {
333                 method = jc.getDeclaredMethod(name, parameterTypeNames);
334                 return method;
335             } catch (NoSuchMethodException JavaDoc nsme) {
336                 // Don't mind.
337
}
338         }
339         while ((jc = jc.getSuperclass()) != null);
340
341         throw new NoSuchMethodException JavaDoc(name);
342     }
343
344     /**
345      * Get a specific method from a class or any of its superclasses.
346      *
347      * @param parameterTypes An array of JiapiClass, where each element
348      * represents a parameter.
349      * @return a method which matches the given name and parameter types
350      * @exception NoSuchMethodException if matching method is not found
351      * @exception ClassNotFoundException is thrown if superclass could
352      * not be loaded
353      */

354     public JiapiMethod getMethod(String JavaDoc name, JiapiClass[] parameterTypes)
355             throws NoSuchMethodException JavaDoc, ClassNotFoundException JavaDoc {
356         JiapiClass jc = this;
357         JiapiMethod method = null;
358
359         do {
360             try {
361                 method = jc.getDeclaredMethod(name, parameterTypes);
362                 return method;
363             } catch (NoSuchMethodException JavaDoc nsme) {
364                 // Don't mind.
365
}
366         }
367         while ((jc = jc.getSuperclass()) != null);
368
369         throw new NoSuchMethodException JavaDoc(name);
370     }
371
372
373     /**
374      * Get all the Fields of this JiapiClass and its superclasses.
375      * All of the fields in this class and superclasses are returned.
376      *
377      * @return an array of fields in this class and its superclasses
378      * @see #getDeclaredFields getDeclaredFields() for further info
379      * @exception ClassNotFoundException is thrown if superclass could
380      * not be loaded
381      */

382     public JiapiField[] getFields() throws ClassNotFoundException JavaDoc {
383         ArrayList JavaDoc al = new ArrayList JavaDoc();
384         JiapiClass jc = this;
385
386         do {
387             al.addAll(jc.jiapiFields);
388         }
389         while ((jc = jc.getSuperclass()) != null);
390
391         return (JiapiField[])al.toArray(fieldArrayTemplate);
392     }
393
394     /**
395      * Get all the fields declared by this JiapiClass. If this JiapiClass
396      * has no fields, an array of length 0 is returned. A new array is created
397      * each time this method is called, so adding and removing items from array
398      * does not reflect such changes back into JiapiClass.
399      *
400      * @return an array of fields in this class
401      */

402     public JiapiField[] getDeclaredFields() {
403         ArrayList JavaDoc al = new ArrayList JavaDoc();
404         al.addAll(jiapiFields);
405
406         return (JiapiField[])al.toArray(fieldArrayTemplate);
407     }
408
409     /**
410      * Get a declared field of a class.
411      *
412      * @param name a name of a field
413      * @return a field with a given name
414      * @exception NoSuchFieldException if matching field is not found
415      */

416     public JiapiField getDeclaredField(String JavaDoc name) throws NoSuchFieldException JavaDoc {
417         Iterator JavaDoc i = jiapiFields.iterator();
418         while(i.hasNext()) {
419             JiapiField f = (JiapiField)i.next();
420             if (f.getName().equals(name)) {
421                 return f;
422             }
423         }
424
425         throw new NoSuchFieldException JavaDoc(name);
426     }
427
428     /**
429      * Get a field from a class or from any of its superclasses.
430      *
431      * @param name a name of a field
432      * @return a field with a given name
433      * @exception NoSuchFieldException if matching field is not found
434      * @exception ClassNotFoundException is thrown if superclass could
435      * not be loaded
436      */

437     public JiapiField getField(String JavaDoc name) throws NoSuchFieldException JavaDoc, ClassNotFoundException JavaDoc {
438         JiapiClass jc = this;
439         JiapiField field = null;
440
441         do {
442             try {
443                 field = jc.getDeclaredField(name);
444                 return field;
445             } catch (NoSuchFieldException JavaDoc nsfe) {
446                 // Don't mind.
447
}
448         }
449         while ((jc = jc.getSuperclass()) != null);
450
451         throw new NoSuchFieldException JavaDoc(name);
452     }
453
454     /**
455      * Gets the super class of this JiapiClass. If this JiapiClass
456      * represents java.lang.Object, a null is returned.
457      *
458      * @return super class of the class represented by this JiapiClass
459      * @exception ClassNotFoundException is thrown, if superclass could not
460      * be loaded
461      */

462     public JiapiClass getSuperclass() throws ClassNotFoundException JavaDoc {
463         String JavaDoc scName = clazz.getSuperclassName();
464         JiapiClass superClass = null;
465         if (scName != null) {
466             try {
467                 superClass = loader.loadClass(scName);
468             }
469             catch(IOException JavaDoc ioe) {
470                 log.error("", ioe);
471             }
472         }
473
474         return superClass;
475     }
476
477     /**
478      * Get modifiers of this JiapiClass.
479      *
480      * @return access modifiers of a class
481      * @see java.lang.reflect.Modifier
482      */

483     public int getModifiers() {
484         return clazz.getAccessFlags();
485     }
486
487
488     /**
489      * Adds a named Field to this JiapiClass. Field will be <code>
490      * public</code> and of type <code>java.lang.Object</code>
491      *
492      * @param name Name of the field to be added
493      * @return JiapiField which was added
494      * @exception FieldExistsException if a field with a same name already
495      * exists
496      */

497     public JiapiField addField(String JavaDoc name) throws FieldExistsException {
498         return addField((short)Modifier.PUBLIC, "java.lang.Object", name);
499     }
500
501     /**
502      * Adds a new Field to this JiapiClass.
503      *
504      * @param modifiers Modifiers of the field
505      * @param type Type of the field to be added. Type is given in
506      * simple form, like 'java.lang.Object' or 'int'
507      * @param name Name of the field to be added
508      * @return JiapiField which was added
509      * @exception FieldExistsException if a field with a same name already
510      * exists
511      */

512     public JiapiField addField(int modifiers, String JavaDoc type, String JavaDoc name) throws FieldExistsException {
513         JiapiField jf = builder.addField((short)modifiers, type, name);
514         jf.setDeclaringClass(this);
515         jiapiFields.add(jf);
516
517         return jf;
518     }
519     
520
521
522     /**
523      * Gets all the interfaces, that this class directly implements.
524      *
525      * @return names of the implemented interfaces
526      */

527     public String JavaDoc[] getInterfaceNames() {
528         ConstantPool cp = clazz.getConstantPool();
529         List JavaDoc l = clazz.getInterfaces();
530
531         String JavaDoc[] iNames = new String JavaDoc[l.size()];
532         for (int i = 0; i < iNames.length; i++) {
533             Interface iFace = (Interface)l.get(i);
534
535             iNames[i] = iFace.getName();
536         }
537
538         return iNames;
539     }
540
541     /**
542      * Gets all the interfaces, that this class directly implements.
543      *
544      * @return names of the implemented interfaces
545      */

546     public JiapiClass[] getInterfaceTypes() throws ClassNotFoundException JavaDoc {
547         String JavaDoc[] iNames = getInterfaceNames();
548         JiapiClass[] interfaces = new JiapiClass[iNames.length];
549
550         for (int i = 0; i < interfaces.length; i++) {
551             try {
552                 interfaces[i] = getLoader().loadClass(iNames[i]);
553             }
554             catch(java.io.IOException JavaDoc ioe) {
555                 throw new ClassNotFoundException JavaDoc(iNames[i]);
556             }
557         }
558
559         return interfaces;
560     }
561
562     /**
563      * Adds an interface for a class.
564      * If current class is an interface, it extends the added interface.
565      * Otherwise it implements it.
566      *
567      * @param interfaceType the type of an interface
568      */

569     public void addInterface(String JavaDoc interfaceType) {
570         clazz.addInterface(interfaceType);
571     }
572
573
574     /**
575      * Adds an interface for a class.
576      * If current class is an interface, it extends the added interface.
577      * Otherwise it implements it.
578      *
579      * @param interfaceType the type of an interface
580      * @exception IllegalArgumentException is thrown, if interfaceType is
581      * not an interface.
582      */

583     public void addInterface(JiapiClass interfaceType) throws IllegalArgumentException JavaDoc {
584         if (!interfaceType.isInterface()) {
585             throw new IllegalArgumentException JavaDoc("Not an interface: " +
586                                                interfaceType.getName());
587         }
588
589         addInterface(interfaceType.getName());
590     }
591     
592     /**
593      * Adds a new method to this class. The signature is derived
594      * from given methods signature.
595      *
596      * @param m JiapiMethod to be used as method signature
597      * @return JiapiMethod which was added
598      * @exception MethodExistsException if a method with a same name and
599      * parameter signature already exists
600      */

601     public JiapiMethod addMethod(JiapiMethod m) throws MethodExistsException {
602         return addMethod((int)m.getModifiers(), m.getName(), m.getSignature());
603     }
604
605     /**
606      * Adds a new method to this class. Method, that is added, do not
607      * contain any bytecode. It is the responsibility of the developer
608      * to provide later some meaningful method body.
609      *
610      * @param modifiers access modifiers of a class
611      * @param methodName name of a method
612      * @param signature signature of a method
613      * @return JiapiMethod which was added
614      * @exception MethodExistsException if a method with a same name and
615      * parameter signature already exists
616      * @see java.lang.reflect.Modifier
617      */

618     public JiapiMethod addMethod(int modifiers, String JavaDoc methodName,
619                                  Signature signature) throws MethodExistsException {
620         JiapiMethod jm = null;
621         // Check, that the method don't exist
622
Iterator JavaDoc i = jiapiMethods.iterator();
623         while(i.hasNext()) {
624             JiapiMethod method = (JiapiMethod)i.next();
625             if (method.getName().equals(methodName) &&
626                 method.getSignature().getDescriptor().equals(signature.getDescriptor())) {
627
628                 throw new MethodExistsException(method);
629             }
630         }
631         
632
633
634         try {
635             jm = builder.addMethod((short)modifiers, methodName, signature);
636         }
637         catch(MethodExistsException mee) {
638             jm = mee.getMethod();
639             jm.setDeclaringClass(this);
640
641             throw mee;
642         }
643
644         jm.setDeclaringClass(this);
645         jiapiMethods.add(jm);
646
647         return jm;
648     }
649
650
651     /**
652      * Tests, whether this JiapiClass is an interface or not.
653      *
654      * @return true, if this JiapiClass represents an interface.
655      */

656     public boolean isInterface() {
657         return Modifier.isInterface(getModifiers());
658     }
659
660     public String JavaDoc toString() {
661         StringBuffer JavaDoc sb = new StringBuffer JavaDoc();
662
663         // clear ACC_SUPER(0x0020 -> 0xffdf), otherwise 'synchronized' would
664
// be returned by java.lang.reflect.Modifier
665
sb.append(Modifier.toString(getModifiers() & 0xffdf));
666         sb.append(" JiapiClass ");
667         sb.append(getName());
668
669         String JavaDoc[] interfaces = getInterfaceNames();
670         if (interfaces.length > 0) {
671             sb.append(" implements ");
672             for (int i = 0; i < interfaces.length; i++) {
673                 sb.append(interfaces[i]);
674                 if (i < interfaces.length - 1) {
675                     sb.append(", ");
676                 }
677             }
678         }
679
680         sb.append("\nFields:");
681         JiapiField[] fields = getDeclaredFields();
682         for (int i = 0; i < fields.length; i++) {
683             sb.append("\n ");
684             sb.append(fields[i].toString());
685         }
686
687         sb.append("\nMethods:");
688         JiapiMethod[] methods = getDeclaredMethods();
689         for (int i = 0; i < methods.length; i++) {
690             sb.append("\n ");
691             sb.append(methods[i].toString());
692
693 // sb.append('\n');
694
// sb.append(methods[i].getInstructionList());
695
}
696
697         return sb.toString();
698     }
699
700
701     // Package access -----------------
702
void setLoader(Loader l) {
703         this.loader = l;
704     }
705
706
707     // Made public for alt.jiapi.tool.Javap
708
// public ClassFile getClassFile() {
709
// return clazz;
710
// }
711

712     /**
713      * Get the ConstantPool related to this JiapiClass.
714      *
715      * @return ConstantPool of this JiapiClass
716      */

717     public ConstantPool getConstantPool() {
718         return clazz.getConstantPool();
719     }
720 }
721
Popular Tags