• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Javassist, a Java-bytecode translator toolkit.
3  * Copyright (C) 1999-2007 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 
20 /**
21  * An instance of <code>CtMethod</code> represents a method.
22  *
23  * <p>See the super class <code>CtBehavior</code> since
24  * a number of useful methods are in <code>CtBehavior</code>.
25  * A number of useful factory methods are in <code>CtNewMethod</code>.
26  *
27  * @see CtClass#getDeclaredMethods()
28  * @see CtNewMethod
29  */
30 public final class CtMethod extends CtBehavior {
31     protected String cachedStringRep;
32 
33     /**
34      * @see #make(MethodInfo minfo, CtClass declaring)
35      */
CtMethod(MethodInfo minfo, CtClass declaring)36     CtMethod(MethodInfo minfo, CtClass declaring) {
37         super(declaring, minfo);
38         cachedStringRep = null;
39     }
40 
41     /**
42      * Creates a public abstract method.  The created method must be
43      * added to a class with <code>CtClass.addMethod()</code>.
44      *
45      * @param declaring         the class to which the created method is added.
46      * @param returnType        the type of the returned value
47      * @param mname             the method name
48      * @param parameters        a list of the parameter types
49      *
50      * @see CtClass#addMethod(CtMethod)
51      */
CtMethod(CtClass returnType, String mname, CtClass[] parameters, CtClass declaring)52     public CtMethod(CtClass returnType, String mname,
53                     CtClass[] parameters, CtClass declaring) {
54         this(null, declaring);
55         ConstPool cp = declaring.getClassFile2().getConstPool();
56         String desc = Descriptor.ofMethod(returnType, parameters);
57         methodInfo = new MethodInfo(cp, mname, desc);
58         setModifiers(Modifier.PUBLIC | Modifier.ABSTRACT);
59     }
60 
61     /**
62      * Creates a copy of a <code>CtMethod</code> object.
63      * The created method must be
64      * added to a class with <code>CtClass.addMethod()</code>.
65      *
66      * <p>All occurrences of class names in the created method
67      * are replaced with names specified by
68      * <code>map</code> if <code>map</code> is not <code>null</code>.
69      *
70      * <p>For example, suppose that a method <code>at()</code> is as
71      * follows:
72      *
73      * <ul><pre>public X at(int i) {
74      *     return (X)super.elementAt(i);
75      * }</pre></ul>
76      *
77      * <p>(<code>X</code> is a class name.)  If <code>map</code> substitutes
78      * <code>String</code> for <code>X</code>, then the created method is:
79      *
80      * <ul><pre>public String at(int i) {
81      *     return (String)super.elementAt(i);
82      * }</pre></ul>
83      *
84      * <p>By default, all the occurrences of the names of the class
85      * declaring <code>at()</code> and the superclass are replaced
86      * with the name of the class and the superclass that the
87      * created method is added to.
88      * This is done whichever <code>map</code> is null or not.
89      * To prevent this replacement, call <code>ClassMap.fix()</code>
90      * or <code>put()</code> to explicitly specify replacement.
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      */
CtMethod(CtMethod src, CtClass declaring, ClassMap map)109     public CtMethod(CtMethod src, CtClass declaring, ClassMap map)
110         throws CannotCompileException
111     {
112         this(null, declaring);
113         copy(src, false, map);
114     }
115 
116     /**
117      * Compiles the given source code and creates a method.
118      * This method simply delegates to <code>make()</code> in
119      * <code>CtNewMethod</code>.  See it for more details.
120      * <code>CtNewMethod</code> has a number of useful factory methods.
121      *
122      * @param src               the source text.
123      * @param declaring    the class to which the created method is added.
124      * @see CtNewMethod#make(String, CtClass)
125      */
make(String src, CtClass declaring)126     public static CtMethod make(String src, CtClass declaring)
127         throws CannotCompileException
128     {
129         return CtNewMethod.make(src, declaring);
130     }
131 
132     /**
133      * Creates a method from a <code>MethodInfo</code> object.
134      *
135      * @param declaring     the class declaring the method.
136      * @throws CannotCompileException       if the the <code>MethodInfo</code>
137      *          object and the declaring class have different
138      *          <code>ConstPool</code> objects
139      * @since 3.6
140      */
make(MethodInfo minfo, CtClass declaring)141     public static CtMethod make(MethodInfo minfo, CtClass declaring)
142         throws CannotCompileException
143     {
144         if (declaring.getClassFile2().getConstPool() != minfo.getConstPool())
145             throw new CannotCompileException("bad declaring class");
146 
147         return new CtMethod(minfo, declaring);
148     }
149 
150     /**
151      * Returns a hash code value for the method.
152      * If two methods have the same name and signature, then
153      * the hash codes for the two methods are equal.
154      */
hashCode()155     public int hashCode() {
156         return getStringRep().hashCode();
157     }
158 
159     /**
160      * This method is invoked when setName() or replaceClassName()
161      * in CtClass is called.
162      */
nameReplaced()163     void nameReplaced() {
164         cachedStringRep = null;
165     }
166 
167     /* This method is also called by CtClassType.getMethods0().
168      */
getStringRep()169     final String getStringRep() {
170         if (cachedStringRep == null)
171             cachedStringRep = methodInfo.getName()
172                 + Descriptor.getParamDescriptor(methodInfo.getDescriptor());
173 
174         return cachedStringRep;
175     }
176 
177     /**
178      * Indicates whether <code>obj</code> has the same name and the
179      * same signature as this method.
180      */
equals(Object obj)181     public boolean equals(Object obj) {
182         return obj != null && obj instanceof CtMethod
183                && ((CtMethod)obj).getStringRep().equals(getStringRep());
184     }
185 
186     /**
187      * Returns the method name followed by parameter types
188      * such as <code>javassist.CtMethod.setBody(String)</code>.
189      *
190      * @since 3.5
191      */
getLongName()192     public String getLongName() {
193         return getDeclaringClass().getName() + "."
194                + getName() + Descriptor.toString(getSignature());
195     }
196 
197     /**
198      * Obtains the name of this method.
199      */
getName()200     public String getName() {
201         return methodInfo.getName();
202     }
203 
204     /**
205      * Changes the name of this method.
206      */
setName(String newname)207     public void setName(String newname) {
208         declaringClass.checkModify();
209         methodInfo.setName(newname);
210     }
211 
212     /**
213      * Obtains the type of the returned value.
214      */
getReturnType()215     public CtClass getReturnType() throws NotFoundException {
216         return getReturnType0();
217     }
218 
219     /**
220      * Returns true if the method body is empty, that is, <code>{}</code>.
221      * It also returns true if the method is an abstract method.
222      */
isEmpty()223     public boolean isEmpty() {
224         CodeAttribute ca = getMethodInfo2().getCodeAttribute();
225         if (ca == null)         // abstract or native
226             return (getModifiers() & Modifier.ABSTRACT) != 0;
227 
228         CodeIterator it = ca.iterator();
229         try {
230             return it.hasNext() && it.byteAt(it.next()) == Opcode.RETURN
231                 && !it.hasNext();
232         }
233         catch (BadBytecode e) {}
234         return false;
235     }
236 
237     /**
238      * Copies a method body from another method.
239      * If this method is abstract, the abstract modifier is removed
240      * after the method body is copied.
241      *
242      * <p>All occurrences of the class names in the copied method body
243      * are replaced with the names specified by
244      * <code>map</code> if <code>map</code> is not <code>null</code>.
245      *
246      * @param src       the method that the body is copied from.
247      * @param map       the hashtable associating original class names
248      *                  with substituted names.
249      *                  It can be <code>null</code>.
250      */
setBody(CtMethod src, ClassMap map)251     public void setBody(CtMethod src, ClassMap map)
252         throws CannotCompileException
253     {
254         setBody0(src.declaringClass, src.methodInfo,
255                  declaringClass, methodInfo, map);
256     }
257 
258     /**
259      * Replace a method body with a new method body wrapping the
260      * given method.
261      *
262      * @param mbody             the wrapped method
263      * @param constParam        the constant parameter given to
264      *                          the wrapped method
265      *                          (maybe <code>null</code>).
266      *
267      * @see CtNewMethod#wrapped(CtClass,String,CtClass[],CtClass[],CtMethod,CtMethod.ConstParameter,CtClass)
268      */
setWrappedBody(CtMethod mbody, ConstParameter constParam)269     public void setWrappedBody(CtMethod mbody, ConstParameter constParam)
270         throws CannotCompileException
271     {
272         declaringClass.checkModify();
273 
274         CtClass clazz = getDeclaringClass();
275         CtClass[] params;
276         CtClass retType;
277         try {
278             params = getParameterTypes();
279             retType = getReturnType();
280         }
281         catch (NotFoundException e) {
282             throw new CannotCompileException(e);
283         }
284 
285         Bytecode code = CtNewWrappedMethod.makeBody(clazz,
286                                                     clazz.getClassFile2(),
287                                                     mbody,
288                                                     params, retType,
289                                                     constParam);
290         CodeAttribute cattr = code.toCodeAttribute();
291         methodInfo.setCodeAttribute(cattr);
292         methodInfo.setAccessFlags(methodInfo.getAccessFlags()
293                                   & ~AccessFlag.ABSTRACT);
294         // rebuilding a stack map table is not needed.
295     }
296 
297     // inner classes
298 
299     /**
300      * Instances of this class represent a constant parameter.
301      * They are used to specify the parameter given to the methods
302      * created by <code>CtNewMethod.wrapped()</code>.
303      *
304      * @see CtMethod#setWrappedBody(CtMethod,CtMethod.ConstParameter)
305      * @see CtNewMethod#wrapped(CtClass,String,CtClass[],CtClass[],CtMethod,CtMethod.ConstParameter,CtClass)
306      * @see CtNewConstructor#make(CtClass[],CtClass[],int,CtMethod,CtMethod.ConstParameter,CtClass)
307      */
308     public static class ConstParameter {
309         /**
310          * Makes an integer constant.
311          *
312          * @param i             the constant value.
313          */
integer(int i)314         public static ConstParameter integer(int i) {
315             return new IntConstParameter(i);
316         }
317 
318         /**
319          * Makes a long integer constant.
320          *
321          * @param i             the constant value.
322          */
integer(long i)323         public static ConstParameter integer(long i) {
324             return new LongConstParameter(i);
325         }
326 
327         /**
328          * Makes an <code>String</code> constant.
329          *
330          * @param s             the constant value.
331          */
string(String s)332         public static ConstParameter string(String s) {
333             return new StringConstParameter(s);
334         }
335 
ConstParameter()336         ConstParameter() {}
337 
338         /**
339          * @return      the size of the stack consumption.
340          */
compile(Bytecode code)341         int compile(Bytecode code) throws CannotCompileException {
342             return 0;
343         }
344 
descriptor()345         String descriptor() {
346             return defaultDescriptor();
347         }
348 
349         /**
350          * @see CtNewWrappedMethod
351          */
defaultDescriptor()352         static String defaultDescriptor() {
353             return "([Ljava/lang/Object;)Ljava/lang/Object;";
354         }
355 
356         /**
357          * Returns the descriptor for constructors.
358          *
359          * @see CtNewWrappedConstructor
360          */
constDescriptor()361         String constDescriptor() {
362             return defaultConstDescriptor();
363         }
364 
365         /**
366          * Returns the default descriptor for constructors.
367          */
defaultConstDescriptor()368         static String defaultConstDescriptor() {
369             return "([Ljava/lang/Object;)V";
370         }
371     }
372 
373     static class IntConstParameter extends ConstParameter {
374         int param;
375 
IntConstParameter(int i)376         IntConstParameter(int i) {
377             param = i;
378         }
379 
compile(Bytecode code)380         int compile(Bytecode code) throws CannotCompileException {
381             code.addIconst(param);
382             return 1;
383         }
384 
descriptor()385         String descriptor() {
386             return "([Ljava/lang/Object;I)Ljava/lang/Object;";
387         }
388 
constDescriptor()389         String constDescriptor() {
390             return "([Ljava/lang/Object;I)V";
391         }
392     }
393 
394     static class LongConstParameter extends ConstParameter {
395         long param;
396 
LongConstParameter(long l)397         LongConstParameter(long l) {
398             param = l;
399         }
400 
compile(Bytecode code)401         int compile(Bytecode code) throws CannotCompileException {
402             code.addLconst(param);
403             return 2;
404         }
405 
descriptor()406         String descriptor() {
407             return "([Ljava/lang/Object;J)Ljava/lang/Object;";
408         }
409 
constDescriptor()410         String constDescriptor() {
411             return "([Ljava/lang/Object;J)V";
412         }
413     }
414 
415     static class StringConstParameter extends ConstParameter {
416         String param;
417 
StringConstParameter(String s)418         StringConstParameter(String s) {
419             param = s;
420         }
421 
compile(Bytecode code)422         int compile(Bytecode code) throws CannotCompileException {
423             code.addLdc(param);
424             return 1;
425         }
426 
descriptor()427         String descriptor() {
428             return "([Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;";
429         }
430 
constDescriptor()431         String constDescriptor() {
432             return "([Ljava/lang/Object;Ljava/lang/String;)V";
433         }
434     }
435 }
436