
com.feilong.lib.javassist.CtMethod Maven / Gradle / Ivy
Show all versions of feilong Show documentation
/*
* 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 com.feilong.lib.javassist;
import com.feilong.lib.javassist.bytecode.AccessFlag;
import com.feilong.lib.javassist.bytecode.BadBytecode;
import com.feilong.lib.javassist.bytecode.Bytecode;
import com.feilong.lib.javassist.bytecode.CodeAttribute;
import com.feilong.lib.javassist.bytecode.CodeIterator;
import com.feilong.lib.javassist.bytecode.ConstPool;
import com.feilong.lib.javassist.bytecode.Descriptor;
import com.feilong.lib.javassist.bytecode.MethodInfo;
import com.feilong.lib.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 CtClass#getDeclaredMethods()
* @see CtNewMethod
*/
public final class CtMethod extends CtBehavior{
protected String cachedStringRep;
/**
* @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()
.
*
* @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.
*
* @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 null
.
*
* @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.
*
* @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.
*
* @param declaring
* the class declaring the method.
* @throws CannotCompileException
* if the the MethodInfo
* object and the declaring class have different
* ConstPool
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.
*/
@Override
public int hashCode(){
return getStringRep().hashCode();
}
/**
* 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.
*/
@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
*/
@Override
public String getLongName(){
return getDeclaringClass().getName() + "." + getName() + Descriptor.toString(getSignature());
}
/**
* Obtains the name of this method.
*/
@Override
public String getName(){
return methodInfo.getName();
}
/**
* Changes the name of this method.
*/
public void setName(String newname){
declaringClass.checkModify();
methodInfo.setName(newname);
}
/**
* 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.
*/
@Override
public boolean isEmpty(){
CodeAttribute ca = getMethodInfo2().getCodeAttribute();
if (ca == null){
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
.
*
* @param src
* the method that the body is copied from.
* @param map
* the hashtable associating original class names
* with substituted names.
* It can be null
.
*/
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.
*
* @param mbody
* the wrapped method
* @param constParam
* the constant parameter given to
* the wrapped method
* (maybe null
).
*
* @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 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.
*
* @param i
* the constant value.
*/
public static ConstParameter integer(int i){
return new IntConstParameter(i);
}
/**
* Makes a long integer constant.
*
* @param i
* the constant value.
*/
public static ConstParameter integer(long i){
return new LongConstParameter(i);
}
/**
* Makes an String
constant.
*
* @param s
* the constant value.
*/
public static ConstParameter string(String s){
return new StringConstParameter(s);
}
ConstParameter(){
}
/**
* @return the size of the stack consumption.
*/
int compile(Bytecode code) throws CannotCompileException{
return 0;
}
String descriptor(){
return defaultDescriptor();
}
/**
* @see CtNewWrappedMethod
*/
static String defaultDescriptor(){
return "([Ljava/lang/Object;)Ljava/lang/Object;";
}
/**
* Returns the descriptor for constructors.
*
* @see CtNewWrappedConstructor
*/
String constDescriptor(){
return defaultConstDescriptor();
}
/**
* 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";
}
}
}