/Users/lyon/j4p/src/javassist/CtConstructor.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.expr.ExprEditor; 
22    
23   /* Some methods do nothing except calling the super's method. 
24    * They might seem redundant but they are necessary so that javadoc 
25    * includes the description of those methods in the page of this class. 
26    */ 
27    
28   /** 
29    * An instance of CtConstructor represents a constructor. 
30    * It may represent a static constructor 
31    * (class initializer).  To distinguish a constructor and a class 
32    * initializer, call <code>isClassInitializer()</code>. 
33    * 
34    * @see CtClass#getDeclaredConstructors() 
35    * @see CtClass#getClassInitializer() 
36    * @see CtNewConstructor 
37    */ 
38   public final class CtConstructor extends CtBehavior { 
39       protected CtConstructor next; 
40    
41       protected CtConstructor(MethodInfo minfo, CtClass declaring) { 
42           super(declaring, minfo); 
43           next = null; 
44       } 
45    
46       /** 
47        * Creates a constructor with no constructor body. 
48        * The created constructor 
49        * must be added to a class with <code>CtClass.addConstructor()</code>. 
50        * 
51        * <p>The created constructor does not include a constructor body, 
52        * must be specified with <code>setBody()</code>. 
53        * 
54        * @param declaring         the class to which the created method is added. 
55        * @param parameters        a list of the parameter types 
56        * 
57        * @see CtClass#addConstructor(CtConstructor) 
58        * @see CtConstructor#setBody(String) 
59        * @see CtConstructor#setBody(CtConstructor,ClassMap) 
60        */ 
61       public CtConstructor(CtClass[] parameters, CtClass declaring) { 
62           this((MethodInfo) null, declaring); 
63           ConstPool cp = declaring.getClassFile2().getConstPool(); 
64           String desc = Descriptor.ofConstructor(parameters); 
65           methodInfo = new MethodInfo(cp, "<init>", desc); 
66           setModifiers(Modifier.PUBLIC); 
67       } 
68    
69       /** 
70        * Creates a copy of a <code>CtConstructor</code> object. 
71        * The created constructor must be 
72        * added to a class with <code>CtClass.addConstructor()</code>. 
73        * 
74        * <p>All occurrences of class names in the created constructor 
75        * are replaced with names specified by 
76        * <code>map</code> if <code>map</code> is not <code>null</code>. 
77        * 
78        * <p>By default, all the occurrences of the names of the class 
79        * declaring <code>src</code> and the superclass are replaced 
80        * with the name of the class and the superclass that 
81        * the created constructor is added to. 
82        * This is done whichever <code>map</code> is null or not. 
83        * To prevent this replacement, call <code>ClassMap.fix()</code>. 
84        * 
85        * <p><b>Note:</b> if the <code>.class</code> notation (for example, 
86        * <code>String.class</code>) is included in an expression, the 
87        * Javac compiler may produce a helper method. 
88        * Since this constructor never 
89        * copies this helper method, the programmers have the responsiblity of 
90        * copying it.  Otherwise, use <code>Class.forName()</code> in the 
91        * expression. 
92        * 
93        * @param src       the source method. 
94        * @param declaring    the class to which the created method is added. 
95        * @param map       the hashtable associating original class names 
96        *                  with substituted names. 
97        *                  It can be <code>null</code>. 
98        * 
99        * @see CtClass#addConstructor(CtConstructor) 
100       * @see ClassMap#fix(String) 
101       */ 
102      public CtConstructor(CtConstructor src, CtClass declaring, ClassMap map) 
103              throws CannotCompileException { 
104          this((MethodInfo) null, declaring); 
105          MethodInfo srcInfo = src.methodInfo; 
106          CtClass srcClass = src.getDeclaringClass(); 
107          ConstPool cp = declaring.getClassFile2().getConstPool(); 
108          if (map == null) 
109              map = new ClassMap(); 
110   
111          map.put(srcClass.getName(), declaring.getName()); 
112          try { 
113              boolean patch = false; 
114              CtClass srcSuper = srcClass.getSuperclass(); 
115              String destSuperName = declaring.getSuperclass().getName(); 
116              if (srcSuper != null) { 
117                  String srcSuperName = srcSuper.getName(); 
118                  if (!srcSuperName.equals(destSuperName)) 
119                      if (srcSuperName.equals(CtClass.javaLangObject)) 
120                          patch = true; 
121                      else 
122                          map.put(srcSuperName, destSuperName); 
123              } 
124   
125              methodInfo = new MethodInfo(cp, srcInfo.getName(), srcInfo, map); 
126              if (patch) 
127                  methodInfo.setSuperclass(destSuperName); 
128          } catch (NotFoundException e) { 
129              throw new CannotCompileException(e); 
130          } catch (BadBytecode e) { 
131              throw new CannotCompileException(e); 
132          } 
133      } 
134   
135      static CtConstructor append(CtConstructor list, CtConstructor tail) { 
136          tail.next = null; 
137          if (list == null) 
138              return tail; 
139          else { 
140              CtConstructor lst = list; 
141              while (lst.next != null) 
142                  lst = lst.next; 
143   
144              lst.next = tail; 
145              return list; 
146          } 
147      } 
148   
149      static int count(CtConstructor m) { 
150          int n = 0; 
151          while (m != null) { 
152              ++n; 
153              m = m.next; 
154          } 
155   
156          return n; 
157      } 
158   
159      /** 
160       * Returns the MethodInfo representing the constructor in the 
161       * class file. 
162       */ 
163      public MethodInfo getMethodInfo() { 
164          return super.getMethodInfo(); 
165      } 
166   
167      /** 
168       * Returns true if this object represents a constructor. 
169       */ 
170      public boolean isConstructor() { 
171          return methodInfo.isConstructor(); 
172      } 
173   
174      /** 
175       * Returns true if this object represents a static initializer. 
176       */ 
177      public boolean isClassInitializer() { 
178          return methodInfo.isStaticInitializer(); 
179      } 
180   
181      /** 
182       * Obtains the encoded modifiers of the constructor. 
183       * 
184       * @return          modifiers encoded with 
185       *                  <code>javassist.Modifier</code>. 
186       * @see Modifier 
187       */ 
188      public int getModifiers() { 
189          return super.getModifiers(); 
190      } 
191   
192      /** 
193       * Sets the encoded modifiers of the constructor. 
194       * 
195       * @see Modifier 
196       */ 
197      public void setModifiers(int mod) { 
198          super.setModifiers(mod); 
199      } 
200   
201      /** 
202       * Obtains the name of this constructor. 
203       * It is the same as the simple name of the class declaring this 
204       * constructor.  If this object represents a class initializer, 
205       * then this method returns <code>"&lt;clinit&gt;"</code>. 
206       */ 
207      public String getName() { 
208          if (methodInfo.isStaticInitializer()) 
209              return MethodInfo.nameClinit; 
210          else 
211              return declaringClass.getName(); 
212      } 
213   
214      /** 
215       * Returns the class that declares this constructor. 
216       */ 
217      public CtClass getDeclaringClass() { 
218          return super.getDeclaringClass(); 
219      } 
220   
221      /** 
222       * Obtains parameter types of this constructor. 
223       */ 
224      public CtClass[] getParameterTypes() throws NotFoundException { 
225          return super.getParameterTypes(); 
226      } 
227   
228      /** 
229       * Returns the character string representing the parameter types. 
230       * If two constructors have the same parameter types, 
231       * <code>getSignature()</code> returns the same string. 
232       */ 
233      public String getSignature() { 
234          return super.getSignature(); 
235      } 
236   
237      /** 
238       * Obtains exceptions that this constructor may throw. 
239       */ 
240      public CtClass[] getExceptionTypes() throws NotFoundException { 
241          return super.getExceptionTypes(); 
242      } 
243   
244      /** 
245       * Sets exceptions that this constructor may throw. 
246       */ 
247      public void setExceptionTypes(CtClass[] types) 
248              throws NotFoundException { 
249          super.setExceptionTypes(types); 
250      } 
251   
252      /** 
253       * Returns true if the constructor is the default one. 
254       */ 
255      public boolean isEmpty() { 
256          CodeAttribute ca = getMethodInfo2().getCodeAttribute(); 
257          if (ca == null) 
258              return false;       // native or abstract?? 
259          // they are not allowed, though. 
260   
261          ConstPool cp = ca.getConstPool(); 
262          CodeIterator it = ca.iterator(); 
263          try { 
264              int pos, desc; 
265              return it.byteAt(it.next()) == Opcode.ALOAD_0 
266                      && it.byteAt(pos = it.next()) == Opcode.INVOKESPECIAL 
267                      && (desc = cp.isConstructor(CtClass.javaLangObject, 
268                              it.u16bitAt(pos + 1))) != 0 
269                      && cp.getUtf8Info(desc).equals("()V") 
270                      && it.byteAt(it.next()) == Opcode.RETURN 
271                      && !it.hasNext(); 
272          } catch (BadBytecode e) { 
273          } 
274          return false; 
275      } 
276   
277      /** 
278       * Sets a constructor body. 
279       * 
280       * @param src       the source code representing the constructor body. 
281       *                  It must be a single statement or block. 
282       *                  If it is <code>null</code>, the substituted 
283       *                  constructor body does nothing except calling 
284       *                  <code>super()</code>. 
285       */ 
286      public void setBody(String src) throws CannotCompileException { 
287          if (src == null) 
288              if (isClassInitializer()) 
289                  src = ";"; 
290              else 
291                  src = "super();"; 
292   
293          super.setBody(src); 
294      } 
295   
296      /** 
297       * Copies a constructor body from another constructor. 
298       * 
299       * <p>All occurrences of the class names in the copied body 
300       * are replaced with the names specified by 
301       * <code>map</code> if <code>map</code> is not <code>null</code>. 
302       * 
303       * @param src       the method that the body is copied from. 
304       * @param map       the hashtable associating original class names 
305       *                  with substituted names. 
306       *                  It can be <code>null</code>. 
307       */ 
308      public void setBody(CtConstructor src, ClassMap map) 
309              throws CannotCompileException { 
310          setBody0(src.declaringClass, src.methodInfo, 
311                  declaringClass, methodInfo, map); 
312      } 
313   
314      /** 
315       * Obtains an attribute with the given name. 
316       * If that attribute is not found in the class file, this 
317       * method returns null. 
318       * 
319       * @param name              attribute name 
320       */ 
321      public byte[] getAttribute(String name) { 
322          return super.getAttribute(name); 
323      } 
324   
325      /** 
326       * Adds an attribute. The attribute is saved in the class file. 
327       * 
328       * @param name      attribute name 
329       * @param data      attribute value 
330       */ 
331      public void setAttribute(String name, byte[] data) { 
332          super.setAttribute(name, data); 
333      } 
334   
335      /** 
336       * Declares to use <code>$cflow</code> for this constructor. 
337       * If <code>$cflow</code> is used, the class files modified 
338       * with Javassist requires a support class 
339       * <code>javassist.runtime.Cflow</code> at runtime 
340       * (other Javassist classes are not required at runtime). 
341       * 
342       * <p>Every <code>$cflow</code> variable is given a unique name. 
343       * For example, if the given name is <code>"Point.paint"</code>, 
344       * then the variable is indicated by <code>$cflow(Point.paint)</code>. 
345       * 
346       * @param name      <code>$cflow</code> name.  It can include 
347       *                  alphabets, numbers, <code>_</code>, 
348       *                  <code>$</code>, and <code>.</code> (dot). 
349       * 
350       * @see javassist.runtime.Cflow 
351       */ 
352      public void useCflow(String name) throws CannotCompileException { 
353          super.useCflow(name); 
354      } 
355   
356      /** 
357       * Modifies the constructor body. 
358       * 
359       * @param converter         specifies how to modify. 
360       */ 
361      public void instrument(CodeConverter converter) 
362              throws CannotCompileException { 
363          super.instrument(converter); 
364      } 
365   
366      /** 
367       * Modifies the constructor body. 
368       * 
369       * @param editor            specifies how to modify. 
370       */ 
371      public void instrument(ExprEditor editor) 
372              throws CannotCompileException { 
373          super.instrument(editor); 
374      } 
375   
376      /** 
377       * Inserts bytecode at the beginning of the constructor body. 
378       * Since the bytecode is inserted before a constructor in the super 
379       * class or this class is called, the bytecode is subject 
380       * to constraints described 
381       * in Section 4.8.2 of The Java Virtual Machine Specification (2nd ed). 
382       * For example, it cannot access instance members although it can access 
383       * static members. 
384       * 
385       * @param src       the source code representing the inserted bytecode. 
386       *                  It must be a single statement or block. 
387       */ 
388      public void insertBefore(String src) throws CannotCompileException { 
389          super.insertBefore(src); 
390      } 
391   
392      /** 
393       * Inserts bytecode just after another constructor in the super class 
394       * or this class is called. 
395       * It does not work if this object represents a class initializer. 
396       * 
397       * @param src       the source code representing the inserted bytecode. 
398       *                  It must be a single statement or block. 
399       */ 
400      public void insertBeforeBody(String src) throws CannotCompileException { 
401          declaringClass.checkModify(); 
402          if (isClassInitializer()) 
403              throw new CannotCompileException("class initializer"); 
404   
405          CodeAttribute ca = methodInfo.getCodeAttribute(); 
406          CodeIterator iterator = ca.iterator(); 
407          Bytecode b = new Bytecode(methodInfo.getConstPool(), 
408                  ca.getMaxStack(), ca.getMaxLocals()); 
409          b.setStackDepth(ca.getMaxStack()); 
410          Javac jv = new Javac(b, declaringClass); 
411          try { 
412              jv.recordParams(getParameterTypes(), false); 
413              jv.compileStmnt(src); 
414              ca.setMaxStack(b.getMaxStack()); 
415              ca.setMaxLocals(b.getMaxLocals()); 
416              iterator.skipConstructor(); 
417              int pos = iterator.insertEx(b.get()); 
418              iterator.insert(b.getExceptionTable(), pos); 
419          } catch (NotFoundException e) { 
420              throw new CannotCompileException(e); 
421          } catch (CompileError e) { 
422              throw new CannotCompileException(e); 
423          } catch (BadBytecode e) { 
424              throw new CannotCompileException(e); 
425          } 
426      } 
427   
428      /** 
429       * Inserts bytecode at the end of the constructor body. 
430       * The bytecode is inserted just before every return insturction. 
431       * It is not executed when an exception is thrown. 
432       * 
433       * @param src       the source code representing the inserted bytecode. 
434       *                  It must be a single statement or block. 
435       */ 
436      public void insertAfter(String src) 
437              throws CannotCompileException { 
438          super.insertAfter(src); 
439      } 
440   
441      /** 
442       * Inserts bytecode at the end of the constructor body. 
443       * The bytecode is inserted just before every return insturction. 
444       * 
445       * @param src       the source code representing the inserted bytecode. 
446       *                  It must be a single statement or block. 
447       * @param asFinally         true if the inserted bytecode is executed 
448       *                  not only when the transfer normally returns 
449       *                  but also when an exception is thrown. 
450       */ 
451      public void insertAfter(String src, boolean asFinally) 
452              throws CannotCompileException { 
453          super.insertAfter(src, asFinally); 
454      } 
455   
456      /** 
457       * Adds a catch clause that handles an exception thrown in the 
458       * constructor body. 
459       * The catch clause must end with a return or throw statement. 
460       * 
461       * @param src       the source code representing the catch clause. 
462       *                  It must be a single statement or block. 
463       * @param exceptionType     the type of the exception handled by the 
464       *                          catch clause. 
465       */ 
466      public void addCatch(String src, CtClass exceptionType) 
467              throws CannotCompileException { 
468          super.addCatch(src, exceptionType); 
469      } 
470  } 
471