/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. Alternatively, the contents of this file may be used under
* the terms of the GNU Lesser General Public License Version 2.1 or later,
* or the Apache License Version 2.0.
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*/
package javassist;
import javassist.bytecode.AccessFlag;
import javassist.bytecode.BadBytecode;
import javassist.bytecode.Bytecode;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.CodeIterator;
import javassist.bytecode.ConstPool;
import javassist.bytecode.Descriptor;
import javassist.bytecode.MethodInfo;
import javassist.bytecode.Opcode;
An instance of CtMethod
represents a method.
See the super class CtBehavior
since
a number of useful methods are in CtBehavior
.
A number of useful factory methods are in CtNewMethod
.
See Also: - getDeclaredMethods.getDeclaredMethods()
- CtNewMethod
/**
* An instance of <code>CtMethod</code> represents a method.
*
* <p>See the super class <code>CtBehavior</code> since
* a number of useful methods are in <code>CtBehavior</code>.
* A number of useful factory methods are in <code>CtNewMethod</code>.
*
* @see CtClass#getDeclaredMethods()
* @see CtNewMethod
*/
public final class CtMethod extends CtBehavior {
protected String cachedStringRep;
See Also: - make(MethodInfo minfo, CtClass declaring)
/**
* @see #make(MethodInfo minfo, CtClass declaring)
*/
CtMethod(MethodInfo minfo, CtClass declaring) {
super(declaring, minfo);
cachedStringRep = null;
}
Creates a public abstract method. The created method must be
added to a class with CtClass.addMethod()
.
Params: - declaring – the class to which the created method is added.
- returnType – the type of the returned value
- mname – the method name
- parameters – a list of the parameter types
See Also:
/**
* Creates a public abstract method. The created method must be
* added to a class with <code>CtClass.addMethod()</code>.
*
* @param declaring the class to which the created method is added.
* @param returnType the type of the returned value
* @param mname the method name
* @param parameters a list of the parameter types
*
* @see CtClass#addMethod(CtMethod)
*/
public CtMethod(CtClass returnType, String mname,
CtClass[] parameters, CtClass declaring) {
this(null, declaring);
ConstPool cp = declaring.getClassFile2().getConstPool();
String desc = Descriptor.ofMethod(returnType, parameters);
methodInfo = new MethodInfo(cp, mname, desc);
setModifiers(Modifier.PUBLIC | Modifier.ABSTRACT);
}
Creates a copy of a CtMethod
object.
The created method must be
added to a class with CtClass.addMethod()
.
All occurrences of class names in the created method
are replaced with names specified by
map
if map
is not null
.
For example, suppose that a method at()
is as
follows:
public X at(int i) {
return (X)super.elementAt(i);
}
(X
is a class name.) If map
substitutes
String
for X
, then the created method is:
public String at(int i) {
return (String)super.elementAt(i);
}
By default, all the occurrences of the names of the class
declaring at()
and the superclass are replaced
with the name of the class and the superclass that the
created method is added to.
This is done whichever map
is null or not.
To prevent this replacement, call ClassMap.fix()
or put()
to explicitly specify replacement.
Note: if the .class
notation (for example,
String.class
) is included in an expression, the
Javac compiler may produce a helper method.
Since this constructor never
copies this helper method, the programmers have the responsiblity of
copying it. Otherwise, use Class.forName()
in the
expression.
Params: - src – the source method.
- declaring – the class to which the created method is added.
- map – the hashtable associating original class names
with substituted names.
It can be
null
.
See Also:
/**
* Creates a copy of a <code>CtMethod</code> object.
* The created method must be
* added to a class with <code>CtClass.addMethod()</code>.
*
* <p>All occurrences of class names in the created method
* are replaced with names specified by
* <code>map</code> if <code>map</code> is not <code>null</code>.
*
* <p>For example, suppose that a method <code>at()</code> is as
* follows:
*
* <pre>
* public X at(int i) {
* return (X)super.elementAt(i);
* }</pre>
*
* <p>(<code>X</code> is a class name.) If <code>map</code> substitutes
* <code>String</code> for <code>X</code>, then the created method is:
*
* <pre>
* public String at(int i) {
* return (String)super.elementAt(i);
* }</pre>
*
* <p>By default, all the occurrences of the names of the class
* declaring <code>at()</code> and the superclass are replaced
* with the name of the class and the superclass that the
* created method is added to.
* This is done whichever <code>map</code> is null or not.
* To prevent this replacement, call <code>ClassMap.fix()</code>
* or <code>put()</code> to explicitly specify replacement.
*
* <p><b>Note:</b> if the <code>.class</code> notation (for example,
* <code>String.class</code>) is included in an expression, the
* Javac compiler may produce a helper method.
* Since this constructor never
* copies this helper method, the programmers have the responsiblity of
* copying it. Otherwise, use <code>Class.forName()</code> in the
* expression.
*
* @param src the source method.
* @param declaring the class to which the created method is added.
* @param map the hashtable associating original class names
* with substituted names.
* It can be <code>null</code>.
*
* @see CtClass#addMethod(CtMethod)
* @see ClassMap#fix(String)
*/
public CtMethod(CtMethod src, CtClass declaring, ClassMap map)
throws CannotCompileException
{
this(null, declaring);
copy(src, false, map);
}
Compiles the given source code and creates a method.
This method simply delegates to make()
in
CtNewMethod
. See it for more details.
CtNewMethod
has a number of useful factory methods.
Params: - src – the source text.
- declaring – the class to which the created method is added.
See Also:
/**
* Compiles the given source code and creates a method.
* This method simply delegates to <code>make()</code> in
* <code>CtNewMethod</code>. See it for more details.
* <code>CtNewMethod</code> has a number of useful factory methods.
*
* @param src the source text.
* @param declaring the class to which the created method is added.
* @see CtNewMethod#make(String, CtClass)
*/
public static CtMethod make(String src, CtClass declaring)
throws CannotCompileException
{
return CtNewMethod.make(src, declaring);
}
Creates a method from a MethodInfo
object.
Params: - declaring – the class declaring the method.
Throws: - CannotCompileException – if the the
MethodInfo
object and the declaring class have different
ConstPool
objects
Since: 3.6
/**
* Creates a method from a <code>MethodInfo</code> object.
*
* @param declaring the class declaring the method.
* @throws CannotCompileException if the the <code>MethodInfo</code>
* object and the declaring class have different
* <code>ConstPool</code> objects
* @since 3.6
*/
public static CtMethod make(MethodInfo minfo, CtClass declaring)
throws CannotCompileException
{
if (declaring.getClassFile2().getConstPool() != minfo.getConstPool())
throw new CannotCompileException("bad declaring class");
return new CtMethod(minfo, declaring);
}
Returns a hash code value for the method.
If two methods have the same name and signature, then
the hash codes for the two methods are equal.
/**
* Returns a hash code value for the method.
* If two methods have the same name and signature, then
* the hash codes for the two methods are equal.
*/
@Override
public int hashCode() {
return getStringRep().hashCode();
}
This method is invoked when setName() or replaceClassName()
in CtClass is called.
/**
* This method is invoked when setName() or replaceClassName()
* in CtClass is called.
*/
@Override
void nameReplaced() {
cachedStringRep = null;
}
/* This method is also called by CtClassType.getMethods0().
*/
final String getStringRep() {
if (cachedStringRep == null)
cachedStringRep = methodInfo.getName()
+ Descriptor.getParamDescriptor(methodInfo.getDescriptor());
return cachedStringRep;
}
Indicates whether obj
has the same name and the
same signature as this method.
/**
* Indicates whether <code>obj</code> has the same name and the
* same signature as this method.
*/
@Override
public boolean equals(Object obj) {
return obj != null && obj instanceof CtMethod
&& ((CtMethod)obj).getStringRep().equals(getStringRep());
}
Returns the method name followed by parameter types
such as javassist.CtMethod.setBody(String)
.
Since: 3.5
/**
* Returns the method name followed by parameter types
* such as <code>javassist.CtMethod.setBody(String)</code>.
*
* @since 3.5
*/
@Override
public String getLongName() {
return getDeclaringClass().getName() + "."
+ getName() + Descriptor.toString(getSignature());
}
Obtains the name of this method.
/**
* Obtains the name of this method.
*/
@Override
public String getName() {
return methodInfo.getName();
}
Changes the name of this method.
/**
* Changes the name of this method.
*/
public void setName(String newname) {
declaringClass.checkModify();
methodInfo.setName(newname);
}
Obtains the type of the returned value.
/**
* Obtains the type of the returned value.
*/
public CtClass getReturnType() throws NotFoundException {
return getReturnType0();
}
Returns true if the method body is empty, that is, {}
.
It also returns true if the method is an abstract method.
/**
* Returns true if the method body is empty, that is, <code>{}</code>.
* It also returns true if the method is an abstract method.
*/
@Override
public boolean isEmpty() {
CodeAttribute ca = getMethodInfo2().getCodeAttribute();
if (ca == null) // abstract or native
return (getModifiers() & Modifier.ABSTRACT) != 0;
CodeIterator it = ca.iterator();
try {
return it.hasNext() && it.byteAt(it.next()) == Opcode.RETURN
&& !it.hasNext();
}
catch (BadBytecode e) {}
return false;
}
Copies a method body from another method.
If this method is abstract, the abstract modifier is removed
after the method body is copied.
All occurrences of the class names in the copied method body
are replaced with the names specified by
map
if map
is not null
.
Params: - src – the method that the body is copied from.
- map – the hashtable associating original class names
with substituted names.
It can be
null
.
/**
* Copies a method body from another method.
* If this method is abstract, the abstract modifier is removed
* after the method body is copied.
*
* <p>All occurrences of the class names in the copied method body
* are replaced with the names specified by
* <code>map</code> if <code>map</code> is not <code>null</code>.
*
* @param src the method that the body is copied from.
* @param map the hashtable associating original class names
* with substituted names.
* It can be <code>null</code>.
*/
public void setBody(CtMethod src, ClassMap map)
throws CannotCompileException
{
setBody0(src.declaringClass, src.methodInfo,
declaringClass, methodInfo, map);
}
Replace a method body with a new method body wrapping the
given method.
Params: - mbody – the wrapped method
- constParam – the constant parameter given to
the wrapped method
(maybe
null
).
See Also:
/**
* Replace a method body with a new method body wrapping the
* given method.
*
* @param mbody the wrapped method
* @param constParam the constant parameter given to
* the wrapped method
* (maybe <code>null</code>).
*
* @see CtNewMethod#wrapped(CtClass,String,CtClass[],CtClass[],CtMethod,CtMethod.ConstParameter,CtClass)
*/
public void setWrappedBody(CtMethod mbody, ConstParameter constParam)
throws CannotCompileException
{
declaringClass.checkModify();
CtClass clazz = getDeclaringClass();
CtClass[] params;
CtClass retType;
try {
params = getParameterTypes();
retType = getReturnType();
}
catch (NotFoundException e) {
throw new CannotCompileException(e);
}
Bytecode code = CtNewWrappedMethod.makeBody(clazz,
clazz.getClassFile2(),
mbody,
params, retType,
constParam);
CodeAttribute cattr = code.toCodeAttribute();
methodInfo.setCodeAttribute(cattr);
methodInfo.setAccessFlags(methodInfo.getAccessFlags()
& ~AccessFlag.ABSTRACT);
// rebuilding a stack map table is not needed.
}
// inner classes
Instances of this class represent a constant parameter.
They are used to specify the parameter given to the methods
created by CtNewMethod.wrapped()
.
See Also: - setWrappedBody.setWrappedBody(CtMethod, ConstParameter)
- CtNewMethod.wrapped(CtClass, String, CtClass[], CtClass[], CtMethod, ConstParameter, CtClass)
- CtNewConstructor.make(CtClass[], CtClass[], int, CtMethod, ConstParameter, CtClass)
/**
* Instances of this class represent a constant parameter.
* They are used to specify the parameter given to the methods
* created by <code>CtNewMethod.wrapped()</code>.
*
* @see CtMethod#setWrappedBody(CtMethod,CtMethod.ConstParameter)
* @see CtNewMethod#wrapped(CtClass,String,CtClass[],CtClass[],CtMethod,CtMethod.ConstParameter,CtClass)
* @see CtNewConstructor#make(CtClass[],CtClass[],int,CtMethod,CtMethod.ConstParameter,CtClass)
*/
public static class ConstParameter {
Makes an integer constant.
Params: - i – the constant value.
/**
* Makes an integer constant.
*
* @param i the constant value.
*/
public static ConstParameter integer(int i) {
return new IntConstParameter(i);
}
Makes a long integer constant.
Params: - i – the constant value.
/**
* Makes a long integer constant.
*
* @param i the constant value.
*/
public static ConstParameter integer(long i) {
return new LongConstParameter(i);
}
Makes an String
constant.
Params: - s – the constant value.
/**
* Makes an <code>String</code> constant.
*
* @param s the constant value.
*/
public static ConstParameter string(String s) {
return new StringConstParameter(s);
}
ConstParameter() {}
Returns: the size of the stack consumption.
/**
* @return the size of the stack consumption.
*/
int compile(Bytecode code) throws CannotCompileException {
return 0;
}
String descriptor() {
return defaultDescriptor();
}
See Also: - CtNewWrappedMethod
/**
* @see CtNewWrappedMethod
*/
static String defaultDescriptor() {
return "([Ljava/lang/Object;)Ljava/lang/Object;";
}
Returns the descriptor for constructors.
See Also: - CtNewWrappedConstructor
/**
* Returns the descriptor for constructors.
*
* @see CtNewWrappedConstructor
*/
String constDescriptor() {
return defaultConstDescriptor();
}
Returns the default descriptor for constructors.
/**
* Returns the default descriptor for constructors.
*/
static String defaultConstDescriptor() {
return "([Ljava/lang/Object;)V";
}
}
static class IntConstParameter extends ConstParameter {
int param;
IntConstParameter(int i) {
param = i;
}
@Override
int compile(Bytecode code) throws CannotCompileException {
code.addIconst(param);
return 1;
}
@Override
String descriptor() {
return "([Ljava/lang/Object;I)Ljava/lang/Object;";
}
@Override
String constDescriptor() {
return "([Ljava/lang/Object;I)V";
}
}
static class LongConstParameter extends ConstParameter {
long param;
LongConstParameter(long l) {
param = l;
}
@Override
int compile(Bytecode code) throws CannotCompileException {
code.addLconst(param);
return 2;
}
@Override
String descriptor() {
return "([Ljava/lang/Object;J)Ljava/lang/Object;";
}
@Override
String constDescriptor() {
return "([Ljava/lang/Object;J)V";
}
}
static class StringConstParameter extends ConstParameter {
String param;
StringConstParameter(String s) {
param = s;
}
@Override
int compile(Bytecode code) throws CannotCompileException {
code.addLdc(param);
return 1;
}
@Override
String descriptor() {
return "([Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;";
}
@Override
String constDescriptor() {
return "([Ljava/lang/Object;Ljava/lang/String;)V";
}
}
}