/Users/lyon/j4p/src/javassist/CtField.java

1    /* 
2     * Javassist, a Java-bytecode translator toolkit. 
3     * Copyright (C) 1999-2003 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.*; 
19   import javassist.compiler.Javac; 
20   import javassist.compiler.CompileError; 
21   import javassist.compiler.ast.ASTree; 
22    
23   /** 
24    * An instance of CtField represents a field. 
25    * 
26    * @see CtClass#getDeclaredFields() 
27    */ 
28   public class CtField extends CtMember { 
29       protected FieldInfo fieldInfo; 
30       CtField next; 
31    
32       /** 
33        * Creates a <code>CtField</code> object. 
34        * The created field must be added to a class 
35        * with <code>CtClass.addField()</code>. 
36        * An initial value of the field is specified 
37        * by a <code>CtField.Initializer</code> object. 
38        * 
39        * <p>If getter and setter methods are needed, 
40        * call <code>CtNewMethod.getter()</code> and 
41        * <code>CtNewMethod.setter()</code>. 
42        * 
43        * @param type              field type 
44        * @param name              field name 
45        * @param declaring         the class to which the field will be added. 
46        * 
47        * @see CtClass#addField(CtField) 
48        * @see CtNewMethod#getter(String,CtField) 
49        * @see CtNewMethod#setter(String,CtField) 
50        * @see CtField.Initializer 
51        */ 
52       public CtField(CtClass type, String name, CtClass declaring) 
53               throws CannotCompileException { 
54           this(Descriptor.of(type), name, declaring); 
55       } 
56    
57       /** 
58        * Creates a copy of the given field. 
59        * The created field must be added to a class 
60        * with <code>CtClass.addField()</code>. 
61        * An initial value of the field is specified 
62        * by a <code>CtField.Initializer</code> object. 
63        * 
64        * <p>If getter and setter methods are needed, 
65        * call <code>CtNewMethod.getter()</code> and 
66        * <code>CtNewMethod.setter()</code>. 
67        * 
68        * @param src               the original field 
69        * @param declaring         the class to which the field will be added. 
70        * @see CtNewMethod#getter(String,CtField) 
71        * @see CtNewMethod#setter(String,CtField) 
72        * @see CtField.Initializer 
73        */ 
74       public CtField(CtField src, CtClass declaring) 
75               throws CannotCompileException { 
76           this(src.fieldInfo.getDescriptor(), src.fieldInfo.getName(), 
77                   declaring); 
78       } 
79    
80       private CtField(String typeDesc, String name, CtClass clazz) 
81               throws CannotCompileException { 
82           super(clazz); 
83           next = null; 
84           ClassFile cf = clazz.getClassFile2(); 
85           if (cf == null) 
86               throw new CannotCompileException("bad declaring class: " 
87                       + clazz.getName()); 
88    
89           fieldInfo = new FieldInfo(cf.getConstPool(), name, typeDesc); 
90       } 
91    
92       CtField(FieldInfo fi, CtClass clazz) { 
93           super(clazz); 
94           fieldInfo = fi; 
95           next = null; 
96       } 
97    
98       /* Javac.CtFieldWithInit overrides. 
99        */ 
100      protected ASTree getInitAST() { 
101          return null; 
102      } 
103   
104      /* Called by CtClassType.addField(). 
105       */ 
106      Initializer getInit() { 
107          ASTree tree = getInitAST(); 
108          if (tree == null) 
109              return null; 
110          else 
111              return Initializer.byExpr(tree); 
112      } 
113   
114      /** 
115       * Compiles the given source code and creates a field. 
116       * Examples of the source code are: 
117       * 
118       * <ul><pre> 
119       * "public String name;" 
120       * "public int k = 3;"</pre></ul> 
121       * 
122       * <p>Note that the source code ends with <code>';'</code> 
123       * (semicolon). 
124       * 
125       * @param src               the source text. 
126       * @param declaring    the class to which the created field is added. 
127       */ 
128      public static CtField make(String src, CtClass declaring) 
129              throws CannotCompileException { 
130          Javac compiler = new Javac(declaring); 
131          try { 
132              CtMember obj = compiler.compile(src); 
133              if (obj instanceof CtField) 
134                  return (CtField) obj; // an instance of Javac.CtFieldWithInit 
135          } catch (CompileError e) { 
136              throw new CannotCompileException(e); 
137          } 
138   
139          throw new CannotCompileException("not a field"); 
140      } 
141   
142      static CtField append(CtField list, CtField tail) { 
143          tail.next = null; 
144          if (list == null) 
145              return tail; 
146          else { 
147              CtField lst = list; 
148              while (lst.next != null) 
149                  lst = lst.next; 
150   
151              lst.next = tail; 
152              return list; 
153          } 
154      } 
155   
156      static int count(CtField f) { 
157          int n = 0; 
158          while (f != null) { 
159              ++n; 
160              f = f.next; 
161          } 
162   
163          return n; 
164      } 
165   
166      /** 
167       * Returns the FieldInfo representing the field in the class file. 
168       */ 
169      public FieldInfo getFieldInfo() { 
170          declaringClass.checkModify(); 
171          return fieldInfo; 
172      } 
173   
174      /** 
175       * Undocumented method.  Do not use; internal-use only. 
176       */ 
177      public FieldInfo getFieldInfo2() { 
178          return fieldInfo; 
179      } 
180   
181      /** 
182       * Returns the class declaring the field. 
183       */ 
184      public CtClass getDeclaringClass() { 
185          // this is redundant but for javadoc. 
186          return super.getDeclaringClass(); 
187      } 
188   
189      /** 
190       * Returns the name of the field. 
191       */ 
192      public String getName() { 
193          return fieldInfo.getName(); 
194      } 
195   
196      /** 
197       * Changes the name of the field. 
198       */ 
199      public void setName(String newName) { 
200          declaringClass.checkModify(); 
201          fieldInfo.setName(newName); 
202      } 
203   
204      /** 
205       * Returns the encoded modifiers of the field. 
206       * 
207       * @see Modifier 
208       */ 
209      public int getModifiers() { 
210          return AccessFlag.toModifier(fieldInfo.getAccessFlags()); 
211      } 
212   
213      /** 
214       * Sets the encoded modifiers of the field. 
215       * 
216       * @see Modifier 
217       */ 
218      public void setModifiers(int mod) { 
219          declaringClass.checkModify(); 
220          fieldInfo.setAccessFlags(AccessFlag.of(mod)); 
221      } 
222   
223      /** 
224       * Returns the type of the field. 
225       */ 
226      public CtClass getType() throws NotFoundException { 
227          return Descriptor.toCtClass(fieldInfo.getDescriptor(), 
228                  declaringClass.getClassPool()); 
229      } 
230   
231      /** 
232       * Sets the type of the field. 
233       */ 
234      public void setType(CtClass clazz) { 
235          declaringClass.checkModify(); 
236          fieldInfo.setDescriptor(Descriptor.of(clazz)); 
237      } 
238   
239      /** 
240       * Obtains an attribute with the given name. 
241       * If that attribute is not found in the class file, this 
242       * method returns null. 
243       * 
244       * @param name              attribute name 
245       */ 
246      public byte[] getAttribute(String name) { 
247          AttributeInfo ai = fieldInfo.getAttribute(name); 
248          if (ai == null) 
249              return null; 
250          else 
251              return ai.get(); 
252      } 
253   
254      /** 
255       * Adds an attribute. The attribute is saved in the class file. 
256       * 
257       * @param name      attribute name 
258       * @param data      attribute value 
259       */ 
260      public void setAttribute(String name, byte[] data) { 
261          declaringClass.checkModify(); 
262          fieldInfo.addAttribute(new AttributeInfo(fieldInfo.getConstPool(), 
263                  name, data)); 
264      } 
265   
266      // inner classes 
267   
268      /** 
269       * Instances of this class specify how to initialize a field. 
270       * <code>Initializer</code> is passed to 
271       * <code>CtClass.addField()</code> with a <code>CtField</code>. 
272       * 
273       * <p>This class cannot be instantiated with the <code>new</code> operator. 
274       * Factory methods such as <code>byParameter()</code> and 
275       * <code>byNew</code> 
276       * must be used for the instantiation.  They create a new instance with 
277       * the given parameters and return it. 
278       * 
279       * @see CtClass#addField(CtField,CtField.Initializer) 
280       */ 
281      public static abstract class Initializer { 
282          /** 
283           * Makes an initializer that assigns a constant integer value. 
284           * The field must be integer type. 
285           */ 
286          public static Initializer constant(int i) { 
287              return new IntInitializer(i); 
288          } 
289   
290          /** 
291           * Makes an initializer that assigns a constant long value. 
292           * The field must be long type. 
293           */ 
294          public static Initializer constant(long l) { 
295              return new LongInitializer(l); 
296          } 
297   
298          /** 
299           * Makes an initializer that assigns a constant double value. 
300           * The field must be double type. 
301           */ 
302          public static Initializer constant(double d) { 
303              return new DoubleInitializer(d); 
304          } 
305   
306          /** 
307           * Makes an initializer that assigns a constant string value. 
308           * The field must be <code>java.lang.String</code> type. 
309           */ 
310          public static Initializer constant(String s) { 
311              return new StringInitializer(s); 
312          } 
313   
314          /** 
315           * Makes an initializer using a constructor parameter. 
316           * 
317           * <p>The initial value is the 
318           * N-th parameter given to the constructor of the object including 
319           * the field.  If the constructor takes less than N parameters, 
320           * the field is not initialized. 
321           * If the field is static, it is never initialized. 
322           * 
323           * @param nth           the n-th (&gt;= 0) parameter is used as 
324           *                      the initial value. 
325           *                      If nth is 0, then the first parameter is 
326           *                      used. 
327           */ 
328          public static Initializer byParameter(int nth) { 
329              ParamInitializer i = new ParamInitializer(); 
330              i.nthParam = nth; 
331              return i; 
332          } 
333   
334          /** 
335           * Makes an initializer creating a new object. 
336           * 
337           * <p>This initializer creates a new object and uses it as the initial 
338           * value of the field.  The constructor of the created object receives 
339           * the parameter: 
340           * 
341           * <ul><code>Object obj</code> - the object including the field.<br> 
342           * </ul> 
343           * 
344           * <p>If the initialized field is static, then the constructor does 
345           * not receive any parameters. 
346           * 
347           * @param objectType    the class instantiated for the initial value. 
348           */ 
349          public static Initializer byNew(CtClass objectType) { 
350              NewInitializer i = new NewInitializer(); 
351              i.objectType = objectType; 
352              i.stringParams = null; 
353              i.withConstructorParams = false; 
354              return i; 
355          } 
356   
357          /** 
358           * Makes an initializer creating a new object. 
359           * 
360           * <p>This initializer creates a new object and uses it as the initial 
361           * value of the field.  The constructor of the created object receives 
362           * the parameters: 
363           * 
364           * <ul><code>Object obj</code> - the object including the field.<br> 
365           *     <code>String[] strs</code> - the character strings specified 
366           *                              by <code>stringParams</code><br> 
367           * </ul> 
368           * 
369           * <p>If the initialized field is static, then the constructor 
370           * receives only <code>strs</code>. 
371           * 
372           * @param objectType    the class instantiated for the initial value. 
373           * @param stringParams  the array of strings passed to the 
374           *                      constructor. 
375           */ 
376          public static Initializer byNew(CtClass objectType, 
377                                          String[] stringParams) { 
378              NewInitializer i = new NewInitializer(); 
379              i.objectType = objectType; 
380              i.stringParams = stringParams; 
381              i.withConstructorParams = false; 
382              return i; 
383          } 
384   
385          /** 
386           * Makes an initializer creating a new object. 
387           * 
388           * <p>This initializer creates a new object and uses it as the initial 
389           * value of the field.  The constructor of the created object receives 
390           * the parameters: 
391           * 
392           * <ul><code>Object obj</code> - the object including the field.<br> 
393           *     <code>Object[] args</code> - the parameters passed to the 
394           *                      constructor of the object including the 
395           *                      filed. 
396           * </ul> 
397           * 
398           * <p>If the initialized field is static, then the constructor does 
399           * not receive any parameters. 
400           * 
401           * @param objectType    the class instantiated for the initial value. 
402           * 
403           * @see javassist.CtField.Initializer#byNewArray(CtClass,int) 
404           * @see javassist.CtField.Initializer#byNewArray(CtClass,int[]) 
405           */ 
406          public static Initializer byNewWithParams(CtClass objectType) { 
407              NewInitializer i = new NewInitializer(); 
408              i.objectType = objectType; 
409              i.stringParams = null; 
410              i.withConstructorParams = true; 
411              return i; 
412          } 
413   
414          /** 
415           * Makes an initializer creating a new object. 
416           * 
417           * <p>This initializer creates a new object and uses it as the initial 
418           * value of the field.  The constructor of the created object receives 
419           * the parameters: 
420           * 
421           * <ul><code>Object obj</code> - the object including the field.<br> 
422           *     <code>String[] strs</code> - the character strings specified 
423           *                              by <code>stringParams</code><br> 
424           *     <code>Object[] args</code> - the parameters passed to the 
425           *                      constructor of the object including the 
426           *                      filed. 
427           * </ul> 
428           * 
429           * <p>If the initialized field is static, then the constructor receives 
430           * only <code>strs</code>. 
431           * 
432           * @param objectType    the class instantiated for the initial value. 
433           * @param stringParams  the array of strings passed to the 
434           *                              constructor. 
435           */ 
436          public static Initializer byNewWithParams(CtClass objectType, 
437                                                    String[] stringParams) { 
438              NewInitializer i = new NewInitializer(); 
439              i.objectType = objectType; 
440              i.stringParams = stringParams; 
441              i.withConstructorParams = true; 
442              return i; 
443          } 
444   
445          /** 
446           * Makes an initializer calling a static method. 
447           * 
448           * <p>This initializer calls a static method and uses the returned 
449           * value as the initial value of the field. 
450           * The called method receives the parameters: 
451           * 
452           * <ul><code>Object obj</code> - the object including the field.<br> 
453           * </ul> 
454           * 
455           * <p>If the initialized field is static, then the method does 
456           * not receive any parameters. 
457           * 
458           * <p>The type of the returned value must be the same as the field 
459           * type. 
460           * 
461           * @param methodClass   the class that the static method is 
462           *                              declared in. 
463           * @param methodName    the name of the satic method. 
464           */ 
465          public static Initializer byCall(CtClass methodClass, 
466                                           String methodName) { 
467              MethodInitializer i = new MethodInitializer(); 
468              i.objectType = methodClass; 
469              i.methodName = methodName; 
470              i.stringParams = null; 
471              i.withConstructorParams = false; 
472              return i; 
473          } 
474   
475          /** 
476           * Makes an initializer calling a static method. 
477           * 
478           * <p>This initializer calls a static method and uses the returned 
479           * value as the initial value of the field.  The called method 
480           * receives the parameters: 
481           * 
482           * <ul><code>Object obj</code> - the object including the field.<br> 
483           *     <code>String[] strs</code> - the character strings specified 
484           *                              by <code>stringParams</code><br> 
485           * </ul> 
486           * 
487           * <p>If the initialized field is static, then the method 
488           * receive only <code>strs</code>. 
489           * 
490           * <p>The type of the returned value must be the same as the field 
491           * type. 
492           * 
493           * @param methodClass   the class that the static method is 
494           *                              declared in. 
495           * @param methodName    the name of the satic method. 
496           * @param stringParams  the array of strings passed to the 
497           *                              static method. 
498           */ 
499          public static Initializer byCall(CtClass methodClass, 
500                                           String methodName, 
501                                           String[] stringParams) { 
502              MethodInitializer i = new MethodInitializer(); 
503              i.objectType = methodClass; 
504              i.methodName = methodName; 
505              i.stringParams = stringParams; 
506              i.withConstructorParams = false; 
507              return i; 
508          } 
509   
510          /** 
511           * Makes an initializer calling a static method. 
512           * 
513           * <p>This initializer calls a static method and uses the returned 
514           * value as the initial value of the field.  The called method 
515           * receives the parameters: 
516           * 
517           * <ul><code>Object obj</code> - the object including the field.<br> 
518           *     <code>Object[] args</code> - the parameters passed to the 
519           *                      constructor of the object including the 
520           *                      filed. 
521           * </ul> 
522           * 
523           * <p>If the initialized field is static, then the method does 
524           * not receive any parameters. 
525           * 
526           * <p>The type of the returned value must be the same as the field 
527           * type. 
528           * 
529           * @param methodClass   the class that the static method is 
530           *                              declared in. 
531           * @param methodName    the name of the satic method. 
532           */ 
533          public static Initializer byCallWithParams(CtClass methodClass, 
534                                                     String methodName) { 
535              MethodInitializer i = new MethodInitializer(); 
536              i.objectType = methodClass; 
537              i.methodName = methodName; 
538              i.stringParams = null; 
539              i.withConstructorParams = true; 
540              return i; 
541          } 
542   
543          /** 
544           * Makes an initializer calling a static method. 
545           * 
546           * <p>This initializer calls a static method and uses the returned 
547           * value as the initial value of the field.  The called method 
548           * receives the parameters: 
549           * 
550           * <ul><code>Object obj</code> - the object including the field.<br> 
551           *     <code>String[] strs</code> - the character strings specified 
552           *                              by <code>stringParams</code><br> 
553           *     <code>Object[] args</code> - the parameters passed to the 
554           *                      constructor of the object including the 
555           *                      filed. 
556           * </ul> 
557           * 
558           * <p>If the initialized field is static, then the method 
559           * receive only <code>strs</code>. 
560           * 
561           * <p>The type of the returned value must be the same as the field 
562           * type. 
563           * 
564           * @param methodClass   the class that the static method is 
565           *                              declared in. 
566           * @param methodName    the name of the satic method. 
567           * @param stringParams  the array of strings passed to the 
568           *                              static method. 
569           */ 
570          public static Initializer byCallWithParams(CtClass methodClass, 
571                                                     String methodName, String[] stringParams) { 
572              MethodInitializer i = new MethodInitializer(); 
573              i.objectType = methodClass; 
574              i.methodName = methodName; 
575              i.stringParams = stringParams; 
576              i.withConstructorParams = true; 
577              return i; 
578          } 
579   
580          /** 
581           * Makes an initializer creating a new array. 
582           * 
583           * @param type  the type of the array. 
584           * @param size  the size of the array. 
585           * @throws NotFoundException    if the type of the array components 
586           *                              is not found. 
587           */ 
588          public static Initializer byNewArray(CtClass type, int size) 
589                  throws NotFoundException { 
590              return new ArrayInitializer(type.getComponentType(), size); 
591          } 
592   
593          /** 
594           * Makes an initializer creating a new multi-dimensional array. 
595           * 
596           * @param type  the type of the array. 
597           * @param sizes an <code>int</code> array of the size in every 
598           *                      dimension. 
599           *                      The first element is the size in the first 
600           *                      dimension.  The second is in the second, etc. 
601           */ 
602          public static Initializer byNewArray(CtClass type, int[] sizes) { 
603              return new MultiArrayInitializer(type, sizes); 
604          } 
605   
606          /** 
607           * Makes an initializer. 
608           * 
609           * @param source        initializer expression. 
610           */ 
611          public static Initializer byExpr(String source) { 
612              return new CodeInitializer(source); 
613          } 
614   
615          static Initializer byExpr(ASTree source) { 
616              return new PtreeInitializer(source); 
617          } 
618   
619          // Check whether this initializer is valid for the field type. 
620          // If it is invaild, this method throws an exception. 
621          void check(CtClass type) throws CannotCompileException { 
622          } 
623   
624          // produce codes for initialization 
625          abstract int compile(CtClass type, String name, Bytecode code, 
626                               CtClass[] parameters, Javac drv) 
627                  throws CannotCompileException; 
628   
629          // produce codes for initialization 
630          abstract int compileIfStatic(CtClass type, String name, 
631                                       Bytecode code, Javac drv) throws CannotCompileException; 
632      } 
633   
634      static abstract class CodeInitializer0 extends Initializer { 
635          abstract void compileExpr(Javac drv) throws CompileError; 
636   
637          int compile(CtClass type, String name, Bytecode code, 
638                      CtClass[] parameters, Javac drv) 
639                  throws CannotCompileException { 
640              try { 
641                  code.addAload(0); 
642                  compileExpr(drv); 
643                  code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 
644                  return code.getMaxStack(); 
645              } catch (CompileError e) { 
646                  throw new CannotCompileException(e); 
647              } 
648          } 
649   
650          int compileIfStatic(CtClass type, String name, Bytecode code, 
651                              Javac drv) throws CannotCompileException { 
652              try { 
653                  compileExpr(drv); 
654                  code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 
655                  return code.getMaxStack(); 
656              } catch (CompileError e) { 
657                  throw new CannotCompileException(e); 
658              } 
659          } 
660      } 
661   
662      static class CodeInitializer extends CodeInitializer0 { 
663          private String expression; 
664   
665          CodeInitializer(String expr) { 
666              expression = expr; 
667          } 
668   
669          void compileExpr(Javac drv) throws CompileError { 
670              drv.compileExpr(expression); 
671          } 
672      } 
673   
674      static class PtreeInitializer extends CodeInitializer0 { 
675          private ASTree expression; 
676   
677          PtreeInitializer(ASTree expr) { 
678              expression = expr; 
679          } 
680   
681          void compileExpr(Javac drv) throws CompileError { 
682              drv.compileExpr(expression); 
683          } 
684      } 
685   
686      /** 
687       * A field initialized with a parameter passed to the constructor 
688       * of the class containing that field. 
689       */ 
690      static class ParamInitializer extends Initializer { 
691          int nthParam; 
692   
693          ParamInitializer() { 
694          } 
695   
696          int compile(CtClass type, String name, Bytecode code, 
697                      CtClass[] parameters, Javac drv) 
698                  throws CannotCompileException { 
699              if (parameters != null && nthParam < parameters.length) { 
700                  code.addAload(0); 
701                  int nth = nthParamToLocal(nthParam, parameters, false); 
702                  int s = code.addLoad(nth, type) + 1; 
703                  code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 
704                  return s;       // stack size 
705              } else 
706                  return 0;       // do not initialize 
707          } 
708   
709          /** 
710           * Computes the index of the local variable that the n-th parameter 
711           * is assigned to. 
712           * 
713           * @param nth           n-th parameter 
714           * @param params                list of parameter types 
715           * @param isStatic              true if the method is static. 
716           */ 
717          static int nthParamToLocal(int nth, CtClass[] params, 
718                                     boolean isStatic) { 
719              CtClass longType = CtClass.longType; 
720              CtClass doubleType = CtClass.doubleType; 
721              int k; 
722              if (isStatic) 
723                  k = 0; 
724              else 
725                  k = 1;  // 0 is THIS. 
726   
727              for (int i = 0; i < nth; ++i) { 
728                  CtClass type = params[i]; 
729                  if (type == longType || type == doubleType) 
730                      k += 2; 
731                  else 
732                      ++k; 
733              } 
734   
735              return k; 
736          } 
737   
738          int compileIfStatic(CtClass type, String name, Bytecode code, 
739                              Javac drv) throws CannotCompileException { 
740              return 0; 
741          } 
742      } 
743   
744      /** 
745       * A field initialized with an object created by the new operator. 
746       */ 
747      static class NewInitializer extends Initializer { 
748          CtClass objectType; 
749          String[] stringParams; 
750          boolean withConstructorParams; 
751   
752          NewInitializer() { 
753          } 
754   
755          /** 
756           * Produces codes in which a new object is created and assigned to 
757           * the field as the initial value. 
758           */ 
759          int compile(CtClass type, String name, Bytecode code, 
760                      CtClass[] parameters, Javac drv) 
761                  throws CannotCompileException { 
762              int stacksize; 
763   
764              code.addAload(0); 
765              code.addNew(objectType); 
766              code.add(Bytecode.DUP); 
767              code.addAload(0); 
768   
769              if (stringParams == null) 
770                  stacksize = 4; 
771              else 
772                  stacksize = compileStringParameter(code) + 4; 
773   
774              if (withConstructorParams) 
775                  stacksize += CtNewWrappedMethod.compileParameterList(code, 
776                          parameters, 1); 
777   
778              code.addInvokespecial(objectType, "<init>", getDescriptor()); 
779              code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 
780              return stacksize; 
781          } 
782   
783          private String getDescriptor() { 
784              final String desc3 
785                      = "(Ljava/lang/Object;[Ljava/lang/String;[Ljava/lang/Object;)V"; 
786   
787              if (stringParams == null) 
788                  if (withConstructorParams) 
789                      return "(Ljava/lang/Object;[Ljava/lang/Object;)V"; 
790                  else 
791                      return "(Ljava/lang/Object;)V"; 
792              else if (withConstructorParams) 
793                  return desc3; 
794              else 
795                  return "(Ljava/lang/Object;[Ljava/lang/String;)V"; 
796          } 
797   
798          /** 
799           * Produces codes for a static field. 
800           */ 
801          int compileIfStatic(CtClass type, String name, Bytecode code, 
802                              Javac drv) throws CannotCompileException { 
803              String desc; 
804   
805              code.addNew(objectType); 
806              code.add(Bytecode.DUP); 
807   
808              int stacksize = 2; 
809              if (stringParams == null) 
810                  desc = "()V"; 
811              else { 
812                  desc = "([Ljava/lang/String;)V"; 
813                  stacksize += compileStringParameter(code); 
814              } 
815   
816              code.addInvokespecial(objectType, "<init>", desc); 
817              code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 
818              return stacksize; 
819          } 
820   
821          protected final int compileStringParameter(Bytecode code) 
822                  throws CannotCompileException { 
823              int nparam = stringParams.length; 
824              code.addIconst(nparam); 
825              code.addAnewarray("java.lang.String"); 
826              for (int j = 0; j < nparam; ++j) { 
827                  code.add(Bytecode.DUP);         // dup 
828                  code.addIconst(j);                      // iconst_<j> 
829                  code.addLdc(stringParams[j]);   // ldc ... 
830                  code.add(Bytecode.AASTORE);             // aastore 
831              } 
832   
833              return 4; 
834          } 
835   
836      } 
837   
838      /** 
839       * A field initialized with the result of a static method call. 
840       */ 
841      static class MethodInitializer extends NewInitializer { 
842          String methodName; 
843          // the method class is specified by objectType. 
844   
845          MethodInitializer() { 
846          } 
847   
848          /** 
849           * Produces codes in which a new object is created and assigned to 
850           * the field as the initial value. 
851           */ 
852          int compile(CtClass type, String name, Bytecode code, 
853                      CtClass[] parameters, Javac drv) 
854                  throws CannotCompileException { 
855              int stacksize; 
856   
857              code.addAload(0); 
858              code.addAload(0); 
859   
860              if (stringParams == null) 
861                  stacksize = 2; 
862              else 
863                  stacksize = compileStringParameter(code) + 2; 
864   
865              if (withConstructorParams) 
866                  stacksize += CtNewWrappedMethod.compileParameterList(code, 
867                          parameters, 1); 
868   
869              String typeDesc = Descriptor.of(type); 
870              String mDesc = getDescriptor() + typeDesc; 
871              code.addInvokestatic(objectType, methodName, mDesc); 
872              code.addPutfield(Bytecode.THIS, name, typeDesc); 
873              return stacksize; 
874          } 
875   
876          private String getDescriptor() { 
877              final String desc3 
878                      = "(Ljava/lang/Object;[Ljava/lang/String;[Ljava/lang/Object;)"; 
879   
880              if (stringParams == null) 
881                  if (withConstructorParams) 
882                      return "(Ljava/lang/Object;[Ljava/lang/Object;)"; 
883                  else 
884                      return "(Ljava/lang/Object;)"; 
885              else if (withConstructorParams) 
886                  return desc3; 
887              else 
888                  return "(Ljava/lang/Object;[Ljava/lang/String;)"; 
889          } 
890   
891          /** 
892           * Produces codes for a static field. 
893           */ 
894          int compileIfStatic(CtClass type, String name, Bytecode code, 
895                              Javac drv) throws CannotCompileException { 
896              String desc; 
897   
898              int stacksize = 1; 
899              if (stringParams == null) 
900                  desc = "()"; 
901              else { 
902                  desc = "([Ljava/lang/String;)"; 
903                  stacksize += compileStringParameter(code); 
904              } 
905   
906              String typeDesc = Descriptor.of(type); 
907              code.addInvokestatic(objectType, methodName, desc + typeDesc); 
908              code.addPutstatic(Bytecode.THIS, name, typeDesc); 
909              return stacksize; 
910          } 
911      } 
912   
913      static class IntInitializer extends Initializer { 
914          int value; 
915   
916          IntInitializer(int v) { 
917              value = v; 
918          } 
919   
920          void check(CtClass type) throws CannotCompileException { 
921              if (type != CtClass.intType) 
922                  throw new CannotCompileException("type mismatch"); 
923          } 
924   
925          int compile(CtClass type, String name, Bytecode code, 
926                      CtClass[] parameters, Javac drv) 
927                  throws CannotCompileException { 
928              code.addAload(0); 
929              code.addIconst(value); 
930              code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 
931              return 2;   // stack size 
932          } 
933   
934          int compileIfStatic(CtClass type, String name, Bytecode code, 
935                              Javac drv) throws CannotCompileException { 
936              code.addIconst(value); 
937              code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 
938              return 1;   // stack size 
939          } 
940      } 
941   
942      static class LongInitializer extends Initializer { 
943          long value; 
944   
945          LongInitializer(long v) { 
946              value = v; 
947          } 
948   
949          void check(CtClass type) throws CannotCompileException { 
950              if (type != CtClass.longType) 
951                  throw new CannotCompileException("type mismatch"); 
952          } 
953   
954          int compile(CtClass type, String name, Bytecode code, 
955                      CtClass[] parameters, Javac drv) 
956                  throws CannotCompileException { 
957              code.addAload(0); 
958              code.addLdc2w(value); 
959              code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 
960              return 3;   // stack size 
961          } 
962   
963          int compileIfStatic(CtClass type, String name, Bytecode code, 
964                              Javac drv) throws CannotCompileException { 
965              code.addLdc2w(value); 
966              code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 
967              return 2;   // stack size 
968          } 
969      } 
970   
971      static class DoubleInitializer extends Initializer { 
972          double value; 
973   
974          DoubleInitializer(double v) { 
975              value = v; 
976          } 
977   
978          void check(CtClass type) throws CannotCompileException { 
979              if (type != CtClass.doubleType) 
980                  throw new CannotCompileException("type mismatch"); 
981          } 
982   
983          int compile(CtClass type, String name, Bytecode code, 
984                      CtClass[] parameters, Javac drv) 
985                  throws CannotCompileException { 
986              code.addAload(0); 
987              code.addLdc2w(value); 
988              code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 
989              return 3;   // stack size 
990          } 
991   
992          int compileIfStatic(CtClass type, String name, Bytecode code, 
993                              Javac drv) throws CannotCompileException { 
994              code.addLdc2w(value); 
995              code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 
996              return 2;   // stack size 
997          } 
998      } 
999   
1000     static class StringInitializer extends Initializer { 
1001         String value; 
1002  
1003         StringInitializer(String v) { 
1004             value = v; 
1005         } 
1006  
1007         void check(CtClass type) throws CannotCompileException { 
1008             if (!type.getName().equals("java.lang.String")) 
1009                 throw new CannotCompileException("type mismatch"); 
1010         } 
1011  
1012         int compile(CtClass type, String name, Bytecode code, 
1013                     CtClass[] parameters, Javac drv) 
1014                 throws CannotCompileException { 
1015             code.addAload(0); 
1016             code.addLdc(value); 
1017             code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 
1018             return 2;   // stack size 
1019         } 
1020  
1021         int compileIfStatic(CtClass type, String name, Bytecode code, 
1022                             Javac drv) throws CannotCompileException { 
1023             code.addLdc(value); 
1024             code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 
1025             return 1;   // stack size 
1026         } 
1027     } 
1028  
1029     static class ArrayInitializer extends Initializer { 
1030         CtClass type; 
1031         int size; 
1032  
1033         ArrayInitializer(CtClass t, int s) { 
1034             type = t; 
1035             size = s; 
1036         } 
1037  
1038         private void addNewarray(Bytecode code) { 
1039             if (type.isPrimitive()) 
1040                 code.addNewarray(((CtPrimitiveType) type).getArrayType(), 
1041                         size); 
1042             else 
1043                 code.addAnewarray(type, size); 
1044         } 
1045  
1046         int compile(CtClass type, String name, Bytecode code, 
1047                     CtClass[] parameters, Javac drv) 
1048                 throws CannotCompileException { 
1049             code.addAload(0); 
1050             addNewarray(code); 
1051             code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 
1052             return 2;   // stack size 
1053         } 
1054  
1055         int compileIfStatic(CtClass type, String name, Bytecode code, 
1056                             Javac drv) throws CannotCompileException { 
1057             addNewarray(code); 
1058             code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 
1059             return 1;   // stack size 
1060         } 
1061     } 
1062  
1063     static class MultiArrayInitializer extends Initializer { 
1064         CtClass type; 
1065         int[] dim; 
1066  
1067         MultiArrayInitializer(CtClass t, int[] d) { 
1068             type = t; 
1069             dim = d; 
1070         } 
1071  
1072         void check(CtClass type) throws CannotCompileException { 
1073             if (!type.isArray()) 
1074                 throw new CannotCompileException("type mismatch"); 
1075         } 
1076  
1077         int compile(CtClass type, String name, Bytecode code, 
1078                     CtClass[] parameters, Javac drv) 
1079                 throws CannotCompileException { 
1080             code.addAload(0); 
1081             int s = code.addMultiNewarray(type, dim); 
1082             code.addPutfield(Bytecode.THIS, name, Descriptor.of(type)); 
1083             return s + 1;       // stack size 
1084         } 
1085  
1086         int compileIfStatic(CtClass type, String name, Bytecode code, 
1087                             Javac drv) throws CannotCompileException { 
1088             int s = code.addMultiNewarray(type, dim); 
1089             code.addPutstatic(Bytecode.THIS, name, Descriptor.of(type)); 
1090             return s;   // stack size 
1091         } 
1092     } 
1093 } 
1094