KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > CtClassType


1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
4  *
5  * The contents of this file are subject to the Mozilla Public License Version
6  * 1.1 (the "License"); you may not use this file except in compliance with
7  * the License. Alternatively, the contents of this file may be used under
8  * the terms of the GNU Lesser General Public License Version 2.1 or later.
9  *
10  * Software distributed under the License is distributed on an "AS IS" basis,
11  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12  * for the specific language governing rights and limitations under the
13  * License.
14  */

15
16 package javassist;
17
18 import javassist.bytecode.AccessFlag;
19 import javassist.bytecode.AttributeInfo;
20 import javassist.bytecode.BadBytecode;
21 import javassist.bytecode.Bytecode;
22 import javassist.bytecode.ClassFile;
23 import javassist.bytecode.CodeAttribute;
24 import javassist.bytecode.CodeIterator;
25 import javassist.bytecode.ConstPool;
26 import javassist.bytecode.Descriptor;
27 import javassist.bytecode.EnclosingMethodAttribute;
28 import javassist.bytecode.FieldInfo;
29 import javassist.bytecode.InnerClassesAttribute;
30 import javassist.bytecode.MethodInfo;
31 import javassist.compiler.AccessorMaker;
32 import javassist.compiler.CompileError;
33 import javassist.compiler.Javac;
34 import javassist.expr.ExprEditor;
35
36 import java.io.BufferedInputStream JavaDoc;
37 import java.io.DataInputStream JavaDoc;
38 import java.io.DataOutputStream JavaDoc;
39 import java.io.IOException JavaDoc;
40 import java.io.InputStream JavaDoc;
41 import java.net.URL JavaDoc;
42 import java.util.ArrayList JavaDoc;
43 import java.util.Enumeration JavaDoc;
44 import java.util.HashMap JavaDoc;
45 import java.util.Hashtable JavaDoc;
46 import java.util.List JavaDoc;
47
48 /**
49  * Class types.
50  */

