Recentemente ho scritto il mio mapper ConstantPool perché ASM e JarJar hanno avuto i seguenti problemi:
- a rallentare
- non supportava la riscrittura senza tutte le dipendenze classe
- non supportava lo streaming
- Non supportato Remapper in modalità API Albero
- Ha dovuto espandere e comprimere StackMaps
ho finito con il seguente:
public void process(DataInputStream in, DataOutputStream out, Function mapper) throws IOException {
int magic = in.readInt();
if (magic != 0xcafebabe) throw new ClassFormatError("wrong magic: " + magic);
out.writeInt(magic);
copy(in, out, 4); // minor and major
int size = in.readUnsignedShort();
out.writeShort(size);
for (int i = 1; i < size; i++) {
int tag = in.readUnsignedByte();
out.writeByte(tag);
Constant constant = Constant.constant(tag);
switch (constant) {
case Utf8:
out.writeUTF(mapper.apply(in.readUTF()));
break;
case Double:
case Long:
i++; // "In retrospect, making 8-byte constants take two constant pool entries was a poor choice."
// See http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.5
default:
copy(in, out, constant.size);
break;
}
}
Streams.copyAndClose(in, out);
}
private final byte[] buffer = new byte[8];
private void copy(DataInputStream in, DataOutputStream out, int amount) throws IOException {
in.readFully(buffer, 0, amount);
out.write(buffer, 0, amount);
}
E poi
public enum Constant {
Utf8(1, -1),
Integer(3, 4),
Float(4, 4),
Long(5, 8),
Double(6,8),
Class(7, 2),
String(8, 2),
Field(9, 4),
Method(10, 4),
InterfaceMethod(11, 4),
NameAndType(12, 4),
MethodHandle(15, 3),
MethodType(16, 2),
InvokeDynamic(18, 4);
public final int tag, size;
Constant(int tag, int size) { this.tag = tag; this.size = size; }
private static final Constant[] constants;
static{
constants = new Constant[19];
for (Constant c : Constant.values()) constants[c.tag] = c;
}
public static Constant constant(int tag) {
try {
Constant constant = constants[tag];
if(constant != null) return constant;
} catch (IndexOutOfBoundsException ignored) { }
throw new ClassFormatError("Unknown tag: " + tag);
}
Ho pensato di mostrare le alternative senza librerie come è un bel posto abbastanza per iniziare l'hacking da. Il mio codice è stato ispirato dal codice sorgente javap
Ci sono un paio di librerie di manipolazione bytecode, come ASM e BCEL, che consentono di modificare i file di classe a proprio piacimento. La soluzione migliore, IMO, è estrarre la costante come una proprietà e passare attraverso l'inconveniente della ricompilazione il tempo necessario per l'estrazione. –
@ NathanD.Ryan Certamente lo estrarrò e lo inserirò in un file di configurazione per il futuro, ma in questo caso specifico sarebbe molto scomodo ricompilare la versione distribuita, che è piuttosto vecchia. –
La stringa in questione è una costante in fase di compilazione? –