/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