001: /*
002: * Javassist, a Java-bytecode translator toolkit.
003: * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
004: *
005: * The contents of this file are subject to the Mozilla Public License Version
006: * 1.1 (the "License"); you may not use this file except in compliance with
007: * the License. Alternatively, the contents of this file may be used under
008: * the terms of the GNU Lesser General Public License Version 2.1 or later.
009: *
010: * Software distributed under the License is distributed on an "AS IS" basis,
011: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
012: * for the specific language governing rights and limitations under the
013: * License.
014: */
015:
016: package javassist;
017:
018: import javassist.bytecode.*;
019:
020: /**
021: * An instance of <code>CtMethod</code> represents a method.
022: *
023: * <p>See the super class <code>CtBehavior</code> since
024: * a number of useful methods are in <code>CtBehavior</code>.
025: * A number of useful factory methods are in <code>CtNewMethod</code>.
026: *
027: * @see CtClass#getDeclaredMethods()
028: * @see CtNewMethod
029: */
030: public final class CtMethod extends CtBehavior {
031: protected String cachedStringRep;
032:
033: CtMethod(MethodInfo minfo, CtClass declaring) {
034: super (declaring, minfo);
035: next = null;
036: cachedStringRep = null;
037: }
038:
039: /**
040: * Creates a public abstract method. The created method must be
041: * added to a class with <code>CtClass.addMethod()</code>.
042: *
043: * @param declaring the class to which the created method is added.
044: * @param returnType the type of the returned value
045: * @param mname the method name
046: * @param parameters a list of the parameter types
047: *
048: * @see CtClass#addMethod(CtMethod)
049: */
050: public CtMethod(CtClass returnType, String mname,
051: CtClass[] parameters, CtClass declaring) {
052: this (null, declaring);
053: ConstPool cp = declaring.getClassFile2().getConstPool();
054: String desc = Descriptor.ofMethod(returnType, parameters);
055: methodInfo = new MethodInfo(cp, mname, desc);
056: setModifiers(Modifier.PUBLIC | Modifier.ABSTRACT);
057: }
058:
059: /**
060: * Creates a copy of a <code>CtMethod</code> object.
061: * The created method must be
062: * added to a class with <code>CtClass.addMethod()</code>.
063: *
064: * <p>All occurrences of class names in the created method
065: * are replaced with names specified by
066: * <code>map</code> if <code>map</code> is not <code>null</code>.
067: *
068: * <p>For example, suppose that a method <code>at()</code> is as
069: * follows:
070: *
071: * <ul><pre>public X at(int i) {
072: * return (X)super.elementAt(i);
073: * }</pre></ul>
074: *
075: * <p>(<code>X</code> is a class name.) If <code>map</code> substitutes
076: * <code>String</code> for <code>X</code>, then the created method is:
077: *
078: * <ul><pre>public String at(int i) {
079: * return (String)super.elementAt(i);
080: * }</pre></ul>
081: *
082: * <p>By default, all the occurrences of the names of the class
083: * declaring <code>at()</code> and the superclass are replaced
084: * with the name of the class and the superclass that the
085: * created method is added to.
086: * This is done whichever <code>map</code> is null or not.
087: * To prevent this replacement, call <code>ClassMap.fix()</code>.
088: *
089: * <p><b>Note:</b> if the <code>.class</code> notation (for example,
090: * <code>String.class</code>) is included in an expression, the
091: * Javac compiler may produce a helper method.
092: * Since this constructor never
093: * copies this helper method, the programmers have the responsiblity of
094: * copying it. Otherwise, use <code>Class.forName()</code> in the
095: * expression.
096: *
097: * @param src the source method.
098: * @param declaring the class to which the created method is added.
099: * @param map the hashtable associating original class names
100: * with substituted names.
101: * It can be <code>null</code>.
102: *
103: * @see CtClass#addMethod(CtMethod)
104: * @see ClassMap#fix(String)
105: */
106: public CtMethod(CtMethod src, CtClass declaring, ClassMap map)
107: throws CannotCompileException {
108: this (null, declaring);
109: copy(src, false, map);
110: }
111:
112: /**
113: * Compiles the given source code and creates a method.
114: * This method simply delegates to <code>make()</code> in
115: * <code>CtNewMethod</code>. See it for more details.
116: * <code>CtNewMethod</code> has a number of useful factory methods.
117: *
118: * @param src the source text.
119: * @param declaring the class to which the created method is added.
120: * @see CtNewMethod#make(String, CtClass)
121: */
122: public static CtMethod make(String src, CtClass declaring)
123: throws CannotCompileException {
124: return CtNewMethod.make(src, declaring);
125: }
126:
127: /**
128: * Returns a hash code value for the method.
129: * If two methods have the same name and signature, then
130: * the hash codes for the two methods are equal.
131: */
132: public int hashCode() {
133: return getStringRep().hashCode();
134: }
135:
136: /* This method is also called by CtClassType.getMethods0().
137: */
138: final String getStringRep() {
139: if (cachedStringRep == null)
140: cachedStringRep = methodInfo.getName()
141: + Descriptor.getParamDescriptor(methodInfo
142: .getDescriptor());
143:
144: return cachedStringRep;
145: }
146:
147: /**
148: * Indicates whether <code>obj</code> has the same name and the
149: * same signature as this method.
150: */
151: public boolean equals(Object obj) {
152: return obj != null
153: && obj instanceof CtMethod
154: && ((CtMethod) obj).getStringRep().equals(
155: getStringRep());
156: }
157:
158: /**
159: * Obtains the name of this method.
160: */
161: public String getName() {
162: return methodInfo.getName();
163: }
164:
165: /**
166: * Changes the name of this method.
167: */
168: public void setName(String newname) {
169: declaringClass.checkModify();
170: methodInfo.setName(newname);
171: }
172:
173: /**
174: * Obtains the type of the returned value.
175: */
176: public CtClass getReturnType() throws NotFoundException {
177: return getReturnType0();
178: }
179:
180: /**
181: * Returns true if the method body is empty, that is, <code>{}</code>.
182: * It also returns true if the method is an abstract method.
183: */
184: public boolean isEmpty() {
185: CodeAttribute ca = getMethodInfo2().getCodeAttribute();
186: if (ca == null) // abstract or native
187: return (getModifiers() & Modifier.ABSTRACT) != 0;
188:
189: CodeIterator it = ca.iterator();
190: try {
191: return it.hasNext()
192: && it.byteAt(it.next()) == Opcode.RETURN
193: && !it.hasNext();
194: } catch (BadBytecode e) {
195: }
196: return false;
197: }
198:
199: /**
200: * Copies a method body from another method.
201: * If this method is abstract, the abstract modifier is removed
202: * after the method body is copied.
203: *
204: * <p>All occurrences of the class names in the copied method body
205: * are replaced with the names specified by
206: * <code>map</code> if <code>map</code> is not <code>null</code>.
207: *
208: * @param src the method that the body is copied from.
209: * @param map the hashtable associating original class names
210: * with substituted names.
211: * It can be <code>null</code>.
212: */
213: public void setBody(CtMethod src, ClassMap map)
214: throws CannotCompileException {
215: setBody0(src.declaringClass, src.methodInfo, declaringClass,
216: methodInfo, map);
217: }
218:
219: /**
220: * Replace a method body with a new method body wrapping the
221: * given method.
222: *
223: * @param mbody the wrapped method
224: * @param constParam the constant parameter given to
225: * the wrapped method
226: * (maybe <code>null</code>).
227: *
228: * @see CtNewMethod#wrapped(CtClass,String,CtClass[],CtClass[],CtMethod,CtMethod.ConstParameter,CtClass)
229: */
230: public void setWrappedBody(CtMethod mbody, ConstParameter constParam)
231: throws CannotCompileException {
232: declaringClass.checkModify();
233:
234: CtClass clazz = getDeclaringClass();
235: CtClass[] params;
236: CtClass retType;
237: try {
238: params = getParameterTypes();
239: retType = getReturnType();
240: } catch (NotFoundException e) {
241: throw new CannotCompileException(e);
242: }
243:
244: Bytecode code = CtNewWrappedMethod.makeBody(clazz, clazz
245: .getClassFile2(), mbody, params, retType, constParam);
246: CodeAttribute cattr = code.toCodeAttribute();
247: methodInfo.setCodeAttribute(cattr);
248: methodInfo.setAccessFlags(methodInfo.getAccessFlags()
249: & ~AccessFlag.ABSTRACT);
250: }
251:
252: // inner classes
253:
254: /**
255: * Instances of this class represent a constant parameter.
256: * They are used to specify the parameter given to the methods
257: * created by <code>CtNewMethod.wrapped()</code>.
258: *
259: * @see CtMethod#setWrappedBody(CtMethod,CtMethod.ConstParameter)
260: * @see CtNewMethod#wrapped(CtClass,String,CtClass[],CtClass[],CtMethod,CtMethod.ConstParameter,CtClass)
261: * @see CtNewConstructor#make(CtClass[],CtClass[],int,CtMethod,CtMethod.ConstParameter,CtClass)
262: */
263: public static class ConstParameter {
264: /**
265: * Makes an integer constant.
266: *
267: * @param i the constant value.
268: */
269: public static ConstParameter integer(int i) {
270: return new IntConstParameter(i);
271: }
272:
273: /**
274: * Makes a long integer constant.
275: *
276: * @param i the constant value.
277: */
278: public static ConstParameter integer(long i) {
279: return new LongConstParameter(i);
280: }
281:
282: /**
283: * Makes an <code>String</code> constant.
284: *
285: * @param s the constant value.
286: */
287: public static ConstParameter string(String s) {
288: return new StringConstParameter(s);
289: }
290:
291: ConstParameter() {
292: }
293:
294: /**
295: * @return the size of the stack consumption.
296: */
297: int compile(Bytecode code) throws CannotCompileException {
298: return 0;
299: }
300:
301: String descriptor() {
302: return defaultDescriptor();
303: }
304:
305: /**
306: * @see CtNewWrappedMethod
307: */
308: static String defaultDescriptor() {
309: return "([Ljava/lang/Object;)Ljava/lang/Object;";
310: }
311:
312: /**
313: * Returns the descriptor for constructors.
314: *
315: * @see CtNewWrappedConstructor
316: */
317: String constDescriptor() {
318: return defaultConstDescriptor();
319: }
320:
321: /**
322: * Returns the default descriptor for constructors.
323: */
324: static String defaultConstDescriptor() {
325: return "([Ljava/lang/Object;)V";
326: }
327: }
328:
329: static class IntConstParameter extends ConstParameter {
330: int param;
331:
332: IntConstParameter(int i) {
333: param = i;
334: }
335:
336: int compile(Bytecode code) throws CannotCompileException {
337: code.addIconst(param);
338: return 1;
339: }
340:
341: String descriptor() {
342: return "([Ljava/lang/Object;I)Ljava/lang/Object;";
343: }
344:
345: String constDescriptor() {
346: return "([Ljava/lang/Object;I)V";
347: }
348: }
349:
350: static class LongConstParameter extends ConstParameter {
351: long param;
352:
353: LongConstParameter(long l) {
354: param = l;
355: }
356:
357: int compile(Bytecode code) throws CannotCompileException {
358: code.addLconst(param);
359: return 2;
360: }
361:
362: String descriptor() {
363: return "([Ljava/lang/Object;J)Ljava/lang/Object;";
364: }
365:
366: String constDescriptor() {
367: return "([Ljava/lang/Object;J)V";
368: }
369: }
370:
371: static class StringConstParameter extends ConstParameter {
372: String param;
373:
374: StringConstParameter(String s) {
375: param = s;
376: }
377:
378: int compile(Bytecode code) throws CannotCompileException {
379: code.addLdc(param);
380: return 1;
381: }
382:
383: String descriptor() {
384: return "([Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;";
385: }
386:
387: String constDescriptor() {
388: return "([Ljava/lang/Object;Ljava/lang/String;)V";
389: }
390: }
391: }
|