/Users/lyon/j4p/src/javassist/CtMethod.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.expr.ExprEditor; 
20    
21   /* Some methods do nothing except calling the super's method. 
22    * They might seem redundant but they are necessary so that javadoc 
23    * includes the description of those methods in the page of this class. 
24    */ 
25    
26   /** 
27    * An instance of <code>CtMethod</code> represents a method. 
28    * 
29    * @see CtClass#getDeclaredMethods() 
30    * @see CtNewMethod 
31    */ 
32   public final class CtMethod extends CtBehavior { 
33       protected CtMethod next; 
34       protected int cachedHashCode; 
35    
36       CtMethod(MethodInfo minfo, CtClass declaring) { 
37           super(declaring, minfo); 
38           next = null; 
39           cachedHashCode = 0; 
40       } 
41    
42       /** 
43        * Creates a public abstract method.  The created method must be 
44        * added to a class with <code>CtClass.addMethod()</code>. 
45        * 
46        * @param declaring         the class to which the created method is added. 
47        * @param returnType        the type of the returned value 
48        * @param mname             the method name 
49        * @param parameters        a list of the parameter types 
50        * 
51        * @see CtClass#addMethod(CtMethod) 
52        */ 
53       public CtMethod(CtClass returnType, String mname, 
54                       CtClass[] parameters, CtClass declaring) { 
55           this(null, declaring); 
56           ConstPool cp = declaring.getClassFile2().getConstPool(); 
57           String desc = Descriptor.ofMethod(returnType, parameters); 
58           methodInfo = new MethodInfo(cp, mname, desc); 
59           setModifiers(Modifier.PUBLIC | Modifier.ABSTRACT); 
60       } 
61    
62       /** 
63        * Creates a copy of a <code>CtMethod</code> object. 
64        * The created method must be 
65        * added to a class with <code>CtClass.addMethod()</code>. 
66        * 
67        * <p>All occurrences of class names in the created method 
68        * are replaced with names specified by 
69        * <code>map</code> if <code>map</code> is not <code>null</code>. 
70        * 
71        * <p>For example, suppose that a method <code>at()</code> is as 
72        * follows: 
73        * 
74        * <ul><pre>public X at(int i) { 
75        *     return (X)super.elementAt(i); 
76        * }</pre></ul> 
77        * 
78        * <p>(<code>X</code> is a class name.)  If <code>map</code> substitutes 
79        * <code>String</code> for <code>X</code>, then the created method is: 
80        * 
81        * <ul><pre>public String at(int i) { 
82        *     return (String)super.elementAt(i); 
83        * }</pre></ul> 
84        * 
85        * <p>By default, all the occurrences of the names of the class 
86        * declaring <code>at()</code> and the superclass are replaced 
87        * with the name of the class and the superclass that the 
88        * created method is added to. 
89        * This is done whichever <code>map</code> is null or not. 
90        * To prevent this replacement, call <code>ClassMap.fix()</code>. 
91        * 
92        * <p><b>Note:</b> if the <code>.class</code> notation (for example, 
93        * <code>String.class</code>) is included in an expression, the 
94        * Javac compiler may produce a helper method. 
95        * Since this constructor never 
96        * copies this helper method, the programmers have the responsiblity of 
97        * copying it.  Otherwise, use <code>Class.forName()</code> in the 
98        * expression. 
99        * 
100       * @param src       the source method. 
101       * @param declaring    the class to which the created method is added. 
102       * @param map       the hashtable associating original class names 
103       *                  with substituted names. 
104       *                  It can be <code>null</code>. 
105       * 
106       * @see CtClass#addMethod(CtMethod) 
107       * @see ClassMap#fix(String) 
108       */ 
109      public CtMethod(CtMethod src, CtClass declaring, ClassMap map) 
110              throws CannotCompileException { 
111          this(null, declaring); 
112          MethodInfo srcInfo = src.methodInfo; 
113          CtClass srcClass = src.getDeclaringClass(); 
114          ConstPool cp = declaring.getClassFile2().getConstPool(); 
115          if (map == null) 
116              map = new ClassMap(); 
117   
118          map.put(srcClass.getName(), declaring.getName()); 
119          try { 
120              CtClass srcSuper = srcClass.getSuperclass(); 
121              if (srcSuper != null) { 
122                  String srcSuperName = srcSuper.getName(); 
123                  if (!srcSuperName.equals(CtClass.javaLangObject)) 
124                      map.put(srcSuperName, 
125                              declaring.getSuperclass().getName()); 
126              } 
127   
128              methodInfo = new MethodInfo(cp, srcInfo.getName(), srcInfo, map); 
129          } catch (NotFoundException e) { 
130              throw new CannotCompileException(e); 
131          } catch (BadBytecode e) { 
132              throw new CannotCompileException(e); 
133          } 
134      } 
135   
136      static CtMethod append(CtMethod list, CtMethod tail) { 
137          tail.next = null; 
138          if (list == null) 
139              return tail; 
140          else { 
141              CtMethod lst = list; 
142              while (lst.next != null) 
143                  lst = lst.next; 
144   
145              lst.next = tail; 
146              return list; 
147          } 
148      } 
149   
150      static int count(CtMethod m) { 
151          int n = 0; 
152          while (m != null) { 
153              ++n; 
154              m = m.next; 
155          } 
156   
157          return n; 
158      } 
159   
160      /** 
161       * Returns a hash code value for the method. 
162       * If two methods have the same name and signature, then 
163       * the hash codes for the two methods are equal. 
164       */ 
165      public int hashCode() { 
166          /* This method is overridden in ExistingMethod for optimization. 
167           */ 
168          if (cachedHashCode == 0) { 
169              String signature 
170                      = methodInfo.getName() + ':' + methodInfo.getDescriptor(); 
171   
172              // System.identityHashCode() returns 0 only for null. 
173              cachedHashCode = System.identityHashCode(signature.intern()); 
174          } 
175   
176          return cachedHashCode; 
177      } 
178   
179      /** 
180       * Indicates whether <code>obj</code> has the same name and the 
181       * same signature as this method. 
182       */ 
183      public boolean equals(Object obj) { 
184          return obj != null && obj instanceof CtMethod 
185                  && obj.hashCode() == hashCode(); 
186      } 
187   
188      /** 
189       * Returns the MethodInfo representing the method in the class file. 
190       */ 
191      public MethodInfo getMethodInfo() { 
192          return super.getMethodInfo(); 
193      } 
194   
195      /** 
196       * Obtains the modifiers of the method. 
197       * 
198       * @return          modifiers encoded with 
199       *                  <code>javassist.Modifier</code>. 
200       * @see Modifier 
201       */ 
202      public int getModifiers() { 
203          return super.getModifiers(); 
204      } 
205   
206      /** 
207       * Sets the encoded modifiers of the method. 
208       * 
209       * <p>Changing the modifiers may cause a problem. 
210       * For example, if a non-static method is changed to static, 
211       * the method will be rejected by the bytecode verifier. 
212       * 
213       * @see Modifier 
214       */ 
215      public void setModifiers(int mod) { 
216          super.setModifiers(mod); 
217      } 
218   
219      /** 
220       * Obtains the name of this method. 
221       */ 
222      public String getName() { 
223          return methodInfo.getName(); 
224      } 
225   
226      /** 
227       * Changes the name of this method. 
228       */ 
229      public void setName(String newname) { 
230          declaringClass.checkModify(); 
231          methodInfo.setName(newname); 
232      } 
233   
234      /** 
235       * Returns the class that declares this method. 
236       */ 
237      public CtClass getDeclaringClass() { 
238          return super.getDeclaringClass(); 
239      } 
240   
241      /** 
242       * Obtains parameter types of this method. 
243       */ 
244      public CtClass[] getParameterTypes() throws NotFoundException { 
245          return super.getParameterTypes(); 
246      } 
247   
248      /** 
249       * Obtains the type of the returned value. 
250       */ 
251      public CtClass getReturnType() throws NotFoundException { 
252          return getReturnType0(); 
253      } 
254   
255      /** 
256       * Returns the character string representing the parameter types 
257       * and the return type.  If two methods have the same parameter types 
258       * and the return type, <code>getSignature()</code> returns the 
259       * same string. 
260       */ 
261      public String getSignature() { 
262          return super.getSignature(); 
263      } 
264   
265      /** 
266       * Obtains exceptions that this method may throw. 
267       */ 
268      public CtClass[] getExceptionTypes() throws NotFoundException { 
269          return super.getExceptionTypes(); 
270      } 
271   
272      /** 
273       * Sets exceptions that this method may throw. 
274       * 
275       * @param types     exception types (or null) 
276       */ 
277      public void setExceptionTypes(CtClass[] types) throws NotFoundException { 
278          super.setExceptionTypes(types); 
279      } 
280   
281      /** 
282       * Returns true if the method body is empty, that is, <code>{}</code>. 
283       * It also returns true if the method is an abstract method. 
284       */ 
285      public boolean isEmpty() { 
286          CodeAttribute ca = getMethodInfo2().getCodeAttribute(); 
287          if (ca == null)         // abstract or native 
288              return (getModifiers() & Modifier.ABSTRACT) != 0; 
289   
290          CodeIterator it = ca.iterator(); 
291          try { 
292              return it.hasNext() && it.byteAt(it.next()) == Opcode.RETURN 
293                      && !it.hasNext(); 
294          } catch (BadBytecode e) { 
295          } 
296          return false; 
297      } 
298   
299      /** 
300       * Sets a method body. 
301       * 
302       * @param src       the source code representing the method body. 
303       *                  It must be a single statement or block. 
304       *                  If it is <code>null</code>, the substituted method 
305       *                  body does nothing except returning zero or null. 
306       */ 
307      public void setBody(String src) throws CannotCompileException { 
308          super.setBody(src); 
309      } 
310   
311      /** 
312       * Copies a method body from another method. 
313       * If this method is abstract, the abstract modifier is removed 
314       * after the method body is copied. 
315       * 
316       * <p>All occurrences of the class names in the copied method body 
317       * are replaced with the names specified by 
318       * <code>map</code> if <code>map</code> is not <code>null</code>. 
319       * 
320       * @param src       the method that the body is copied from. 
321       * @param map       the hashtable associating original class names 
322       *                  with substituted names. 
323       *                  It can be <code>null</code>. 
324       */ 
325      public void setBody(CtMethod src, ClassMap map) 
326              throws CannotCompileException { 
327          setBody0(src.declaringClass, src.methodInfo, 
328                  declaringClass, methodInfo, map); 
329      } 
330   
331      /** 
332       * Replace a method body with a new method body wrapping the 
333       * given method. 
334       * 
335       * @param mbody             the wrapped method 
336       * @param constParam        the constant parameter given to 
337       *                          the wrapped method 
338       *                          (maybe <code>null</code>). 
339       * 
340       * @see CtNewMethod#wrapped(CtClass,String,CtClass[],CtClass[],CtMethod,CtMethod.ConstParameter,CtClass) 
341       */ 
342      public void setWrappedBody(CtMethod mbody, ConstParameter constParam) 
343              throws CannotCompileException { 
344          declaringClass.checkModify(); 
345   
346          CtClass clazz = getDeclaringClass(); 
347          CtClass[] params; 
348          CtClass retType; 
349          try { 
350              params = getParameterTypes(); 
351              retType = getReturnType(); 
352          } catch (NotFoundException e) { 
353              throw new CannotCompileException(e); 
354          } 
355   
356          Bytecode code = CtNewWrappedMethod.makeBody(clazz, 
357                  clazz.getClassFile2(), 
358                  mbody, 
359                  params, retType, 
360                  constParam); 
361          CodeAttribute cattr = code.toCodeAttribute(); 
362          methodInfo.setCodeAttribute(cattr); 
363          methodInfo.setAccessFlags(methodInfo.getAccessFlags() 
364                  & ~AccessFlag.ABSTRACT); 
365      } 
366   
367      /** 
368       * Obtains an attribute with the given name. 
369       * If that attribute is not found in the class file, this 
370       * method returns null. 
371       * 
372       * @param name              attribute name 
373       */ 
374      public byte[] getAttribute(String name) { 
375          return super.getAttribute(name); 
376      } 
377   
378      /** 
379       * Adds an attribute. The attribute is saved in the class file. 
380       * 
381       * @param name      attribute name 
382       * @param data      attribute value 
383       */ 
384      public void setAttribute(String name, byte[] data) { 
385          super.setAttribute(name, data); 
386      } 
387   
388      /** 
389       * Declares to use <code>$cflow</code> for this method. 
390       * If <code>$cflow</code> is used, the class files modified 
391       * with Javassist requires a support class 
392       * <code>javassist.runtime.Cflow</code> at runtime 
393       * (other Javassist classes are not required at runtime). 
394       * 
395       * <p>Every <code>$cflow</code> variable is given a unique name. 
396       * For example, if the given name is <code>"Point.paint"</code>, 
397       * then the variable is indicated by <code>$cflow(Point.paint)</code>. 
398       * 
399       * @param name      <code>$cflow</code> name.  It can include 
400       *                  alphabets, numbers, <code>_</code>, 
401       *                  <code>$</code>, and <code>.</code> (dot). 
402       * 
403       * @see javassist.runtime.Cflow 
404       */ 
405      public void useCflow(String name) throws CannotCompileException { 
406          super.useCflow(name); 
407      } 
408   
409      /** 
410       * Modifies the method body. 
411       * 
412       * @param converter         specifies how to modify. 
413       */ 
414      public void instrument(CodeConverter converter) 
415              throws CannotCompileException { 
416          super.instrument(converter); 
417      } 
418   
419      /** 
420       * Modifies the method body. 
421       * 
422       * @param editor            specifies how to modify. 
423       */ 
424      public void instrument(ExprEditor editor) 
425              throws CannotCompileException { 
426          super.instrument(editor); 
427      } 
428   
429      /** 
430       * Inserts bytecode at the beginning of the method body. 
431       * 
432       * @param src       the source code representing the inserted bytecode. 
433       *                  It must be a single statement or block. 
434       */ 
435      public void insertBefore(String src) throws CannotCompileException { 
436          super.insertBefore(src); 
437      } 
438   
439      /** 
440       * Inserts bytecode at the end of the method body. 
441       * The bytecode is inserted just before every return insturction. 
442       * It is not executed when an exception is thrown. 
443       * 
444       * @param src       the source code representing the inserted bytecode. 
445       *                  It must be a single statement or block. 
446       */ 
447      public void insertAfter(String src) 
448              throws CannotCompileException { 
449          super.insertAfter(src); 
450      } 
451   
452      /** 
453       * Inserts bytecode at the end of the method body. 
454       * The bytecode is inserted just before every return insturction. 
455       * 
456       * @param src       the source code representing the inserted bytecode. 
457       *                  It must be a single statement or block. 
458       * @param asFinally         true if the inserted bytecode is executed 
459       *                  not only when the transfer normally returns 
460       *                  but also when an exception is thrown. 
461       */ 
462      public void insertAfter(String src, boolean asFinally) 
463              throws CannotCompileException { 
464          super.insertAfter(src, asFinally); 
465      } 
466   
467      /** 
468       * Adds a catch clause that handles an exception thrown in the 
469       * method body. 
470       * The catch clause must end with a return or throw statement. 
471       * 
472       * @param src       the source code representing the catch clause. 
473       *                  It must be a single statement or block. 
474       * @param exceptionType     the type of the exception handled by the 
475       *                          catch clause. 
476       */ 
477      public void addCatch(String src, CtClass exceptionType) 
478              throws CannotCompileException { 
479          super.addCatch(src, exceptionType); 
480      } 
481   
482      // inner classes 
483   
484      /** 
485       * Instances of this class represent a constant parameter. 
486       * They are used to specify the parameter given to the methods 
487       * created by <code>CtNewMethod.wrapped()</code>. 
488       * 
489       * @see CtMethod#setWrappedBody(CtMethod,CtMethod.ConstParameter) 
490       * @see CtNewMethod#wrapped(CtClass,String,CtClass[],CtClass[],CtMethod,CtMethod.ConstParameter,CtClass) 
491       * @see CtNewConstructor#make(CtClass[],CtClass[],int,CtMethod,CtMethod.ConstParameter,CtClass) 
492       */ 
493      public static class ConstParameter { 
494          /** 
495           * Makes an integer constant. 
496           * 
497           * @param i             the constant value. 
498           */ 
499          public static ConstParameter integer(int i) { 
500              return new IntConstParameter(i); 
501          } 
502   
503          /** 
504           * Makes a long integer constant. 
505           * 
506           * @param i             the constant value. 
507           */ 
508          public static ConstParameter integer(long i) { 
509              return new LongConstParameter(i); 
510          } 
511   
512          /** 
513           * Makes an <code>String</code> constant. 
514           * 
515           * @param s             the constant value. 
516           */ 
517          public static ConstParameter string(String s) { 
518              return new StringConstParameter(s); 
519          } 
520   
521          ConstParameter() { 
522          } 
523   
524          /** 
525           * @return      the size of the stack consumption. 
526           */ 
527          int compile(Bytecode code) throws CannotCompileException { 
528              return 0; 
529          } 
530   
531          String descriptor() { 
532              return defaultDescriptor(); 
533          } 
534   
535          /** 
536           * @see CtNewWrappedMethod 
537           */ 
538          static String defaultDescriptor() { 
539              return "([Ljava/lang/Object;)Ljava/lang/Object;"; 
540          } 
541   
542          /** 
543           * Returns the descriptor for constructors. 
544           * 
545           * @see CtNewWrappedConstructor 
546           */ 
547          String constDescriptor() { 
548              return defaultConstDescriptor(); 
549          } 
550   
551          /** 
552           * Returns the default descriptor for constructors. 
553           */ 
554          static String defaultConstDescriptor() { 
555              return "([Ljava/lang/Object;)V"; 
556          } 
557      } 
558   
559      static class IntConstParameter extends ConstParameter { 
560          int param; 
561   
562          IntConstParameter(int i) { 
563              param = i; 
564          } 
565   
566          int compile(Bytecode code) throws CannotCompileException { 
567              code.addIconst(param); 
568              return 1; 
569          } 
570   
571          String descriptor() { 
572              return "([Ljava/lang/Object;I)Ljava/lang/Object;"; 
573          } 
574   
575          String constDescriptor() { 
576              return "([Ljava/lang/Object;I)V"; 
577          } 
578      } 
579   
580      static class LongConstParameter extends ConstParameter { 
581          long param; 
582   
583          LongConstParameter(long l) { 
584              param = l; 
585          } 
586   
587          int compile(Bytecode code) throws CannotCompileException { 
588              code.addLconst(param); 
589              return 2; 
590          } 
591   
592          String descriptor() { 
593              return "([Ljava/lang/Object;J)Ljava/lang/Object;"; 
594          } 
595   
596          String constDescriptor() { 
597              return "([Ljava/lang/Object;J)V"; 
598          } 
599      } 
600   
601      static class StringConstParameter extends ConstParameter { 
602          String param; 
603   
604          StringConstParameter(String s) { 
605              param = s; 
606          } 
607   
608          int compile(Bytecode code) throws CannotCompileException { 
609              code.addLdc(param); 
610              return 1; 
611          } 
612   
613          String descriptor() { 
614              return "([Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;"; 
615          } 
616   
617          String constDescriptor() { 
618              return "([Ljava/lang/Object;Ljava/lang/String;)V"; 
619          } 
620      } 
621  } 
622