diff options
Diffstat (limited to 'src/main/javassist/bytecode')
7 files changed, 226 insertions, 26 deletions
diff --git a/src/main/javassist/bytecode/AnnotationDefaultAttribute.java b/src/main/javassist/bytecode/AnnotationDefaultAttribute.java index 43021ecf..8c7084c0 100644 --- a/src/main/javassist/bytecode/AnnotationDefaultAttribute.java +++ b/src/main/javassist/bytecode/AnnotationDefaultAttribute.java @@ -117,6 +117,28 @@ public class AnnotationDefaultAttribute extends AttributeInfo { } } + @Override + void renameClass(String oldname, String newname) { + try { + MemberValue defaultValue = getDefaultValue(); + defaultValue.renameClass(oldname, newname); + setDefaultValue(defaultValue); + } catch (Exception e) { + // ignore + } + } + + @Override + void renameClass(Map<String, String> classnames) { + try { + MemberValue defaultValue = getDefaultValue(); + defaultValue.renameClass(classnames); + setDefaultValue(defaultValue); + } catch (Exception e) { + // ignore + } + } + /** * Obtains the default value represented by this attribute. */ diff --git a/src/main/javassist/bytecode/AttributeInfo.java b/src/main/javassist/bytecode/AttributeInfo.java index be6e2a21..3aa0bd31 100644 --- a/src/main/javassist/bytecode/AttributeInfo.java +++ b/src/main/javassist/bytecode/AttributeInfo.java @@ -254,7 +254,7 @@ public class AttributeInfo { /* The following two methods are used to implement * ClassFile.renameClass(). * Only CodeAttribute, LocalVariableAttribute, - * AnnotationsAttribute, and SignatureAttribute + * AnnotationDefaultAttribute, AnnotationsAttribute, and SignatureAttribute * override these methods. */ void renameClass(String oldname, String newname) {} diff --git a/src/main/javassist/bytecode/SignatureAttribute.java b/src/main/javassist/bytecode/SignatureAttribute.java index 1a8a62dc..ff160f82 100644 --- a/src/main/javassist/bytecode/SignatureAttribute.java +++ b/src/main/javassist/bytecode/SignatureAttribute.java @@ -19,6 +19,7 @@ package javassist.bytecode; import java.io.DataInputStream; import java.io.IOException; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -110,42 +111,34 @@ public class SignatureAttribute extends AttributeInfo { } static String renameClass(String desc, Map<String,String> map) { - if (map == null) + if (map == null || map.isEmpty()) return desc; StringBuilder newdesc = new StringBuilder(); int head = 0; int i = 0; for (;;) { - int j = desc.indexOf('L', i); + final int j = desc.indexOf('L', i); if (j < 0) break; - StringBuilder nameBuf = new StringBuilder(); - int k = j; - char c; - try { - while ((c = desc.charAt(++k)) != ';') { - nameBuf.append(c); - if (c == '<') { - while ((c = desc.charAt(++k)) != '>') - nameBuf.append(c); + final ArrayList<StringBuilder> nameBufs = new ArrayList<>(); + final ArrayList<StringBuilder> genericParamBufs = new ArrayList<>(); + i = parseClassName(nameBufs, genericParamBufs, desc, j) + 1; + if (i < 0) + break; - nameBuf.append(c); - } - } - } - catch (IndexOutOfBoundsException e) { break; } - i = k + 1; - String name = nameBuf.toString(); - String name2 = map.get(name); - if (name2 != null) { - newdesc.append(desc.substring(head, j)); - newdesc.append('L'); - newdesc.append(name2); - newdesc.append(c); - head = i; + String name = String.join("$", nameBufs.toArray(new StringBuilder[0])); + String newname = map.get(name); + if (newname != null) { + if (makeNewClassName(desc, map, name, newname, newdesc, head, j, + nameBufs, genericParamBufs)) + head = i; } + else + if (replaceTypeArguments(desc, map, newdesc, head, j, + nameBufs, genericParamBufs)) + head = i; } if (head == 0) @@ -157,6 +150,127 @@ public class SignatureAttribute extends AttributeInfo { return newdesc.toString(); } + private static int parseClassName(ArrayList<StringBuilder> nameBufs, + ArrayList<StringBuilder> genericParamBufs, + String desc, int j) + { + StringBuilder nameBuf = new StringBuilder(); + StringBuilder genericParamBuf = new StringBuilder(); + int k = j; + char c; + try { + while ((c = desc.charAt(++k)) != ';') { + if (c == '<') { + genericParamBuf.append(c); + int level = 1; + while (level > 0) { + c = desc.charAt(++k); + genericParamBuf.append(c); + if (c == '<') + ++level; + else if (c == '>') + --level; + } + } + else if (c == '.') { + nameBufs.add(nameBuf); + genericParamBufs.add(genericParamBuf); + nameBuf = new StringBuilder(); + genericParamBuf = new StringBuilder(); + } + else + nameBuf.append(c); + } + } + catch (IndexOutOfBoundsException e) { + return -2; // error + } + + nameBufs.add(nameBuf); + genericParamBufs.add(genericParamBuf); + return k; + } + + private static boolean makeNewClassName(String desc, + Map<String,String> map, String name, + String newname, StringBuilder newdesc, + int head, int j, + ArrayList<StringBuilder> nameBufs, + ArrayList<StringBuilder> genericParamBufs) + { + final String[] nameSplit = name.split("\\$"); + final String[] newnameSplit = newname.split("\\$"); + if (nameSplit.length == newnameSplit.length) { + final String[] newnames = new String[nameBufs.size()]; + for (int start = 0, z = 0; z < nameBufs.size(); z++) { + final int toAggregate = (int) nameBufs.get(z).chars().filter(ch -> ch == '$').count() + 1; + String s = String.join("$", Arrays.copyOfRange(newnameSplit, start, start + toAggregate)); + start += toAggregate; + newnames[z] = s; + } + + newdesc.append(desc.substring(head, j)); + newdesc.append('L'); + for (int z = 0; z < newnames.length; z++) { + if (z > 0) + newdesc.append('.'); + + newdesc.append(newnames[z]); + final String newgenericParam; + final StringBuilder genericParamBufCurrent = genericParamBufs.get(z); + if (genericParamBufCurrent.length() > 0) + newgenericParam = "<" + renameClass(genericParamBufCurrent.substring(1, genericParamBufCurrent.length() - 1), map) + ">"; + else + newgenericParam = genericParamBufCurrent.toString(); //empty string + + newdesc.append(newgenericParam); + } + newdesc.append(';'); //the final semicolon + return true; + } + else + return false; + } + + private static boolean replaceTypeArguments(String desc, + Map<String,String> map, + StringBuilder newdesc, + int head, int j, + ArrayList<StringBuilder> nameBufs, + ArrayList<StringBuilder> genericParamBufs) + { + final ArrayList<String> newGenericParamBufs = new ArrayList<String>(); + boolean changed = false; + for (int z = 0; z < genericParamBufs.size(); z++) { + final String newGenericParam; + final StringBuilder genericParamBufCurrent = genericParamBufs.get(z); + if (genericParamBufCurrent.length() > 0) { + newGenericParam = "<" + renameClass(genericParamBufCurrent.substring(1, genericParamBufCurrent.length() - 1), map) + ">"; + changed = changed || !genericParamBufCurrent.toString().equals(newGenericParam); + } + else + newGenericParam = genericParamBufCurrent.toString(); //empty string + + newGenericParamBufs.add(newGenericParam); + } + + if (changed) { + newdesc.append(desc.substring(head, j)); + newdesc.append('L'); + for (int z = 0; z < genericParamBufs.size(); z++) { + if (z > 0) + newdesc.append('.'); + + newdesc.append(nameBufs.get(z)); + newdesc.append(newGenericParamBufs.get(z)); + } + newdesc.append(';'); + return true; + } + else + return false; + } + @SuppressWarnings("unused") private static boolean isNamePart(int c) { return c != ';' && c != '<'; diff --git a/src/main/javassist/bytecode/annotation/ArrayMemberValue.java b/src/main/javassist/bytecode/annotation/ArrayMemberValue.java index d1eeb271..f6bc6150 100644 --- a/src/main/javassist/bytecode/annotation/ArrayMemberValue.java +++ b/src/main/javassist/bytecode/annotation/ArrayMemberValue.java @@ -18,6 +18,7 @@ package javassist.bytecode.annotation; import java.io.IOException; import java.lang.reflect.Array; import java.lang.reflect.Method; +import java.util.Map; import javassist.ClassPool; import javassist.bytecode.ConstPool; @@ -87,6 +88,30 @@ public class ArrayMemberValue extends MemberValue { return a.getClass(); } + @Override + public void renameClass(String oldname, String newname) { + if (type != null) { + type.renameClass(oldname, newname); + } + if (values != null) { + for (MemberValue value : values) { + value.renameClass(oldname, newname); + } + } + } + + @Override + public void renameClass(Map<String, String> classnames) { + if (type != null) { + type.renameClass(classnames); + } + if (values != null) { + for (MemberValue value : values) { + value.renameClass(classnames); + } + } + } + /** * Obtains the type of the elements. * diff --git a/src/main/javassist/bytecode/annotation/ClassMemberValue.java b/src/main/javassist/bytecode/annotation/ClassMemberValue.java index e9fd7ec4..495a1e2a 100644 --- a/src/main/javassist/bytecode/annotation/ClassMemberValue.java +++ b/src/main/javassist/bytecode/annotation/ClassMemberValue.java @@ -18,6 +18,7 @@ package javassist.bytecode.annotation; import java.io.IOException; import java.lang.reflect.Method; +import java.util.Map; import javassist.ClassPool; import javassist.bytecode.BadBytecode; @@ -95,6 +96,20 @@ public class ClassMemberValue extends MemberValue { return loadClass(cl, "java.lang.Class"); } + @Override + public void renameClass(String oldname, String newname) { + String value = cp.getUtf8Info(valueIndex); + String newValue = Descriptor.rename(value, oldname, newname); + setValue(Descriptor.toClassName(newValue)); + } + + @Override + public void renameClass(Map<String, String> classnames) { + String value = cp.getUtf8Info(valueIndex); + String newValue = Descriptor.rename(value, classnames); + setValue(Descriptor.toClassName(newValue)); + } + /** * Obtains the value of the member. * diff --git a/src/main/javassist/bytecode/annotation/EnumMemberValue.java b/src/main/javassist/bytecode/annotation/EnumMemberValue.java index a0a4e036..0f37178a 100644 --- a/src/main/javassist/bytecode/annotation/EnumMemberValue.java +++ b/src/main/javassist/bytecode/annotation/EnumMemberValue.java @@ -18,6 +18,7 @@ package javassist.bytecode.annotation; import java.io.IOException; import java.lang.reflect.Method; +import java.util.Map; import javassist.ClassPool; import javassist.bytecode.ConstPool; @@ -76,6 +77,20 @@ public class EnumMemberValue extends MemberValue { return loadClass(cl, getType()); } + @Override + public void renameClass(String oldname, String newname) { + String type = cp.getUtf8Info(typeIndex); + String newType = Descriptor.rename(type, oldname, newname); + setType(Descriptor.toClassName(newType)); + } + + @Override + public void renameClass(Map<String, String> classnames) { + String type = cp.getUtf8Info(typeIndex); + String newType = Descriptor.rename(type, classnames); + setType(Descriptor.toClassName(newType)); + } + /** * Obtains the enum type name. * diff --git a/src/main/javassist/bytecode/annotation/MemberValue.java b/src/main/javassist/bytecode/annotation/MemberValue.java index da99885c..0f132a83 100644 --- a/src/main/javassist/bytecode/annotation/MemberValue.java +++ b/src/main/javassist/bytecode/annotation/MemberValue.java @@ -18,6 +18,7 @@ package javassist.bytecode.annotation; import java.io.IOException; import java.lang.reflect.Method; +import java.util.Map; import javassist.ClassPool; import javassist.bytecode.ConstPool; @@ -74,6 +75,14 @@ public abstract class MemberValue { return classname; } + /* The following two methods are used to implement + * ClassFile.renameClass(). + * Only ArrayMemberValue, ClassMemberValue, EnumMemberValue + * override these methods. + */ + public void renameClass(String oldname, String newname) {} + public void renameClass(Map<String, String> classnames) {} + /** * Accepts a visitor. */ |