<p>-version 3.11
<ul>
- <li>JIRA JASSIST-67, 68, 74, 75, 76, 81, 83, 84, 85 were fixed.
+ <li>JIRA JASSIST-67, 68, 74, 75, 76, 77, 81, 83, 84, 85 were fixed.
<li>Now javassist.bytecode.CodeIterator can insert a gap into
a large method body more than 32KB. (JIRA JASSIST-79, 80)
</ul>
import java.util.Map;
import java.util.LinkedList;
import java.util.ListIterator;
+import java.util.List;
+import java.util.Iterator;
// Note: if you define a new subclass of AttributeInfo, then
// update AttributeInfo.read(), .copy(), and (maybe) write().
*/
if (nameStr.equals(LineNumberAttribute.tag))
return new LineNumberAttribute(cp, name, in);
- else if (nameStr.equals(LocalVariableAttribute.tag)
- || nameStr.equals(LocalVariableAttribute.typeTag))
+ else if (nameStr.equals(LocalVariableAttribute.tag))
return new LocalVariableAttribute(cp, name, in);
+ else if (nameStr.equals(LocalVariableTypeAttribute.tag))
+ return new LocalVariableTypeAttribute(cp, name, in);
else if (nameStr.equals(AnnotationsAttribute.visibleTag)
|| nameStr.equals(AnnotationsAttribute.invisibleTag)) {
// RuntimeVisibleAnnotations or RuntimeInvisibleAnnotations
return newList;
}
+
+ /* The following two methods are used to implement
+ * ClassFile.renameClass().
+ * Only CodeAttribute and LocalVariableAttribute override
+ * this method.
+ */
+ void renameClass(String oldname, String newname) {}
+ void renameClass(Map classnames) {}
+
+ static void renameClass(List attributes, String oldname, String newname) {
+ Iterator iterator = attributes.iterator();
+ while (iterator.hasNext()) {
+ AttributeInfo ai = (AttributeInfo)iterator.next();
+ ai.renameClass(oldname, newname);
+ }
+ }
+
+ static void renameClass(List attributes, Map classnames) {
+ Iterator iterator = attributes.iterator();
+ while (iterator.hasNext()) {
+ AttributeInfo ai = (AttributeInfo)iterator.next();
+ ai.renameClass(classnames);
+ }
+ }
}
newname = Descriptor.toJvmName(newname);
constPool.renameClass(oldname, newname);
+ AttributeInfo.renameClass(attributes, oldname, newname);
list = methods;
n = list.size();
for (int i = 0; i < n; ++i) {
MethodInfo minfo = (MethodInfo)list.get(i);
String desc = minfo.getDescriptor();
minfo.setDescriptor(Descriptor.rename(desc, oldname, newname));
+ AttributeInfo.renameClass(minfo.getAttributes(), oldname, newname);
}
list = fields;
FieldInfo finfo = (FieldInfo)list.get(i);
String desc = finfo.getDescriptor();
finfo.setDescriptor(Descriptor.rename(desc, oldname, newname));
+ AttributeInfo.renameClass(finfo.getAttributes(), oldname, newname);
}
}
constPool.renameClass(classnames);
+ AttributeInfo.renameClass(attributes, classnames);
ArrayList list = methods;
int n = list.size();
for (int i = 0; i < n; ++i) {
MethodInfo minfo = (MethodInfo)list.get(i);
String desc = minfo.getDescriptor();
minfo.setDescriptor(Descriptor.rename(desc, classnames));
+ AttributeInfo.renameClass(minfo.getAttributes(), classnames);
}
list = fields;
FieldInfo finfo = (FieldInfo)list.get(i);
String desc = finfo.getDescriptor();
finfo.setDescriptor(Descriptor.rename(desc, classnames));
+ AttributeInfo.renameClass(finfo.getAttributes(), classnames);
}
}
import java.io.IOException;
import java.util.List;
import java.util.LinkedList;
+import java.util.Iterator;
import java.util.Map;
/**
throw new UnsupportedOperationException("CodeAttribute.set()");
}
+ void renameClass(String oldname, String newname) {
+ AttributeInfo.renameClass(attributes, oldname, newname);
+ }
+
+ void renameClass(Map classnames) {
+ AttributeInfo.renameClass(attributes, classnames);
+ }
+
/**
* Returns the name of the class declaring the method including
* this code attribute.
import java.util.Map;
/**
- * <code>LocalVariableTable_attribute</code> or
- * <code>LocalVariableTypeTable_attribute</code>.
+ * <code>LocalVariableTable_attribute</code>.
*/
public class LocalVariableAttribute extends AttributeInfo {
/**
* Constructs an empty LocalVariableTable.
*/
public LocalVariableAttribute(ConstPool cp) {
- this(cp, tag);
+ super(cp, tag, new byte[2]);
+ ByteArray.write16bit(0, info, 0);
}
/**
* @see #tag
* @see #typeTag
* @since 3.1
+ * @deprecated
*/
public LocalVariableAttribute(ConstPool cp, String name) {
super(cp, name, new byte[2]);
super(cp, n, in);
}
- private LocalVariableAttribute(ConstPool cp, String name, byte[] i) {
+ LocalVariableAttribute(ConstPool cp, String name, byte[] i) {
super(cp, name, i);
}
info = newInfo;
}
+ void renameClass(String oldname, String newname) {
+ ConstPool cp = getConstPool();
+ int n = tableLength();
+ for (int i = 0; i < n; ++i) {
+ int pos = i * 10 + 2;
+ int index = ByteArray.readU16bit(info, pos + 6);
+ if (index != 0) {
+ String desc = cp.getUtf8Info(index);
+ desc = renameEntry(desc, oldname, newname);
+ ByteArray.write16bit(cp.addUtf8Info(desc), info, pos + 6);
+ }
+ }
+ }
+
+ String renameEntry(String desc, String oldname, String newname) {
+ return Descriptor.rename(desc, oldname, newname);
+ }
+
+ void renameClass(Map classnames) {
+ ConstPool cp = getConstPool();
+ int n = tableLength();
+ for (int i = 0; i < n; ++i) {
+ int pos = i * 10 + 2;
+ int index = ByteArray.readU16bit(info, pos + 6);
+ if (index != 0) {
+ String desc = cp.getUtf8Info(index);
+ desc = renameEntry(desc, classnames);
+ ByteArray.write16bit(cp.addUtf8Info(desc), info, pos + 6);
+ }
+ }
+ }
+
+ String renameEntry(String desc, Map classnames) {
+ return Descriptor.rename(desc, classnames);
+ }
+
/**
* For each <code>local_variable_table[i].index</code>,
* this method increases <code>index</code> by <code>delta</code>.
byte[] src = get();
byte[] dest = new byte[src.length];
ConstPool cp = getConstPool();
- LocalVariableAttribute attr
- = new LocalVariableAttribute(newCp, getName(), dest);
+ LocalVariableAttribute attr = makeThisAttr(newCp, dest);
int n = ByteArray.readU16bit(src, 0);
ByteArray.write16bit(n, dest, 0);
int j = 2;
return attr;
}
+
+ // LocalVariableTypeAttribute overrides this method.
+ LocalVariableAttribute makeThisAttr(ConstPool cp, byte[] dest) {
+ return new LocalVariableAttribute(cp, tag, dest);
+ }
}
--- /dev/null
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2007 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.
+ *
+ * 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.IOException;
+import java.util.Map;
+
+/**
+ * <code>LocalVariableTypeTable_attribute</code>.
+ *
+ * @since 3.11
+ */
+public class LocalVariableTypeAttribute extends LocalVariableAttribute {
+ /**
+ * The name of the attribute <code>"LocalVariableTypeTable"</code>.
+ */
+ public static final String tag = LocalVariableAttribute.typeTag;
+
+ /**
+ * Constructs an empty LocalVariableTypeTable.
+ */
+ public LocalVariableTypeAttribute(ConstPool cp) {
+ super(cp, tag, new byte[2]);
+ ByteArray.write16bit(0, info, 0);
+ }
+
+ LocalVariableTypeAttribute(ConstPool cp, int n, DataInputStream in)
+ throws IOException
+ {
+ super(cp, n, in);
+ }
+
+ private LocalVariableTypeAttribute(ConstPool cp, byte[] dest) {
+ super(cp, tag, dest);
+ }
+
+ String renameEntry(String desc, String oldname, String newname) {
+ return SignatureAttribute.renameClass(desc, oldname, newname);
+ }
+
+ String renameEntry(String desc, Map classnames) {
+ return SignatureAttribute.renameClass(desc, classnames);
+ }
+
+ LocalVariableAttribute makeThisAttr(ConstPool cp, byte[] dest) {
+ return new LocalVariableTypeAttribute(cp, dest);
+ }
+}
return getConstPool().getUtf8Info(ByteArray.readU16bit(get(), 0));
}
+ /**
+ * Sets <code>signature_index</code> to the index of the given signature,
+ * which is added to a constant pool.
+ *
+ * @param sig new signature.
+ * @since 3.11
+ */
+ public void setSignature(String sig) {
+ int index = getConstPool().addUtf8Info(sig);
+ ByteArray.write16bit(index, info, 0);
+ }
+
/**
* Makes a copy. Class names are replaced according to the
* given <code>Map</code> object.
return new SignatureAttribute(newCp, getSignature());
}
+ void renameClass(String oldname, String newname) {
+ String sig = renameClass(getSignature(), oldname, newname);
+ setSignature(sig);
+ }
+
+ void renameClass(Map classnames) {
+ String sig = renameClass(getSignature(), classnames);
+ setSignature(sig);
+ }
+
+ static String renameClass(String desc, String oldname, String newname) {
+ if (desc.indexOf(oldname) < 0)
+ return desc;
+
+ StringBuffer newdesc = new StringBuffer();
+ int head = 0;
+ int i = 0;
+ for (;;) {
+ int j = desc.indexOf('L', i);
+ if (j < 0)
+ break;
+
+ int k = j;
+ int p = 0;
+ char c;
+ boolean match = true;
+ try {
+ int len = oldname.length();
+ while (isNamePart(c = desc.charAt(++k)))
+ if (p >= len || c != oldname.charAt(p++))
+ match = false;
+ }
+ catch (IndexOutOfBoundsException e) { break; }
+ i = k + 1;
+ if (match && p == oldname.length()) {
+ newdesc.append(desc.substring(head, j));
+ newdesc.append('L');
+ newdesc.append(newname);
+ newdesc.append(c);
+ head = i;
+ }
+ }
+
+ if (head == 0)
+ return desc;
+ else {
+ int len = desc.length();
+ if (head < len)
+ newdesc.append(desc.substring(head, len));
+
+ return newdesc.toString();
+ }
+ }
+
+ static String renameClass(String desc, Map map) {
+ if (map == null)
+ return desc;
+
+ StringBuffer newdesc = new StringBuffer();
+ int head = 0;
+ int i = 0;
+ for (;;) {
+ int j = desc.indexOf('L', i);
+ if (j < 0)
+ break;
+
+ StringBuffer nameBuf = new StringBuffer();
+ int k = j;
+ char c;
+ try {
+ while (isNamePart(c = desc.charAt(++k)))
+ nameBuf.append(c);
+ }
+ catch (IndexOutOfBoundsException e) { break; }
+ i = k + 1;
+ String name = nameBuf.toString();
+ String name2 = (String)map.get(name);
+ if (name2 != null) {
+ newdesc.append(desc.substring(head, j));
+ newdesc.append('L');
+ newdesc.append(name2);
+ newdesc.append(c);
+ head = i;
+ }
+ }
+
+ if (head == 0)
+ return desc;
+ else {
+ int len = desc.length();
+ if (head < len)
+ newdesc.append(desc.substring(head, len));
+
+ return newdesc.toString();
+ }
+ }
+
+ private static boolean isNamePart(int c) {
+ return c != ';' && c != '<';
+ }
+
static private class Cursor {
int position = 0;