Browse Source

Merge pull request #299 from pietrobraione/master

Fix renaming of classes in presence of generic signatures and nested classes.
This pull request has some problems but I'll fix them later.
tags/rel_3_29_0_ga
Shigeru Chiba 2 years ago
parent
commit
c8b54b3bce
No account linked to committer's email address

+ 69
- 25
src/main/javassist/bytecode/SignatureAttribute.java View File

@@ -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,41 +111,84 @@ 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;

int k = desc.indexOf(';', j);
if (k < 0)
break;

int l = desc.indexOf('<', j);
int classEndIndex;
char classEndChar;
if (l < 0 || k < l) {
classEndIndex = k;
classEndChar = ';';
} else {
classEndIndex = l;
classEndChar = '<';
StringBuilder nameBuf = new StringBuilder();
StringBuilder genericParamBuf = new StringBuilder();
final ArrayList<StringBuilder> nameBufs = new ArrayList<>();
final ArrayList<StringBuilder> genericParamBufs = new ArrayList<>();
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);
}
}
}
i = classEndIndex + 1;

String name = desc.substring(j + 1, classEndIndex);
String name2 = map.get(name);
if (name2 != null) {
newdesc.append(desc.substring(head, j));
newdesc.append('L');
newdesc.append(name2);
newdesc.append(classEndChar);
head = i;
catch (IndexOutOfBoundsException e) { break; }

nameBufs.add(nameBuf);
genericParamBufs.add(genericParamBuf);
i = k + 1;
String name = String.join("$", nameBufs.toArray(new StringBuilder[0]));
String newname = map.get(name);
if (newname != null) {
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(c); //the final semicolon
head = i;
}
}
}


+ 84
- 0
src/test/javassist/bytecode/SignatureAttributeTest.java View File

@@ -0,0 +1,84 @@
package javassist.bytecode;

import static org.junit.Assert.assertEquals;

import java.util.HashMap;

public class SignatureAttributeTest {
void test1() {
final String signature = "TX;TY;La/b/C$D$E$J$K;"; //a sequence of three ReferenceTypeSignature
final HashMap<String, String> map = new HashMap<>();
map.put("a/b/C$D$E$J$K", "o/p/Q$R$S$T$U");
map.put("e/F$G$H$I", "v/W$X$Y$Z");
final String signatureRenamed = SignatureAttribute.renameClass(signature, map);
assertEquals("TX;TY;Lo/p/Q$R$S$T$U;", signatureRenamed);
}
void test2() {
final String signature = "La/b/C<TA;TB;>.D<Ljava/lang/Integer;>;"; //a ClassTypeSignature
final HashMap<String, String> map = new HashMap<>();
map.put("a/b/C$D", "o/p/Q$R");
map.put("java/lang/Integer", "java/lang/Long");
final String signatureRenamed = SignatureAttribute.renameClass(signature, map);
assertEquals("Lo/p/Q<TA;TB;>.R<Ljava/lang/Long;>;", signatureRenamed);
}
void test3() {
final String signature = "BJLB<TX;Lc/D$E;>.F<TY;>;TZ;"; //a sequence of four JavaTypeSignature
final HashMap<String, String> map = new HashMap<>();
map.put("B$F", "P$T");
map.put("c/D$E", "q/R$S");
final String signatureRenamed = SignatureAttribute.renameClass(signature, map);
assertEquals("BJLP<TX;Lq/R$S;>.T<TY;>;TZ;", signatureRenamed);
}
void test4() {
final String signature = "La/b/C<TX;>;[[Ld/E<+TY;-Ljava/lang/Object;*>;Z"; //a sequence of three JavaTypeSignature
final HashMap<String, String> map = new HashMap<>();
map.put("java/lang/Object", "java/util/Map");
map.put("d/E", "F");
final String signatureRenamed = SignatureAttribute.renameClass(signature, map);
assertEquals("La/b/C<TX;>;[[LF<+TY;-Ljava/util/Map;*>;Z", signatureRenamed);
}
void test5() {
final String signature = "La/b/C$D$E<TX;Le/F$G<TY;TZ;>.H$I<TU;TV;>;>.J$K;"; //a ClassTypeSignature
final HashMap<String, String> map = new HashMap<>();
map.put("a/b/C$D$E$J$K", "o/p/Q$R$S$T$U");
map.put("e/F$G$H$I", "v/W$X$Y$Z");
final String signatureRenamed = SignatureAttribute.renameClass(signature, map);
assertEquals("Lo/p/Q$R$S<TX;Lv/W$X<TY;TZ;>.Y$Z<TU;TV;>;>.T$U;", signatureRenamed);
}
void test6() {
final String signature = "<X:La/B$C<TY;>.D<TZ;>;:Le/F$G;>Lh/I$J;"; //a ClassSignature
final HashMap<String, String> map = new HashMap<>();
map.put("a/B$C$D", "o/P$Q$R");
map.put("e/F$G", "s/T$U");
map.put("h/I$J", "v/W$X");
final String signatureRenamed = SignatureAttribute.renameClass(signature, map);
assertEquals("<X:Lo/P$Q<TY;>.R<TZ;>;:Ls/T$U;>Lv/W$X;", signatureRenamed);
}
void test7() {
final String signature = "<A:La/B$C;:Ld/E<TX;>.F<TY;>;:TZ;B:Ljava/lang/Thread;>(LX;TA;LA;)V^Ljava/lang/Exception;"; //a MethodSignature
final HashMap<String, String> map = new HashMap<>();
map.put("A", "P");
map.put("a/B$C", "s/T$U");
map.put("d/E$F", "v/W$X");
map.put("X", "V");
map.put("java/lang/Exception", "java/lang/RuntimeException");
final String signatureRenamed = SignatureAttribute.renameClass(signature, map);
assertEquals("<A:Ls/T$U;:Lv/W<TX;>.X<TY;>;:TZ;B:Ljava/lang/Thread;>(LV;TA;LP;)V^Ljava/lang/RuntimeException;", signatureRenamed);
}
public static void main(String[] s) {
new SignatureAttributeTest().test1();
new SignatureAttributeTest().test2();
new SignatureAttributeTest().test3();
new SignatureAttributeTest().test4();
new SignatureAttributeTest().test5();
new SignatureAttributeTest().test6();
new SignatureAttributeTest().test7();
}
}

Loading…
Cancel
Save