Bu cevap o benim için en tanıdık api çünkü (ASM homepage üzerine ASM 4,0 Bir Java bytecode mühendislik kütüphanesinde bölümünü 2.2 bakınız) ASM ziyaretçi api kullanılarak yapılabilir gösterir. ASM ayrıca, bu durumda kullanılması genellikle daha kolay olabilecek bir nesne modeli API'sine (aynı belgede Bölüm II'ye bakın) sahiptir. Nesne modeli, bellekte tüm sınıf dosyasının bir ağacını oluşturduğundan, ancak biraz daha yavaş bir performans sergilediğinden, performans vuruşunu dönüştürmek için gereken yalnızca küçük bir sınıf varsa, ihmal edilebilir.
Değerleri sabit olmayan (sayı gibi) static final
alanları oluştururken, bunların başlatılması aslında bir "static initializer block" olur. sınıfta orada can sadece dosyaları ederken,
public class Example {
public static final Example FIRST;
public static final Example SECOND;
static {
FIRST = new Example(1);
SECOND = new Example(2);
}
...
}
bir java dosyasında birden böyle statik {...} blokları için izin verilir: Böylece, ikinci (dönüştürülmüş) kod listesi aşağıdaki java kodu eşdeğerdir tek ol. Java derleyicisi, bu gereksinimi karşılamak için birden çok statik bloğu otomatik olarak birleştirir. Bayt kodu manipüle edildiğinde bu, eğer daha önce hiç bir statik blok yoksa, yeni bir tane yaratırız, eğer mevcut bir statik blok varsa, mevcut kodun başlangıcına kodumuzu eklememiz gerekir (ön hazırlık, ekleme yapmaktan daha kolaydır).
ASM ile statik blok, <clinit>
özel adıyla statik bir yönteme benziyor; tıpkı yapıcıların özel adı <init>
olan yöntemlere benzemesi gibi.
Ziyaretçi api'sini kullanırken, bir yöntemin daha önce tanımlanıp tanımlanmadığını bilmenin yolu, tüm visitMethod() çağrılarını dinlemektir ve her çağrıda yöntem adını kontrol etmektir. Tüm yöntemler ziyaret edildikten sonra visitEnd() yöntemi çağrılır, bu nedenle o zamana kadar hiçbir yöntem ziyaret edilmediyse, yeni bir yöntem oluşturmamız gerektiğini biliyoruz.
Byteların [] formatında bir orignal sınıf var varsayarsak, istenen dönüşümü böyle yapılabilir:
import org.objectweb.asm.*;
import static org.objectweb.asm.Opcodes.*;
public static byte[] transform(byte[] origClassData) throws Exception {
ClassReader cr = new ClassReader(origClassData);
final ClassWriter cw = new ClassWriter(cr, Opcodes.ASM4);
// add the static final fields
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "FIRST", "LExample;", null, null).visitEnd();
cw.visitField(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, "SECOND", "LExample;", null, null).visitEnd();
// wrap the ClassWriter with a ClassVisitor that adds the static block to
// initialize the above fields
ClassVisitor cv = new ClassVisitor(ASM4, cw) {
boolean visitedStaticBlock = false;
class StaticBlockMethodVisitor extends MethodVisitor {
StaticBlockMethodVisitor(MethodVisitor mv) {
super(ASM4, mv);
}
public void visitCode() {
super.visitCode();
// here we do what the static block in the java code
// above does i.e. initialize the FIRST and SECOND
// fields
// create first instance
super.visitTypeInsn(NEW, "Example");
super.visitInsn(DUP);
super.visitInsn(ICONST_1); // pass argument 1 to constructor
super.visitMethodInsn(INVOKESPECIAL, "Example", "<init>", "(I)V");
// store it in the field
super.visitFieldInsn(PUTSTATIC, "Example", "FIRST", "LExample;");
// create second instance
super.visitTypeInsn(NEW, "Example");
super.visitInsn(DUP);
super.visitInsn(ICONST_2); // pass argument 2 to constructor
super.visitMethodInsn(INVOKESPECIAL, "Example", "<init>", "(I)V");
super.visitFieldInsn(PUTSTATIC, "Example", "SECOND", "LExample;");
// NOTE: remember not to put a RETURN instruction
// here, since execution should continue
}
public void visitMaxs(int maxStack, int maxLocals) {
// The values 3 and 0 come from the fact that our instance
// creation uses 3 stack slots to construct the instances
// above and 0 local variables.
final int ourMaxStack = 3;
final int ourMaxLocals = 0;
// now, instead of just passing original or our own
// visitMaxs numbers to super, we instead calculate
// the maximum values for both.
super.visitMaxs(Math.max(ourMaxStack, maxStack), Math.max(ourMaxLocals, maxLocals));
}
}
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
if (cv == null) {
return null;
}
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if ("<clinit>".equals(name) && !visitedStaticBlock) {
visitedStaticBlock = true;
return new StaticBlockMethodVisitor(mv);
} else {
return mv;
}
}
public void visitEnd() {
// All methods visited. If static block was not
// encountered, add a new one.
if (!visitedStaticBlock) {
// Create an empty static block and let our method
// visitor modify it the same way it modifies an
// existing static block
MethodVisitor mv = super.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
mv = new StaticBlockMethodVisitor(mv);
mv.visitCode();
mv.visitInsn(RETURN);
mv.visitMaxs(0, 0);
mv.visitEnd();
}
super.visitEnd();
}
};
// feed the original class to the wrapped ClassVisitor
cr.accept(cv, 0);
// produce the modified class
byte[] newClassData = cw.toByteArray();
return newClassData;
}
soru tam olarak nihai hedef ne olduğu ileri göstergeler vermedi beri, Örnek sınıf durumunuz için çalışmak için kodlanmış temel bir örnekle devam etmeye karar verdik. Dönüştürülmüş sınıfın örneklerini oluşturmak isterseniz, bunun yerine dönüştürülmüş olan sınıfın tam sınıf adını kullanmak için yukarıdaki "Örnek" i içeren tüm dizeleri değiştirmeniz gerekir. Veya her dönüştürülmüş sınıfta Örnek sınıfının iki örneğini özellikle istiyorsanız, yukarıdaki örnek olduğu gibi çalışır.
Bu java mı? Soru manen-montaj-eklenti ile ilgili mi? Sonra bunu etiketleyin. –