/*
 * 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.bytecode;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javassist.ClassPool;
import javassist.bytecode.stackmap.MapMaker;

method_info structure.

The bytecode sequence of the method is represented by a CodeAttribute object.

The following code adds the default constructor to a class: of int type:

ClassFile cf = ...
Bytecode code = new Bytecode(cf.getConstPool());
code.addAload(0);
code.addInvokespecial("java/lang/Object", MethodInfo.nameInit, "()V");
code.addReturn(null);
code.setMaxLocals(1);
MethodInfo minfo = new MethodInfo(cf.getConstPool(), MethodInfo.nameInit, "()V");
minfo.setCodeAttribute(code.toCodeAttribute());
cf.addMethod(minfo);
See Also:
/** * <code>method_info</code> structure. * * <p>The bytecode sequence of the method is represented * by a <code>CodeAttribute</code> object. * * <p>The following code adds the default constructor to a class: * of <code>int</code> type: * <blockquote><pre> * ClassFile cf = ... * Bytecode code = new Bytecode(cf.getConstPool()); * code.addAload(0); * code.addInvokespecial("java/lang/Object", MethodInfo.nameInit, "()V"); * code.addReturn(null); * code.setMaxLocals(1); * * MethodInfo minfo = new MethodInfo(cf.getConstPool(), MethodInfo.nameInit, "()V"); * minfo.setCodeAttribute(code.toCodeAttribute()); * cf.addMethod(minfo); * </pre></blockquote> * * @see #getCodeAttribute() * @see CodeAttribute * @see Bytecode * @see javassist.CtMethod#getMethodInfo() * @see javassist.CtConstructor#getMethodInfo() */
public class MethodInfo { ConstPool constPool; int accessFlags; int name; String cachedName; int descriptor; List<AttributeInfo> attribute; // may be null
If this value is true, Javassist maintains a StackMap attribute generated by the preverify tool of J2ME (CLDC). The initial value of this field is false.
/** * If this value is true, Javassist maintains a <code>StackMap</code> attribute * generated by the <code>preverify</code> tool of J2ME (CLDC). The initial * value of this field is <code>false</code>. */
public static boolean doPreverify = false;
The name of constructors: <init>.
/** * The name of constructors: <code>&lt;init&gt;</code>. */
public static final String nameInit = "<init>";
The name of class initializer (static initializer): <clinit>.
/** * The name of class initializer (static initializer): * <code>&lt;clinit&gt;</code>. */
public static final String nameClinit = "<clinit>"; private MethodInfo(ConstPool cp) { constPool = cp; attribute = null; }
Constructs a method_info structure. The initial value of access_flags is zero.
Params:
  • cp – a constant pool table
  • methodname – method name
  • desc – method descriptor
See Also:
/** * Constructs a <code>method_info</code> structure. The initial value of * <code>access_flags</code> is zero. * * @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); cachedName = 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.

Params:
  • cp – a constant pool table
  • methodname – a method name
  • src – a source method_info
  • classnameMap – specifies pairs of replaced and substituted name.
See Also:
/** * Constructs a copy of <code>method_info</code> structure. Class names * appearing in the source <code>method_info</code> are renamed according * to <code>classnameMap</code>. * * <p> * Note: only <code>Code</code> and <code>Exceptions</code> 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 <code>method_info</code> * @param classnameMap * specifies pairs of replaced and substituted name. * @see Descriptor */
public MethodInfo(ConstPool cp, String methodname, MethodInfo src, Map<String,String> classnameMap) throws BadBytecode { this(cp); read(src, methodname, classnameMap); }
Returns a string representation of the object.
/** * Returns a string representation of the object. */
@Override public String toString() { return getName() + " " + getDescriptor(); }
Copies all constant pool items to a given new constant pool and replaces the original items with the new ones. This is used for garbage collecting the items of removed fields and methods.
Params:
  • cp – the destination
/** * Copies all constant pool items to a given new constant pool * and replaces the original items with the new ones. * This is used for garbage collecting the items of removed fields * and methods. * * @param cp the destination */
void compact(ConstPool cp) { name = cp.addUtf8Info(getName()); descriptor = cp.addUtf8Info(getDescriptor()); attribute = AttributeInfo.copyAll(attribute, cp); constPool = cp; } void prune(ConstPool cp) { List<AttributeInfo> newAttributes = new ArrayList<AttributeInfo>(); AttributeInfo invisibleAnnotations = getAttribute(AnnotationsAttribute.invisibleTag); if (invisibleAnnotations != null) { invisibleAnnotations = invisibleAnnotations.copy(cp, null); newAttributes.add(invisibleAnnotations); } AttributeInfo visibleAnnotations = getAttribute(AnnotationsAttribute.visibleTag); if (visibleAnnotations != null) { visibleAnnotations = visibleAnnotations.copy(cp, null); newAttributes.add(visibleAnnotations); } AttributeInfo parameterInvisibleAnnotations = getAttribute(ParameterAnnotationsAttribute.invisibleTag); if (parameterInvisibleAnnotations != null) { parameterInvisibleAnnotations = parameterInvisibleAnnotations.copy(cp, null); newAttributes.add(parameterInvisibleAnnotations); } AttributeInfo parameterVisibleAnnotations = getAttribute(ParameterAnnotationsAttribute.visibleTag); if (parameterVisibleAnnotations != null) { parameterVisibleAnnotations = parameterVisibleAnnotations.copy(cp, null); newAttributes.add(parameterVisibleAnnotations); } AnnotationDefaultAttribute defaultAttribute = (AnnotationDefaultAttribute) getAttribute(AnnotationDefaultAttribute.tag); if (defaultAttribute != null) newAttributes.add(defaultAttribute); ExceptionsAttribute ea = getExceptionsAttribute(); if (ea != null) newAttributes.add(ea); AttributeInfo signature = getAttribute(SignatureAttribute.tag); if (signature != null) { signature = signature.copy(cp, null); newAttributes.add(signature); } attribute = newAttributes; name = cp.addUtf8Info(getName()); descriptor = cp.addUtf8Info(getDescriptor()); constPool = cp; }
Returns a method name.
/** * Returns a method name. */
public String getName() { if (cachedName == null) cachedName = constPool.getUtf8Info(name); return cachedName; }
Sets a method name.
/** * Sets a method name. */
public void setName(String newName) { name = constPool.addUtf8Info(newName); cachedName = newName; }
Returns true if this is not a constructor or a class initializer (static initializer).
/** * 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.
/** * Returns a constant pool table used by this method. */
public ConstPool getConstPool() { return constPool; }
Returns true if this is a constructor.
/** * Returns true if this is a constructor. */
public boolean isConstructor() { return getName().equals(nameInit); }
Returns true if this is a class initializer (static initializer).
/** * Returns true if this is a class initializer (static initializer). */
public boolean isStaticInitializer() { return getName().equals(nameClinit); }
Returns access flags.
See Also:
  • AccessFlag
/** * Returns access flags. * * @see AccessFlag */
public int getAccessFlags() { return accessFlags; }
Sets access flags.
See Also:
  • AccessFlag
/** * Sets access flags. * * @see AccessFlag */
public void setAccessFlags(int acc) { accessFlags = acc; }
Returns a method descriptor.
See Also:
  • Descriptor
/** * Returns a method descriptor. * * @see Descriptor */
public String getDescriptor() { return constPool.getUtf8Info(descriptor); }
Sets a method descriptor.
See Also:
  • Descriptor
/** * Sets a method descriptor. * * @see Descriptor */
public void setDescriptor(String desc) { if (!desc.equals(getDescriptor())) descriptor = constPool.addUtf8Info(desc); }
Returns all the attributes. The returned List object is shared with this object. If you add a new attribute to the list, the attribute is also added to the method represented by this object. If you remove an attribute from the list, it is also removed from the method.
See Also:
Returns:a list of AttributeInfo objects.
/** * Returns all the attributes. The returned <code>List</code> object * is shared with this object. If you add a new attribute to the list, * the attribute is also added to the method represented by this * object. If you remove an attribute from the list, it is also removed * from the method. * * @return a list of <code>AttributeInfo</code> objects. * @see AttributeInfo */
public List<AttributeInfo> getAttributes() { if (attribute == null) attribute = new ArrayList<AttributeInfo>(); return attribute; }
Returns the attribute with the specified name. If it is not found, this method returns null.

An attribute name can be obtained by, for example, AnnotationsAttribute.visibleTag or AnnotationsAttribute.invisibleTag.

Params:
  • name – attribute name
See Also:
Returns:an AttributeInfo object or null.
/** * Returns the attribute with the specified name. If it is not found, this * method returns null. * * <p>An attribute name can be obtained by, for example, * {@link AnnotationsAttribute#visibleTag} or * {@link AnnotationsAttribute#invisibleTag}. * </p> * * @param name attribute name * @return an <code>AttributeInfo</code> object or null. * @see #getAttributes() */
public AttributeInfo getAttribute(String name) { return AttributeInfo.lookup(attribute, name); }
Removes an attribute with the specified name.
Params:
  • name – attribute name.
Returns: the removed attribute or null.
Since:3.21
/** * Removes an attribute with the specified name. * * @param name attribute name. * @return the removed attribute or null. * @since 3.21 */
public AttributeInfo removeAttribute(String name) { return AttributeInfo.remove(attribute, name); }
Appends an attribute. If there is already an attribute with the same name, the new one substitutes for it.
See Also:
  • getAttributes()
/** * Appends an attribute. If there is already an attribute with the same * name, the new one substitutes for it. * * @see #getAttributes() */
public void addAttribute(AttributeInfo info) { if (attribute == null) attribute = new ArrayList<AttributeInfo>(); AttributeInfo.remove(attribute, info.getName()); attribute.add(info); }
Returns an Exceptions attribute.
Returns:an Exceptions attribute or null if it is not specified.
/** * Returns an Exceptions attribute. * * @return an Exceptions attribute or null if it is not specified. */
public ExceptionsAttribute getExceptionsAttribute() { AttributeInfo info = AttributeInfo.lookup(attribute, ExceptionsAttribute.tag); return (ExceptionsAttribute)info; }
Returns a Code attribute.
Returns:a Code attribute or null if it is not specified.
/** * Returns a Code attribute. * * @return a Code attribute or null if it is not specified. */
public CodeAttribute getCodeAttribute() { AttributeInfo info = AttributeInfo.lookup(attribute, CodeAttribute.tag); return (CodeAttribute)info; }
Removes an Exception attribute.
/** * Removes an Exception attribute. */
public void removeExceptionsAttribute() { AttributeInfo.remove(attribute, ExceptionsAttribute.tag); }
Adds an Exception attribute.

The added attribute must share the same constant pool table as this method_info structure.

/** * Adds an Exception attribute. * * <p> * The added attribute must share the same constant pool table as this * <code>method_info</code> structure. */
public void setExceptionsAttribute(ExceptionsAttribute cattr) { removeExceptionsAttribute(); if (attribute == null) attribute = new ArrayList<AttributeInfo>(); attribute.add(cattr); }
Removes a Code attribute.
/** * Removes a Code attribute. */
public void removeCodeAttribute() { AttributeInfo.remove(attribute, CodeAttribute.tag); }
Adds a Code attribute.

The added attribute must share the same constant pool table as this method_info structure.

/** * Adds a Code attribute. * * <p> * The added attribute must share the same constant pool table as this * <code>method_info</code> structure. */
public void setCodeAttribute(CodeAttribute cattr) { removeCodeAttribute(); if (attribute == null) attribute = new ArrayList<AttributeInfo>(); attribute.add(cattr); }
Rebuilds a stack map table if the class file is for Java 6 or later. Java 5 or older Java VMs do not recognize a stack map table. If doPreverify is true, this method also rebuilds a stack map for J2ME (CLDC).
Params:
  • pool – used for making type hierarchy.
  • cf – rebuild if this class file is for Java 6 or later.
See Also:
Since:3.6
/** * Rebuilds a stack map table if the class file is for Java 6 * or later. Java 5 or older Java VMs do not recognize a stack * map table. If <code>doPreverify</code> is true, this method * also rebuilds a stack map for J2ME (CLDC). * * @param pool used for making type hierarchy. * @param cf rebuild if this class file is for Java 6 or later. * @see #rebuildStackMap(ClassPool) * @see #rebuildStackMapForME(ClassPool) * @see #doPreverify * @since 3.6 */
public void rebuildStackMapIf6(ClassPool pool, ClassFile cf) throws BadBytecode { if (cf.getMajorVersion() >= ClassFile.JAVA_6) rebuildStackMap(pool); if (doPreverify) rebuildStackMapForME(pool); }
Rebuilds a stack map table. If no stack map table is included, a new one is created. If this MethodInfo does not include a code attribute, nothing happens.
Params:
  • pool – used for making type hierarchy.
See Also:
Since:3.6
/** * Rebuilds a stack map table. If no stack map table is included, * a new one is created. If this <code>MethodInfo</code> does not * include a code attribute, nothing happens. * * @param pool used for making type hierarchy. * @see StackMapTable * @since 3.6 */
public void rebuildStackMap(ClassPool pool) throws BadBytecode { CodeAttribute ca = getCodeAttribute(); if (ca != null) { StackMapTable smt = MapMaker.make(pool, this); ca.setAttribute(smt); } }
Rebuilds a stack map table for J2ME (CLDC). If no stack map table is included, a new one is created. If this MethodInfo does not include a code attribute, nothing happens.
Params:
  • pool – used for making type hierarchy.
See Also:
Since:3.12
/** * Rebuilds a stack map table for J2ME (CLDC). If no stack map table is included, * a new one is created. If this <code>MethodInfo</code> does not * include a code attribute, nothing happens. * * @param pool used for making type hierarchy. * @see StackMap * @since 3.12 */
public void rebuildStackMapForME(ClassPool pool) throws BadBytecode { CodeAttribute ca = getCodeAttribute(); if (ca != null) { StackMap sm = MapMaker.make2(pool, this); ca.setAttribute(sm); } }
Returns the line number of the source line corresponding to the specified bytecode contained in this method.
Params:
  • pos – the position of the bytecode (>= 0). an index into the code array.
Returns:-1 if this information is not available.
/** * Returns the line number of the source line corresponding to the specified * bytecode contained in this method. * * @param pos * the position of the bytecode (&gt;= 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 actual 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.

Params:
  • superclass – the new super class
/** * Changes a super constructor called by this constructor. * * <p> * This method modifies a call to <code>super()</code>, 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 actual parameters. * Hence the new super class must have a constructor with the same signature * as the original one. * * <p> * This method should be called when the super class of the class declaring * this method is changed. * * <p> * This method does not perform anything unless this <code>MethodInfo</code> * 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<String,String> classnames) { ConstPool destCp = constPool; accessFlags = src.accessFlags; name = destCp.addUtf8Info(methodname); cachedName = methodname; ConstPool srcCp = src.constPool; String desc = srcCp.getUtf8Info(src.descriptor); String desc2 = Descriptor.rename(desc, classnames); descriptor = destCp.addUtf8Info(desc2); attribute = new ArrayList<AttributeInfo>(); 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 ArrayList<AttributeInfo>(); 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); } } }