method_info
structure.
*
* @see javassist.CtMethod#getMethodInfo()
* @see javassist.CtConstructor#getMethodInfo()
*/
public final class MethodInfo {
ConstPool constPool;
int accessFlags;
int name;
int descriptor;
LinkedList attribute; // may be null
/**
* The name of constructors: <init>
.
*/
public static final String nameInit = "<clinit>
.
*/
public static final String nameClinit = "method_info
structure.
*
* @param cp a constant pool table
* @param methodname method name
* @param desc method descriptor
*
* @see Descriptor
*/
public MethodInfo(ConstPool cp, String methodname, String desc) {
this(cp);
accessFlags = 0;
name = cp.addUtf8Info(methodname);
descriptor = constPool.addUtf8Info(desc);
}
MethodInfo(ConstPool cp, DataInputStream in) throws IOException {
this(cp);
read(in);
}
/**
* Constructs a copy of method_info
structure.
* Class names appearing in the source method_info
* are renamed according to classnameMap
.
*
* Note: only Code
and Exceptions
* attributes are copied from the source. The other attributes
* are ignored.
*
* @param cp a constant pool table
* @param methodname a method name
* @param src a source method_info
* @param classnameMap specifies pairs of replaced and substituted
* name.
* @see Descriptor
*/
public MethodInfo(ConstPool cp, String methodname, MethodInfo src,
Map classnameMap) throws BadBytecode
{
this(cp);
read(src, methodname, classnameMap);
}
/**
* Returns a method name.
*/
public String getName() {
return constPool.getUtf8Info(name);
}
/**
* Sets a method name.
*/
public void setName(String newName) {
name = constPool.addUtf8Info(newName);
}
/**
* Returns true if this is not a constructor or a class initializer
* (static initializer).
*/
public boolean isMethod() {
String n = getName();
return !n.equals(nameInit) && !n.equals(nameClinit);
}
/**
* Returns a constant pool table used by this method.
*/
public ConstPool getConstPool() { return constPool; }
/**
* Returns true if this is a constructor.
*/
public boolean isConstructor() { return getName().equals(nameInit); }
/**
* Returns true if this is a class initializer (static initializer).
*/
public boolean isStaticInitializer() {
return getName().equals(nameClinit);
}
/**
* Returns access flags.
*
* @see AccessFlag
*/
public int getAccessFlags() {
return accessFlags;
}
/**
* Sets access flags.
*
* @see AccessFlag
*/
public void setAccessFlags(int acc) {
accessFlags = acc;
}
/**
* Returns a method descriptor.
*
* @see Descriptor
*/
public String getDescriptor() {
return constPool.getUtf8Info(descriptor);
}
/**
* Sets a method descriptor.
*
* @see Descriptor
*/
public void setDescriptor(String desc) {
if (!desc.equals(getDescriptor()))
descriptor = constPool.addUtf8Info(desc);
}
/**
* Returns all the attributes.
*
* @return a list of AttributeInfo
objects.
* @see AttributeInfo
*/
public List getAttributes() {
if (attribute == null)
attribute = new LinkedList();
return attribute;
}
/**
* Returns the attribute with the specified name.
* If it is not found, this method returns null.
*
* @param name attribute name
* @return an AttributeInfo
object or null.
*/
public AttributeInfo getAttribute(String name) {
return AttributeInfo.lookup(attribute, name);
}
/**
* Appends an attribute. If there is already an attribute with
* the same name, the new one substitutes for it.
*/
public void addAttribute(AttributeInfo info) {
if (attribute == null)
attribute = new LinkedList();
AttributeInfo.remove(attribute, info.getName());
attribute.add(info);
}
/**
* Returns an Exceptions attribute.
*
* @return an Exceptions attribute
* or null if it is not specified.
*/
public ExceptionsAttribute getExceptionsAttribute() {
AttributeInfo info
= AttributeInfo.lookup(attribute, ExceptionsAttribute.class);
return (ExceptionsAttribute)info;
}
/**
* Returns a Code attribute.
*
* @return a Code attribute
* or null if it is not specified.
*/
public CodeAttribute getCodeAttribute() {
AttributeInfo info
= AttributeInfo.lookup(attribute, CodeAttribute.class);
return (CodeAttribute)info;
}
/**
* Removes an Exception attribute.
*/
public void removeExceptionsAttribute() {
AttributeInfo.remove(attribute, ExceptionsAttribute.class);
}
/**
* Adds an Exception attribute.
*
*
The added attribute must share the same constant pool table
* as this method_info
structure.
*/
public void setExceptionsAttribute(ExceptionsAttribute cattr) {
removeExceptionsAttribute();
if (attribute == null)
attribute = new LinkedList();
attribute.add(cattr);
}
/**
* Removes a Code attribute.
*/
public void removeCodeAttribute() {
AttributeInfo.remove(attribute, CodeAttribute.class);
}
/**
* Adds a Code attribute.
*
*
The added attribute must share the same constant pool table
* as this method_info
structure.
*/
public void setCodeAttribute(CodeAttribute cattr) {
removeCodeAttribute();
if (attribute == null)
attribute = new LinkedList();
attribute.add(cattr);
}
/**
* Returns the line number of the source line corresponding to the
* specified bytecode contained in this method.
*
* @param pos the position of the bytecode (>= 0).
* an index into the code array.
* @return -1 if this information is not available.
*/
public int getLineNumber(int pos) {
CodeAttribute ca = getCodeAttribute();
if (ca == null)
return -1;
LineNumberAttribute ainfo
= (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
if (ainfo == null)
return -1;
return ainfo.toLineNumber(pos);
}
/**
* Changes a super constructor called by this constructor.
*
*
This method modifies a call to super()
,
* which should be at the
* head of a constructor body, so that a constructor in a different
* super class is called. This method does not change actural
* parameters. Hence the new super class must have a constructor
* with the same signature as the original one.
*
*
This method should be called when the super class * of the class declaring this method is changed. * *
This method does not perform anything unless this
* MethodInfo
represents a constructor.
*
* @param superclass the new super class
*/
public void setSuperclass(String superclass) throws BadBytecode {
if (!isConstructor())
return;
CodeAttribute ca = getCodeAttribute();
byte[] code = ca.getCode();
CodeIterator iterator = ca.iterator();
int pos = iterator.skipSuperConstructor();
if (pos >= 0) { // not this()
ConstPool cp = constPool;
int mref = ByteArray.readU16bit(code, pos + 1);
int nt = cp.getMethodrefNameAndType(mref);
int sc = cp.addClassInfo(superclass);
int mref2 = cp.addMethodrefInfo(sc, nt);
ByteArray.write16bit(mref2, code, pos + 1);
}
}
private void read(MethodInfo src, String methodname, Map classnames)
throws BadBytecode
{
ConstPool destCp = constPool;
accessFlags = src.accessFlags;
name = destCp.addUtf8Info(methodname);
ConstPool srcCp = src.constPool;
String desc = srcCp.getUtf8Info(src.descriptor);
String desc2 = Descriptor.rename(desc, classnames);
descriptor = destCp.addUtf8Info(desc2);
attribute = new LinkedList();
ExceptionsAttribute eattr = src.getExceptionsAttribute();
if (eattr != null)
attribute.add(eattr.copy(destCp, classnames));
CodeAttribute cattr = src.getCodeAttribute();
if (cattr != null)
attribute.add(cattr.copy(destCp, classnames));
}
private void read(DataInputStream in) throws IOException {
accessFlags = in.readUnsignedShort();
name = in.readUnsignedShort();
descriptor = in.readUnsignedShort();
int n = in.readUnsignedShort();
attribute = new LinkedList();
for (int i = 0; i < n; ++i)
attribute.add(AttributeInfo.read(constPool, in));
}
void write(DataOutputStream out) throws IOException {
out.writeShort(accessFlags);
out.writeShort(name);
out.writeShort(descriptor);
if (attribute == null)
out.writeShort(0);
else {
out.writeShort(attribute.size());
AttributeInfo.writeAll(attribute, out);
}
}
}