51 class CtClassType extends CtClass {
52     ClassPool classPool;
53     boolean wasChanged;
54     private boolean wasFrozen;
55     boolean wasPruned;
56     boolean memberRemoved;
57     ClassFile classfile;
58
59     private CtMember fieldsCache;
60     private CtMember methodsCache;
61     private CtMember constructorsCache;
62     private CtConstructor classInitializerCache;
63
64     private AccessorMaker accessors;
65
66     private FieldInitLink fieldInitializers;
67     private Hashtable JavaDoc hiddenMethods; // must be synchronous
68
private int uniqueNumberSeed;
69
70     private boolean doPruning = false;
71     int getCounter;
72     private static int readCounter = 0;
73     private static final int READ_THRESHOLD = 100; // see getClassFile2()
74

75     CtClassType(String JavaDoc name, ClassPool cp) {
76         super(name);
77         classPool = cp;
78         wasChanged = wasFrozen = wasPruned = memberRemoved = false;
79         classfile = null;
80         accessors = null;
81         fieldInitializers = null;
82         hiddenMethods = null;
83         uniqueNumberSeed = 0;
84         eraseCache();
85         getCounter = 0;
86     }
87
88     CtClassType(InputStream JavaDoc ins, ClassPool cp) throws IOException JavaDoc {
89         this((String JavaDoc)null, cp);
90         classfile = new ClassFile(new DataInputStream JavaDoc(ins));
91         qualifiedName = classfile.getName();
92     }
93
94     protected void extendToString(StringBuffer JavaDoc buffer) {
95         if (wasChanged)
96             buffer.append("changed ");
97
98         if (wasFrozen)
99             buffer.append("frozen ");
100
101         if (wasPruned)
102             buffer.append("pruned ");
103
104         buffer.append(Modifier.toString(getModifiers()));
105         buffer.append(" class ");
106         buffer.append(getName());
107
108         try {
109             CtClass ext = getSuperclass();
110             if (ext != null) {
111                 String JavaDoc name = ext.getName();
112                 if (!name.equals("java.lang.Object"))
113                     buffer.append(" extends " + ext.getName());
114             }
115         }
116         catch (NotFoundException e) {
117             buffer.append(" extends ??");
118         }
119
120         try {
121             CtClass[] intf = getInterfaces();
122             if (intf.length > 0)
123                 buffer.append(" implements ");
124
125             for (int i = 0; i < intf.length; ++i) {
126                 buffer.append(intf[i].getName());
127                 buffer.append(", ");
128             }
129         }
130         catch (NotFoundException e) {
131             buffer.append(" extends ??");
132         }
133
134         CtMember field = getFieldsCache();
135         buffer.append(" fields=");
136         while (field != null) {
137             buffer.append(field);
138             buffer.append(", ");
139             field = field.next;
140         }
141
142         CtMember c = getConstructorsCache();
143         buffer.append(" constructors=");
144         while (c != null) {
145             buffer.append(c);
146             buffer.append(", ");
147             c = c.next;
148         }
149
150         CtMember m = getMethodsCache();
151         buffer.append(" methods=");
152         while (m != null) {
153             buffer.append(m);
154             buffer.append(", ");
155             m = m.next;
156         }
157     }
158
159     protected void eraseCache() {
160         fieldsCache = null;
161         constructorsCache = null;
162         classInitializerCache = null;
163         methodsCache = null;
164     }
165
166     public AccessorMaker getAccessorMaker() {
167         if (accessors == null)
168             accessors = new AccessorMaker(this);
169
170         return accessors;
171     }
172
173     public ClassFile getClassFile2() {
174         if (classfile != null)
175             return classfile;
176
177         if (readCounter++ > READ_THRESHOLD) {
178             doCompaction();
179             readCounter = 0;
180         }
181
182         InputStream JavaDoc fin = null;
183         try {
184             fin = classPool.openClassfile(getName());
185             if (fin == null)
186                 throw new NotFoundException(getName());
187
188             fin = new BufferedInputStream JavaDoc(fin);
189             classfile = new ClassFile(new DataInputStream JavaDoc(fin));
190             if (!classfile.getName().equals(qualifiedName))
191                 throw new RuntimeException JavaDoc(classfile.getName() + " in "
192                                 + qualifiedName.replace('.', '/') + ".java");
193
194             return classfile;
195         }
196         catch (NotFoundException e) {
197             throw new RuntimeException JavaDoc(e.toString());
198         }
199         catch (IOException JavaDoc e) {
200             throw new RuntimeException JavaDoc(e.toString());
201         }
202         finally {
203             if (fin != null)
204                 try {
205                     fin.close();
206                 }
207                 catch (IOException JavaDoc e) {}
208         }
209     }
210
211     /* Inherited from CtClass. Called by get() in ClassPool.
212      *
213      * @see javassist.CtClass#incGetCounter()
214      */

215     void incGetCounter() { ++getCounter; }
216
217     private void doCompaction() {
218         Enumeration JavaDoc e = classPool.classes.elements();
219         while (e.hasMoreElements()) {
220             Object JavaDoc obj = e.nextElement();
221             if (obj instanceof CtClassType) {
222                 CtClassType cct = (CtClassType)obj;
223                 if (cct.getCounter < 2 && !cct.isModified()) {
224                     cct.eraseCache();
225                     cct.classfile = null;
226                 }
227
228                 cct.getCounter = 0;
229             }
230         }
231     }
232
233     public ClassPool getClassPool() { return classPool; }
234
235     void setClassPool(ClassPool cp) { classPool = cp; }
236
237     public URL JavaDoc getURL() throws NotFoundException {
238         URL JavaDoc url = classPool.find(getName());
239         if (url == null)
240             throw new NotFoundException(getName());
241         else
242             return url;
243     }
244
245     public boolean isModified() { return wasChanged; }
246
247     public boolean isFrozen() { return wasFrozen; }
248
249     void freeze() { wasFrozen = true; }
250
251     void checkModify() throws RuntimeException JavaDoc {
252         super.checkModify();
253         wasChanged = true;
254     }
255
256     public void defrost() {
257         checkPruned("defrost");
258         wasFrozen = false;
259     }
260
261     public boolean subtypeOf(CtClass clazz) throws NotFoundException {
262         int i;
263         String JavaDoc cname = clazz.getName();
264         if (this == clazz || getName().equals(cname))
265             return true;
266
267         ClassFile file = getClassFile2();
268         String JavaDoc supername = file.getSuperclass();
269         if (supername != null && supername.equals(cname))
270             return true;
271
272         String JavaDoc[] ifs = file.getInterfaces();
273         int num = ifs.length;
274         for (i = 0; i < num; ++i)
275             if (ifs[i].equals(cname))
276                 return true;
277
278         if (supername != null && classPool.get(supername).subtypeOf(clazz))
279             return true;
280
281         for (i = 0; i < num; ++i)
282             if (classPool.get(ifs[i]).subtypeOf(clazz))
283                 return true;
284
285         return false;
286     }
287
288     public void setName(String JavaDoc name) throws RuntimeException JavaDoc {
289         String JavaDoc oldname = getName();
290         if (name.equals(oldname))
291             return;
292
293         // check this in advance although classNameChanged() below does.
294
classPool.checkNotFrozen(name);
295         ClassFile cf = getClassFile2();
296         super.setName(name);
297         cf.setName(name);
298         eraseCache();
299         classPool.classNameChanged(oldname, this);
300     }
301
302     public void replaceClassName(ClassMap classnames)
303         throws RuntimeException JavaDoc
304     {
305         String JavaDoc oldClassName = getName();
306         String JavaDoc newClassName
307             = (String JavaDoc)classnames.get(Descriptor.toJvmName(oldClassName));
308         if (newClassName != null) {
309             newClassName = Descriptor.toJavaName(newClassName);
310             // check this in advance although classNameChanged() below does.
311
classPool.checkNotFrozen(newClassName);
312         }
313
314         super.replaceClassName(classnames);
315         ClassFile cf = getClassFile2();
316         cf.renameClass(classnames);
317         eraseCache();
318
319         if (newClassName != null) {
320             super.setName(newClassName);
321             classPool.classNameChanged(oldClassName, this);
322         }
323     }
324
325     public void replaceClassName(String JavaDoc oldname, String JavaDoc newname)
326         throws RuntimeException JavaDoc
327     {
328         String JavaDoc thisname = getName();
329         if (thisname.equals(oldname))
330             setName(newname);
331         else {
332             super.replaceClassName(oldname, newname);
333             getClassFile2().renameClass(oldname, newname);
334             eraseCache();
335         }
336     }
337
338     public boolean isInterface() {
339         return Modifier.isInterface(getModifiers());
340     }
341
342     public int getModifiers() {
343         int acc = getClassFile2().getAccessFlags();
344         acc = AccessFlag.clear(acc, AccessFlag.SUPER);
345         return AccessFlag.toModifier(acc);
346     }
347
348     public void setModifiers(int mod) {
349         checkModify();
350         int acc = AccessFlag.of(mod) | AccessFlag.SUPER;
351         getClassFile2().setAccessFlags(acc);
352     }
353
354     public boolean subclassOf(CtClass superclass) {
355         if (superclass == null)
356             return false;
357
358         String JavaDoc superName = superclass.getName();
359         CtClass curr = this;
360         try {
361             while (curr != null) {
362                 if (curr.getName().equals(superName))
363                     return true;
364
365                 curr = curr.getSuperclass();
366             }
367         }
368         catch (Exception JavaDoc ignored) {}
369         return false;
370     }
371
372     public CtClass getSuperclass() throws NotFoundException {
373         String JavaDoc supername = getClassFile2().getSuperclass();
374         if (supername == null)
375             return null;
376         else
377             return classPool.get(supername);
378     }
379
380     public void setSuperclass(CtClass clazz) throws CannotCompileException {
381         checkModify();
382         if (isInterface())
383             addInterface(clazz);
384         else
385             getClassFile2().setSuperclass(clazz.getName());
386     }
387
388     public CtClass[] getInterfaces() throws NotFoundException {
389         String JavaDoc[] ifs = getClassFile2().getInterfaces();
390         int num = ifs.length;
391         CtClass[] ifc = new CtClass[num];
392         for (int i = 0; i < num; ++i)
393             ifc[i] = classPool.get(ifs[i]);
394
395         return ifc;
396     }
397
398     public void setInterfaces(CtClass[] list) {
399         checkModify();
400         String JavaDoc[] ifs;
401         if (list == null)
402             ifs = new String JavaDoc[0];
403         else {
404             int num = list.length;
405             ifs = new String JavaDoc[num];
406             for (int i = 0; i < num; ++i)
407                 ifs[i] = list[i].getName();
408         }
409
410         getClassFile2().setInterfaces(ifs);
411     }
412
413     public void addInterface(CtClass anInterface) {
414         checkModify();
415         if (anInterface != null)
416             getClassFile2().addInterface(anInterface.getName());
417     }
418
419     public CtClass getDeclaringClass() throws NotFoundException {
420         ClassFile cf = getClassFile2();
421         InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
422                                                 InnerClassesAttribute.tag);
423         if (ica == null)
424             return null;
425
426         String JavaDoc name = getName();
427         int n = ica.tableLength();
428         for (int i = 0; i < n; ++i)
429             if (name.equals(ica.innerClass(i))) {
430                 String JavaDoc outName = ica.outerClass(i);
431                 if (outName != null)
432                     return classPool.get(outName);
433             }
434
435         return null;
436     }
437
438     public CtClass getEnclosingClass() throws NotFoundException {
439         CtClass enc = getDeclaringClass();
440         if (enc == null) {
441             ClassFile cf = getClassFile2();
442             EnclosingMethodAttribute ema
443                 = (EnclosingMethodAttribute)cf.getAttribute(
444                                                     EnclosingMethodAttribute.tag);
445             if (ema != null)
446                 enc = classPool.get(ema.className());
447         }
448
449         return enc;
450     }
451
452     public CtClass makeNestedClass(String JavaDoc name, boolean isStatic) {
453         if (!isStatic)
454             throw new RuntimeException JavaDoc(
455                         "sorry, only nested static class is supported");
456
457         checkModify();
458         CtClass c = classPool.makeNestedClass(getName() + "$" + name);
459         ClassFile cf = getClassFile2();
460         InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
461                                                 InnerClassesAttribute.tag);
462         if (ica == null) {
463             ica = new InnerClassesAttribute(cf.getConstPool());
464             cf.addAttribute(ica);
465         }
466
467         ica.append(c.getName(), this.getName(), name, AccessFlag.STATIC);
468         ClassFile cf2 = c.getClassFile2();
469         cf2.addAttribute(ica.copy(cf2.getConstPool(), null));
470         return c;
471     }
472
473     public CtField[] getFields() {
474         ArrayList JavaDoc alist = new ArrayList JavaDoc();
475         getFields(alist, this);
476         return (CtField[])alist.toArray(new CtField[alist.size()]);
477     }
478
479     private static void getFields(ArrayList JavaDoc alist, CtClass cc) {
480         int i, num;
481         if (cc == null)
482             return;
483
484         try {
485             getFields(alist, cc.getSuperclass());
486         }
487         catch (NotFoundException e) {}
488
489         try {
490             CtClass[] ifs = cc.getInterfaces();
491             num = ifs.length;
492             for (i = 0; i < num; ++i)
493                 getFields(alist, ifs[i]);
494         }
495         catch (NotFoundException e) {}
496
497         CtMember cf = ((CtClassType)cc).getFieldsCache();
498         while (cf != null) {
499             if (Modifier.isPublic(cf.getModifiers()))
500                 alist.add(cf);
501
502             cf = cf.next;
503         }
504     }
505
506     public CtField getField(String JavaDoc name) throws NotFoundException {
507         CtField f = getField2(name);
508         if (f == null)
509             throw new NotFoundException("field: " + name + " in " + getName());
510         else
511             return f;
512     }
513
514     CtField getField2(String JavaDoc name) {
515         CtField df = getDeclaredField2(name);
516         if (df != null)
517             return df;
518
519         try {
520             CtClass[] ifs = getInterfaces();
521             int num = ifs.length;
522             for (int i = 0; i < num; ++i) {
523                 CtField f = ifs[i].getField2(name);
524                 if (f != null)
525                     return f;
526             }
527
528             CtClass s = getSuperclass();
529             if (s != null)
530                 return s.getField2(name);
531         }
532         catch (NotFoundException e) {}
533         return null;
534     }
535
536     public CtField[] getDeclaredFields() {
537         CtMember cf = getFieldsCache();
538         int num = CtField.count(cf);
539         CtField[] cfs = new CtField[num];
540         int i = 0;
541         while (cf != null) {
542             cfs[i++] = (CtField)cf;
543             cf = cf.next;
544         }
545
546         return cfs;
547     }
548
549     protected CtMember getFieldsCache() {
550         if (fieldsCache == null) {
551             List JavaDoc list = getClassFile2().getFields();
552             int n = list.size();
553             for (int i = 0; i < n; ++i) {
554                 FieldInfo finfo = (FieldInfo)list.get(i);
555                 fieldsCache = CtMember.append(fieldsCache,
556                                              new CtField(finfo, this));
557             }
558         }
559
560         return fieldsCache;
561     }
562
563     public CtField getDeclaredField(String JavaDoc name) throws NotFoundException {
564         CtField f = getDeclaredField2(name);
565         if (f == null)
566             throw new NotFoundException("field: " + name + " in " + getName());
567         else
568             return f;
569     }
570
571     private CtField getDeclaredField2(String JavaDoc name) {
572         CtMember cf = getFieldsCache();
573         while (cf != null) {
574             if (cf.getName().equals(name))
575                 return (CtField)cf;
576
577             cf = cf.next;
578         }
579
580         return null;
581     }
582
583     public CtBehavior[] getDeclaredBehaviors() {
584         CtMember cc = getConstructorsCache();
585         CtMember cm = getMethodsCache();
586         int num = CtMember.count(cm) + CtMember.count(cc);
587         CtBehavior[] cb = new CtBehavior[num];
588         int i = 0;
589         while (cc != null) {
590             cb[i++] = (CtBehavior)cc;
591             cc = cc.next;
592         }
593
594         while (cm != null) {
595             cb[i++] = (CtBehavior)cm;
596             cm = cm.next;
597         }
598
599         return cb;
600     }
601
602     public CtConstructor[] getConstructors() {
603         CtConstructor[] cons = getDeclaredConstructors();
604         if (cons.length == 0)
605             return cons;
606
607         int n = 0;
608         int i = cons.length;
609         while (--i >= 0)
610             if (Modifier.isPublic(cons[i].getModifiers()))
611                 ++n;
612
613         CtConstructor[] result = new CtConstructor[n];
614         n = 0;
615         i = cons.length;
616         while (--i >= 0) {
617             CtConstructor c = cons[i];
618             if (Modifier.isPublic(c.getModifiers()))
619                 result[n++] = c;
620         }
621
622         return result;
623     }
624
625     public CtConstructor getConstructor(String JavaDoc desc)
626         throws NotFoundException
627     {
628         CtConstructor cc = (CtConstructor)getConstructorsCache();
629         while (cc != null) {
630             if (cc.getMethodInfo2().getDescriptor().equals(desc))
631                 return cc;
632
633             cc = (CtConstructor)cc.next;
634         }
635
636         return super.getConstructor(desc);
637     }
638
639     public CtConstructor[] getDeclaredConstructors() {
640         CtMember cc = getConstructorsCache();
641         int num = CtMember.count(cc);
642         CtConstructor[] ccs = new CtConstructor[num];
643         int i = 0;
644         while (cc != null) {
645             ccs[i++] = (CtConstructor)cc;
646             cc = cc.next;
647         }
648
649         return ccs;
650     }
651
652     protected CtMember getConstructorsCache() {
653         if (constructorsCache == null) {
654             List JavaDoc list = getClassFile2().getMethods();
655             int n = list.size();
656             for (int i = 0; i < n; ++i) {
657                 MethodInfo minfo = (MethodInfo)list.get(i);
658                 if (minfo.isConstructor())
659                     constructorsCache
660                         = CtMember.append(constructorsCache,
661                                           new CtConstructor(minfo, this));
662             }
663         }
664
665         return constructorsCache;
666     }
667
668     public CtConstructor getClassInitializer() {
669         if (classInitializerCache == null) {
670             MethodInfo minfo = getClassFile2().getStaticInitializer();
671             if (minfo != null)
672                 classInitializerCache = new CtConstructor(minfo, this);
673         }
674
675         return classInitializerCache;
676     }
677
678     public CtMethod[] getMethods() {
679         HashMap JavaDoc h = new HashMap JavaDoc();
680         getMethods0(h, this);
681         return (CtMethod[])h.values().toArray(new CtMethod[0]);
682     }
683
684     private static void getMethods0(HashMap JavaDoc h, CtClass cc) {
685         try {
686             CtClass[] ifs = cc.getInterfaces();
687             int size = ifs.length;
688             for (int i = 0; i < size; ++i)
689                 getMethods0(h, ifs[i]);
690         }
691         catch (NotFoundException e) {}
692
693         try {
694             CtClass s = cc.getSuperclass();
695             if (s != null)
696                 getMethods0(h, s);
697         }
698         catch (NotFoundException e) {}
699
700         if (cc instanceof CtClassType) {
701             CtMember cm = ((CtClassType)cc).getMethodsCache();
702             while (cm != null) {
703                 if (Modifier.isPublic(cm.getModifiers()))
704                     h.put(((CtMethod)cm).getStringRep(), cm);
705
706                 cm = cm.next;
707             }
708         }
709     }
710
711     public CtMethod getMethod(String JavaDoc name, String JavaDoc desc)
712         throws NotFoundException
713     {
714         CtMethod m = getMethod0(this, name, desc);
715         if (m != null)
716             return m;
717         else
718             throw new NotFoundException(name + "(..) is not found in "
719                                         + getName());
720     }
721
722     private static CtMethod getMethod0(CtClass cc,
723                                        String JavaDoc name, String JavaDoc desc) {
724         if (cc instanceof CtClassType) {
725             CtMethod cm = (CtMethod)((CtClassType)cc).getMethodsCache();
726             while (cm != null) {
727                 if (cm.getName().equals(name)
728                     && cm.getMethodInfo2().getDescriptor().equals(desc))
729                     return cm;
730
731                 cm = (CtMethod)cm.next;
732             }
733         }
734
735         try {
736             CtClass s = cc.getSuperclass();
737             if (s != null) {
738                 CtMethod m = getMethod0(s, name, desc);
739                 if (m != null)
740                     return m;
741             }
742         }
743         catch (NotFoundException e) {}
744
745         try {
746             CtClass[] ifs = cc.getInterfaces();
747             int size = ifs.length;
748             for (int i = 0; i < size; ++i) {
749                 CtMethod m = getMethod0(ifs[i], name, desc);
750                 if (m != null)
751                     return m;
752             }
753         }
754         catch (NotFoundException e) {}
755         return null;
756     }
757
758     public CtMethod[] getDeclaredMethods() {
759         CtMember cm = getMethodsCache();
760         int num = CtMember.count(cm);
761         CtMethod[] cms = new CtMethod[num];
762         int i = 0;
763         while (cm != null) {
764             cms[i++] = (CtMethod)cm;
765             cm = cm.next;
766         }
767
768         return cms;
769     }
770
771     public CtMethod getDeclaredMethod(String JavaDoc name) throws NotFoundException {
772         CtMember m = getMethodsCache();
773         while (m != null) {
774             if (m.getName().equals(name))
775                 return (CtMethod)m;
776
777             m = m.next;
778         }
779
780         throw new NotFoundException(name + "(..) is not found in "
781                                     + getName());
782     }
783
784     public CtMethod getDeclaredMethod(String JavaDoc name, CtClass[] params)
785         throws NotFoundException
786     {
787         String JavaDoc desc = Descriptor.ofParameters(params);
788         CtMethod m = (CtMethod)getMethodsCache();
789         while (m != null) {
790             if (m.getName().equals(name)
791                 && m.getMethodInfo2().getDescriptor().startsWith(desc))
792                 return m;
793
794             m = (CtMethod)m.next;
795         }
796
797         throw new NotFoundException(name + "(..) is not found in "
798                                     + getName());
799     }
800
801     protected CtMember getMethodsCache() {
802         if (methodsCache == null) {
803             List JavaDoc list = getClassFile2().getMethods();
804             int n = list.size();
805             for (int i = 0; i < n; ++i) {
806                 MethodInfo minfo = (MethodInfo)list.get(i);
807                 if (minfo.isMethod())
808                     methodsCache = CtMember.append(methodsCache,
809                                                    new CtMethod(minfo, this));
810             }
811         }
812
813         return methodsCache;
814     }
815
816     public void addField(CtField f, String JavaDoc init)
817         throws CannotCompileException
818     {
819         addField(f, CtField.Initializer.byExpr(init));
820     }
821
822     public void addField(CtField f, CtField.Initializer init)
823         throws CannotCompileException
824     {
825         checkModify();
826         if (f.getDeclaringClass() != this)
827             throw new CannotCompileException("cannot add");
828
829         if (init == null)
830             init = f.getInit();
831
832         getFieldsCache();
833         fieldsCache = CtField.append(fieldsCache, f);
834         getClassFile2().addField(f.getFieldInfo2());
835
836         if (init != null) {
837             FieldInitLink fil = new FieldInitLink(f, init);
838             FieldInitLink link = fieldInitializers;
839             if (link == null)
840                 fieldInitializers = fil;
841             else {
842                 while (link.next != null)
843                     link = link.next;
844
845                 link.next = fil;
846             }
847         }
848     }
849
850     public void removeField(CtField f) throws NotFoundException {
851         checkModify();
852         FieldInfo fi = f.getFieldInfo2();
853         ClassFile cf = getClassFile2();
854         if (cf.getFields().remove(fi)) {
855             fieldsCache = CtMember.remove(fieldsCache, f);
856             memberRemoved = true;
857         }
858         else
859             throw new NotFoundException(f.toString());
860     }
861
862     public CtConstructor makeClassInitializer()
863         throws CannotCompileException
864     {
865         CtConstructor clinit = getClassInitializer();
866         if (clinit != null)
867             return clinit;
868
869         checkModify();
870         ClassFile cf = getClassFile2();
871         Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
872         modifyClassConstructor(cf, code, 0, 0);
873         return getClassInitializer();
874     }
875
876     public void addConstructor(CtConstructor c)
877         throws CannotCompileException
878     {
879         checkModify();
880         if (c.getDeclaringClass() != this)
881             throw new CannotCompileException("cannot add");
882
883         getConstructorsCache();
884         constructorsCache = (CtConstructor)CtMember.append(constructorsCache, c);
885         getClassFile2().addMethod(c.getMethodInfo2());
886     }
887
888     public void removeConstructor(CtConstructor m) throws NotFoundException {
889         checkModify();
890         MethodInfo mi = m.getMethodInfo2();
891         ClassFile cf = getClassFile2();
892         if (cf.getMethods().remove(mi)) {
893             constructorsCache = CtMember.remove(constructorsCache, m);
894             memberRemoved = true;
895         }
896         else
897             throw new NotFoundException(m.toString());
898     }
899
900     public void addMethod(CtMethod m) throws CannotCompileException {
901         checkModify();
902         if (m.getDeclaringClass() != this)
903             throw new CannotCompileException("cannot add");
904
905         getMethodsCache();
906         methodsCache = CtMember.append(methodsCache, m);
907         getClassFile2().addMethod(m.getMethodInfo2());
908         if ((m.getModifiers() & Modifier.ABSTRACT) != 0)
909             setModifiers(getModifiers() | Modifier.ABSTRACT);
910     }
911
912     public void removeMethod(CtMethod m) throws NotFoundException {
913         checkModify();
914         MethodInfo mi = m.getMethodInfo2();
915         ClassFile cf = getClassFile2();
916         if (cf.getMethods().remove(mi)) {
917             methodsCache = CtMember.remove(methodsCache, m);
918             memberRemoved = true;
919         }
920         else
921             throw new NotFoundException(m.toString());
922     }
923
924     public byte[] getAttribute(String JavaDoc name) {
925         AttributeInfo ai = getClassFile2().getAttribute(name);
926         if (ai == null)
927             return null;
928         else
929             return ai.get();
930     }
931
932     public void setAttribute(String JavaDoc name, byte[] data) {
933         checkModify();
934         ClassFile cf = getClassFile2();
935         cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data));
936     }
937
938     public void instrument(CodeConverter converter)
939         throws CannotCompileException
940     {
941         checkModify();
942         ClassFile cf = getClassFile2();
943         ConstPool cp = cf.getConstPool();
944         List JavaDoc list = cf.getMethods();
945         int n = list.size();
946         for (int i = 0; i < n; ++i) {
947             MethodInfo minfo = (MethodInfo)list.get(i);
948             converter.doit(this, minfo, cp);
949         }
950     }
951
952     public void instrument(ExprEditor editor)
953         throws CannotCompileException
954     {
955         checkModify();
956         ClassFile cf = getClassFile2();
957         List JavaDoc list = cf.getMethods();
958         int n = list.size();
959         for (int i = 0; i < n; ++i) {
960             MethodInfo minfo = (MethodInfo)list.get(i);
961             editor.doit(this, minfo);
962         }
963     }
964
965     public void toBytecode(DataOutputStream JavaDoc out)
966         throws CannotCompileException, IOException JavaDoc
967     {
968         try {
969             if (isModified()) {
970                 checkPruned("toBytecode");
971                 ClassFile cf = getClassFile2();
972                 if (memberRemoved) {
973                     cf.compact();
974                     memberRemoved = false;
975                 }
976
977                 modifyClassConstructor(cf);
978                 modifyConstructors(cf);
979                 cf.write(out);
980                 out.flush();
981                 fieldInitializers = null;
982                 if (doPruning) {
983                     // to save memory
984
cf.prune();
985                     wasPruned = true;
986                 }
987             }
988             else {
989                 classPool.writeClassfile(getName(), out);
990                 // to save memory
991
eraseCache();
992                 classfile = null;
993             }
994
995             wasFrozen = true;
996         }
997         catch (NotFoundException e) {
998             throw new CannotCompileException(e);
999         }
1000        catch (IOException JavaDoc e) {
1001            throw new CannotCompileException(e);
1002        }
1003    }
1004
1005    private void checkPruned(String JavaDoc method) {
1006        if (wasPruned)
1007            throw new RuntimeException JavaDoc(method + "(): " + getName()
1008                                       + " was pruned.");
1009    }
1010
1011    public void stopPruning(boolean stop) {
1012        doPruning = !stop;
1013    }
1014
1015    private void modifyClassConstructor(ClassFile cf)
1016        throws CannotCompileException, NotFoundException
1017    {
1018        if (fieldInitializers == null)
1019            return;
1020
1021        Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
1022        Javac jv = new Javac(code, this);
1023        int stacksize = 0;
1024        boolean doInit = false;
1025        for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
1026            CtField f = fi.field;
1027            if (Modifier.isStatic(f.getModifiers())) {
1028                doInit = true;
1029                int s = fi.init.compileIfStatic(f.getType(), f.getName(),
1030                                                code, jv);
1031                if (stacksize < s)
1032                    stacksize = s;
1033            }
1034        }
1035
1036        if (doInit) // need an initializer for static fileds.
1037
modifyClassConstructor(cf, code, stacksize, 0);
1038    }
1039
1040    private void modifyClassConstructor(ClassFile cf, Bytecode code,
1041                                        int stacksize, int localsize)
1042        throws CannotCompileException
1043    {
1044        MethodInfo m = cf.getStaticInitializer();
1045        if (m == null) {
1046            code.add(Bytecode.RETURN);
1047            code.setMaxStack(stacksize);
1048            code.setMaxLocals(localsize);
1049            m = new MethodInfo(cf.getConstPool(), "<clinit>", "()V");
1050            m.setAccessFlags(AccessFlag.STATIC);
1051            m.setCodeAttribute(code.toCodeAttribute());
1052            cf.addMethod(m);
1053        }
1054        else {
1055            CodeAttribute codeAttr = m.getCodeAttribute();
1056            if (codeAttr == null)
1057                throw new CannotCompileException("empty <clinit>");
1058
1059            try {
1060                CodeIterator it = codeAttr.iterator();
1061                int pos = it.insertEx(code.get());
1062                it.insert(code.getExceptionTable(), pos);
1063                int maxstack = codeAttr.getMaxStack();
1064                if (maxstack < stacksize)
1065                    codeAttr.setMaxStack(stacksize);
1066
1067                int maxlocals = codeAttr.getMaxLocals();
1068                if (maxlocals < localsize)
1069                    codeAttr.setMaxLocals(localsize);
1070            }
1071            catch (BadBytecode e) {
1072                throw new CannotCompileException(e);
1073            }
1074        }
1075    }
1076
1077    private void modifyConstructors(ClassFile cf)
1078        throws CannotCompileException, NotFoundException
1079    {
1080        if (fieldInitializers == null)
1081            return;
1082
1083        ConstPool cp = cf.getConstPool();
1084        List JavaDoc list = cf.getMethods();
1085        int n = list.size();
1086        for (int i = 0; i < n; ++i) {
1087            MethodInfo minfo = (MethodInfo)list.get(i);
1088            if (minfo.isConstructor()) {
1089                CodeAttribute codeAttr = minfo.getCodeAttribute();
1090                if (codeAttr != null)
1091                    try {
1092                        Bytecode init = new Bytecode(cp, 0,
1093                                                codeAttr.getMaxLocals());
1094                        CtClass[] params
1095                            = Descriptor.getParameterTypes(
1096                                                minfo.getDescriptor(),
1097                                                classPool);
1098                        int stacksize = makeFieldInitializer(init, params);
1099                        insertAuxInitializer(codeAttr, init, stacksize);
1100                    }
1101                    catch (BadBytecode e) {
1102                        throw new CannotCompileException(e);
1103                    }
1104            }
1105        }
1106    }
1107
1108    private static void insertAuxInitializer(CodeAttribute codeAttr,
1109                                             Bytecode initializer,
1110                                             int stacksize)
1111        throws BadBytecode
1112    {
1113        CodeIterator it = codeAttr.iterator();
1114        int index = it.skipSuperConstructor();
1115        if (index < 0) {
1116            index = it.skipThisConstructor();
1117            if (index >= 0)
1118                return; // this() is called.
1119

1120            // Neither this() or super() is called.
1121
}
1122
1123        int pos = it.insertEx(initializer.get());
1124        it.insert(initializer.getExceptionTable(), pos);
1125        int maxstack = codeAttr.getMaxStack();
1126        if (maxstack < stacksize)
1127            codeAttr.setMaxStack(stacksize);
1128    }
1129
1130    private int makeFieldInitializer(Bytecode code, CtClass[] parameters)
1131        throws CannotCompileException, NotFoundException
1132    {
1133        int stacksize = 0;
1134        Javac jv = new Javac(code, this);
1135        try {
1136            jv.recordParams(parameters, false);
1137        }
1138        catch (CompileError e) {
1139            throw new CannotCompileException(e);
1140        }
1141
1142        for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
1143            CtField f = fi.field;
1144            if (!Modifier.isStatic(f.getModifiers())) {
1145                int s = fi.init.compile(f.getType(), f.getName(), code,
1146                                        parameters, jv);
1147                if (stacksize < s)
1148                    stacksize = s;
1149            }
1150        }
1151
1152        return stacksize;
1153    }
1154
1155    // Methods used by CtNewWrappedMethod
1156

1157    Hashtable JavaDoc getHiddenMethods() {
1158        if (hiddenMethods == null)
1159            hiddenMethods = new Hashtable JavaDoc();
1160
1161        return hiddenMethods;
1162    }
1163
1164    int getUniqueNumber() { return uniqueNumberSeed++; }
1165}
1166
1167class FieldInitLink {
1168    FieldInitLink next;
1169    CtField field;
1170    CtField.Initializer init;
1171
1172    FieldInitLink(CtField f, CtField.Initializer i) {
1173        next = null;
1174        field = f;
1175        init = i;
1176    }
1177}
1178
Popular Tags