KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > javassist > CtNewMethod


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

15
16 package javassist;
17
18 import javassist.bytecode.*;
19 import javassist.compiler.Javac;
20 import javassist.compiler.CompileError;
21 import javassist.CtMethod.ConstParameter;
22
23 /**
24  * A collection of static methods for creating a <code>CtMethod</code>.
25  * An instance of this class does not make any sense.
26  *
27  * @see CtClass#addMethod(CtMethod)
28  */

29 public class CtNewMethod {
30
31     /**
32      * Compiles the given source code and creates a method.
33      * The source code must include not only the method body
34      * but the whole declaration, for example,
35      *
36      * <ul><pre>"public Object id(Object obj) { return obj; }"</pre></ul>
37      *
38      * @param src the source text.
39      * @param declaring the class to which the created method is added.
40      */

41     public static CtMethod make(String JavaDoc src, CtClass declaring)
42         throws CannotCompileException
43     {
44         return make(src, declaring, null, null);
45     }
46
47     /**
48      * Compiles the given source code and creates a method.
49      * The source code must include not only the method body
50      * but the whole declaration, for example,
51      *
52      * <ul><pre>"public Object id(Object obj) { return obj; }"</pre></ul>
53      *
54      * <p>If the source code includes <code>$proceed()</code>, then
55      * it is compiled into a method call on the specified object.
56      *
57      * @param src the source text.
58      * @param declaring the class to which the created method is added.
59      * @param delegateObj the source text specifying the object
60      * that is called on by <code>$proceed()</code>.
61      * @param delegateMethod the name of the method
62      * that is called by <code>$proceed()</code>.
63      */

64     public static CtMethod make(String JavaDoc src, CtClass declaring,
65                                 String JavaDoc delegateObj, String JavaDoc delegateMethod)
66         throws CannotCompileException
67     {
68         Javac compiler = new Javac(declaring);
69         try {
70             if (delegateMethod != null)
71                 compiler.recordProceed(delegateObj, delegateMethod);
72
73             CtMember obj = compiler.compile(src);
74             if (obj instanceof CtMethod)
75                 return (CtMethod)obj;
76         }
77         catch (CompileError e) {
78             throw new CannotCompileException(e);
79         }
80
81         throw new CannotCompileException("not a method");
82     }
83
84     /**
85      * Creates a public (non-static) method. The created method cannot
86      * be changed to a static method later.
87      *
88      * @param returnType the type of the returned value.
89      * @param mname the method name.
90      * @param parameters a list of the parameter types.
91      * @param exceptions a list of the exception types.
92      * @param body the source text of the method body.
93      * It must be a block surrounded by <code>{}</code>.
94      * If it is <code>null</code>, the created method
95      * does nothing except returning zero or null.
96      * @param declaring the class to which the created method is added.
97      */

98     public static CtMethod make(CtClass returnType,
99                                 String JavaDoc mname, CtClass[] parameters,
100                                 CtClass[] exceptions,
101                                 String JavaDoc body, CtClass declaring)
102         throws CannotCompileException
103     {
104         return make(Modifier.PUBLIC, returnType, mname, parameters, exceptions,
105                     body, declaring);
106     }
107
108     /**
109      * Creates a method.
110      *
111      * @param modifiers access modifiers.
112      * @param returnType the type of the returned value.
113      * @param mname the method name.
114      * @param parameters a list of the parameter types.
115      * @param exceptions a list of the exception types.
116      * @param body the source text of the method body.
117      * It must be a block surrounded by <code>{}</code>.
118      * If it is <code>null</code>, the created method
119      * does nothing except returning zero or null.
120      * @param declaring the class to which the created method is added.
121      *
122      * @see Modifier
123      */

124     public static CtMethod make(int modifiers, CtClass returnType,
125                                 String JavaDoc mname, CtClass[] parameters,
126                                 CtClass[] exceptions,
127                                 String JavaDoc body, CtClass declaring)
128         throws CannotCompileException
129     {
130         try {
131             CtMethod cm
132                 = new CtMethod(returnType, mname, parameters, declaring);
133             cm.setModifiers(modifiers);
134             cm.setExceptionTypes(exceptions);
135             cm.setBody(body);
136             return cm;
137         }
138         catch (NotFoundException e) {
139             throw new CannotCompileException(e);
140         }
141     }
142
143     /**
144      * Creates a copy of a method. This method is provided for creating
145      * a new method based on an existing method.
146      *
147      * @param src the source method.
148      * @param declaring the class to which the created method is added.
149      * @param map the hashtable associating original class names
150      * with substituted names.
151      * It can be <code>null</code>.
152      *
153      * @see CtMethod#CtMethod(CtMethod,CtClass,ClassMap)
154      */

155     public static CtMethod copy(CtMethod src, CtClass declaring,
156                                 ClassMap map) throws CannotCompileException {
157         return new CtMethod(src, declaring, map);
158     }
159
160     /**
161      * Creates a copy of a method with a new name.
162      * This method is provided for creating
163      * a new method based on an existing method.
164      *
165      * @param src the source method.
166      * @param name the name of the created method.
167      * @param declaring the class to which the created method is added.
168      * @param map the hashtable associating original class names
169      * with substituted names.
170      * It can be <code>null</code>.
171      *
172      * @see CtMethod#CtMethod(CtMethod,CtClass,ClassMap)
173      */

174     public static CtMethod copy(CtMethod src, String JavaDoc name, CtClass declaring,
175                                 ClassMap map) throws CannotCompileException {
176         CtMethod cm = new CtMethod(src, declaring, map);
177         cm.setName(name);
178         return cm;
179     }
180
181     /**
182      * Creates a public abstract method.
183      *
184      * @param returnType the type of the returned value
185      * @param mname the method name
186      * @param parameters a list of the parameter types
187      * @param exceptions a list of the exception types
188      * @param declaring the class to which the created method is added.
189      *
190      * @see CtMethod#CtMethod(CtClass,String,CtClass[],CtClass)
191      */

192     public static CtMethod abstractMethod(CtClass returnType,
193                                           String JavaDoc mname,
194                                           CtClass[] parameters,
195                                           CtClass[] exceptions,
196                                           CtClass declaring)
197         throws NotFoundException
198     {
199         CtMethod cm = new CtMethod(returnType, mname, parameters, declaring);
200         cm.setExceptionTypes(exceptions);
201         return cm;
202     }
203
204     /**
205      * Creates a public getter method. The getter method returns the value
206      * of the specified field in the class to which this method is added.
207      * The created method is initially not static even if the field is
208      * static. Change the modifiers if the method should be static.
209      *
210      * @param methodName the name of the getter
211      * @param field the field accessed.
212      */

213     public static CtMethod getter(String JavaDoc methodName, CtField field)
214         throws CannotCompileException
215     {
216         FieldInfo finfo = field.getFieldInfo2();
217         String JavaDoc fieldType = finfo.getDescriptor();
218         String JavaDoc desc = "()" + fieldType;
219         ConstPool cp = finfo.getConstPool();
220         MethodInfo minfo = new MethodInfo(cp, methodName, desc);
221         minfo.setAccessFlags(AccessFlag.PUBLIC);
222
223         Bytecode code = new Bytecode(cp, 2, 1);
224         try {
225             String JavaDoc fieldName = finfo.getName();
226             if ((finfo.getAccessFlags() & AccessFlag.STATIC) == 0) {
227                 code.addAload(0);
228                 code.addGetfield(Bytecode.THIS, fieldName, fieldType);
229             }
230             else
231                 code.addGetstatic(Bytecode.THIS, fieldName, fieldType);
232
233             code.addReturn(field.getType());
234         }
235         catch (NotFoundException e) {
236             throw new CannotCompileException(e);
237         }
238
239         minfo.setCodeAttribute(code.toCodeAttribute());
240         return new CtMethod(minfo, field.getDeclaringClass());
241     }
242
243     /**
244      * Creates a public setter method. The setter method assigns the
245      * value of the first parameter to the specified field
246      * in the class to which this method is added.
247      * The created method is not static even if the field is
248      * static. You may not change it to be static
249      * by <code>setModifiers()</code> in <code>CtBehavior</code>.
250      *
251      * @param methodName the name of the setter
252      * @param field the field accessed.
253      */

254     public static CtMethod setter(String JavaDoc methodName, CtField field)
255         throws CannotCompileException
256     {
257         FieldInfo finfo = field.getFieldInfo2();
258         String JavaDoc fieldType = finfo.getDescriptor();
259         String JavaDoc desc = "(" + fieldType + ")V";
260         ConstPool cp = finfo.getConstPool();
261         MethodInfo minfo = new MethodInfo(cp, methodName, desc);
262         minfo.setAccessFlags(AccessFlag.PUBLIC);
263
264         Bytecode code = new Bytecode(cp, 3, 3);
265         try {
266             String JavaDoc fieldName = finfo.getName();
267             if ((finfo.getAccessFlags() & AccessFlag.STATIC) == 0) {
268                 code.addAload(0);
269                 code.addLoad(1, field.getType());
270                 code.addPutfield(Bytecode.THIS, fieldName, fieldType);
271             }
272             else {
273                 code.addLoad(1, field.getType());
274                 code.addPutstatic(Bytecode.THIS, fieldName, fieldType);
275             }
276
277             code.addReturn(null);
278         }
279         catch (NotFoundException e) {
280             throw new CannotCompileException(e);
281         }
282
283         minfo.setCodeAttribute(code.toCodeAttribute());
284         return new CtMethod(minfo, field.getDeclaringClass());
285     }
286
287     /**
288      * Creates a method forwarding to a delegate in
289      * a super class. The created method calls a method specified
290      * by <code>delegate</code> with all the parameters passed to the
291      * created method. If the delegate method returns a value,
292      * the created method returns that value to the caller.
293      * The delegate method must be declared in a super class.
294      *
295      * <p>The following method is an example of the created method.
296      *
297      * <ul><pre>int f(int p, int q) {
298      * return super.f(p, q);
299      * }</pre></ul>
300      *
301      * <p>The name of the created method can be changed by
302      * <code>setName()</code>.
303      *
304      * @param delegate the method that the created method forwards to.
305      * @param declaring the class to which the created method is
306      * added.
307      */

308     public static CtMethod delegator(CtMethod delegate, CtClass declaring)
309         throws CannotCompileException
310     {
311         try {
312             return delegator0(delegate, declaring);
313         }
314         catch (NotFoundException e) {
315             throw new CannotCompileException(e);
316         }
317     }
318
319     private static CtMethod delegator0(CtMethod delegate, CtClass declaring)
320         throws CannotCompileException, NotFoundException
321     {
322         MethodInfo deleInfo = delegate.getMethodInfo2();
323         String JavaDoc methodName = deleInfo.getName();
324         String JavaDoc desc = deleInfo.getDescriptor();
325         ConstPool cp = declaring.getClassFile2().getConstPool();
326         MethodInfo minfo = new MethodInfo(cp, methodName, desc);
327         minfo.setAccessFlags(deleInfo.getAccessFlags());
328
329         ExceptionsAttribute eattr = deleInfo.getExceptionsAttribute();
330         if (eattr != null)
331             minfo.setExceptionsAttribute(
332                                 (ExceptionsAttribute)eattr.copy(cp, null));
333
334         Bytecode code = new Bytecode(cp, 0, 0);
335         boolean isStatic = Modifier.isStatic(delegate.getModifiers());
336         CtClass deleClass = delegate.getDeclaringClass();
337         CtClass[] params = delegate.getParameterTypes();
338         int s;
339         if (isStatic) {
340             s = code.addLoadParameters(params, 0);
341             code.addInvokestatic(deleClass, methodName, desc);
342         }
343         else {
344             code.addLoad(0, deleClass);
345             s = code.addLoadParameters(params, 1);
346             code.addInvokespecial(deleClass, methodName, desc);
347         }
348
349         code.addReturn(delegate.getReturnType());
350         code.setMaxLocals(++s);
351         code.setMaxStack(s < 2 ? 2 : s); // for a 2-word return value
352
minfo.setCodeAttribute(code.toCodeAttribute());
353         return new CtMethod(minfo, declaring);
354     }
355
356     /**
357      * Creates a wrapped method. The wrapped method receives parameters
358      * in the form of an array of <code>Object</code>.
359      *
360      * <p>The body of the created method is a copy of the body of a method
361      * specified by <code>body</code>. However, it is wrapped in
362      * parameter-conversion code.
363      *
364      * <p>The method specified by <code>body</code> must have this singature:
365      *
366      * <ul><code>Object method(Object[] params, &lt;type&gt; cvalue)
367      * </code></ul>
368      *
369      * <p>The type of the <code>cvalue</code> depends on
370      * <code>constParam</code>.
371      * If <code>constParam</code> is <code>null</code>, the signature
372      * must be:
373      *
374      * <ul><code>Object method(Object[] params)</code></ul>
375      *
376      * <p>The method body copied from <code>body</code> is wrapped in
377      * parameter-conversion code, which converts parameters specified by
378      * <code>parameterTypes</code> into an array of <code>Object</code>.
379      * The returned value is also converted from the <code>Object</code>
380      * type to the type specified by <code>returnType</code>. Thus,
381      * the resulting method body is as follows:
382      *
383      * <ul><pre>Object[] params = new Object[] { p0, p1, ... };
384      * &lt;<i>type</i>&gt; cvalue = &lt;<i>constant-value</i>&gt;;
385      * <i>... copied method body ...</i>
386      * Object result = &lt;<i>returned value</i>&gt;
387      * return (<i>&lt;returnType&gt;</i>)result;
388      * </pre></ul>
389      *
390      * <p>The variables <code>p0</code>, <code>p2</code>, ... represent
391      * formal parameters of the created method.
392      * The value of <code>cvalue</code> is specified by
393      * <code>constParam</code>.
394      *
395      * <p>If the type of a parameter or a returned value is a primitive
396      * type, then the value is converted into a wrapper object such as
397      * <code>java.lang.Integer</code>. If the type of the returned value
398      * is <code>void</code>, the returned value is discarded.
399      *
400      * <p><i>Example:</i>
401      *
402      * <ul><pre>ClassPool pool = ... ;
403      * CtClass vec = pool.makeClass("intVector");
404      * vec.setSuperclass(pool.get("java.util.Vector"));
405      * CtMethod addMethod = pool.getMethod("Sample", "add0");
406      *
407      * CtClass[] argTypes = { CtClass.intType };
408      * CtMethod m = CtNewMethod.wrapped(CtClass.voidType, "add", argTypes,
409      * null, addMethod, null, vec);
410      * vec.addMethod(m);</pre></ul>
411      *
412      * <p>where the class <code>Sample</code> is as follows:
413      *
414      * <ul><pre>public class Sample extends java.util.Vector {
415      * public Object add0(Object[] args) {
416      * super.addElement(args[0]);
417      * return null;
418      * }
419      * }</pre></ul>
420      *
421      * <p>This program produces a class <code>intVector</code>:
422      *
423      * <ul><pre>public class intVector extends java.util.Vector {
424      * public void add(int p0) {
425      * Object[] args = new Object[] { p0 };
426      * // begin of copied body
427      * super.addElement(args[0]);
428      * Object result = null;
429      * // end
430      * }
431      * }</pre></ul>
432      *
433      * <p>Note that the type of the parameter to <code>add()</code> depends
434      * only on the value of <code>argTypes</code> passed to
435      * <code>CtNewMethod.wrapped()</code>. Thus, it is easy to
436      * modify this program to produce a
437      * <code>StringVector</code> class, which is a vector containing
438      * only <code>String</code> objects, and other vector classes.
439      *
440      * @param returnType the type of the returned value.
441      * @param mname the method name.
442      * @param parameterTypes a list of the parameter types.
443      * @param exceptionTypes a list of the exception types.
444      * @param body the method body
445      * (must not be a static method).
446      * @param constParam the constant parameter
447      * (maybe <code>null</code>).
448      * @param declaring the class to which the created method is
449      * added.
450      */

451     public static CtMethod wrapped(CtClass returnType,
452                                    String JavaDoc mname,
453                                    CtClass[] parameterTypes,
454                                    CtClass[] exceptionTypes,
455                                    CtMethod body, ConstParameter constParam,
456                                    CtClass declaring)
457         throws CannotCompileException
458     {
459         return CtNewWrappedMethod.wrapped(returnType, mname, parameterTypes,
460                         exceptionTypes, body, constParam, declaring);
461     }
462 }
463
Popular Tags