इस उत्तर से पता चलता है कि यह कैसे एएसएम के आगंतुक एपीआई का उपयोग किया जा सकता है (ASM homepage पर एएसएम 4.0 एक जावा बाईटकोड इंजीनियरिंग पुस्तकालय की धारा 2.2 देखें), क्योंकि यह मेरे लिए सबसे परिचित एपीआई। एएसएम में एक ऑब्जेक्ट मॉडल एपीआई भी है (उसी दस्तावेज़ में भाग II देखें) संस्करण जो आमतौर पर इस मामले में उपयोग करना आसान हो सकता है। ऑब्जेक्ट मॉडल काफी हद तक धीमा है क्योंकि यह स्मृति में पूरी कक्षा फ़ाइल का एक पेड़ बनाता है, लेकिन यदि प्रदर्शन की हिट को बदलने की आवश्यकता वाले वर्गों की केवल थोड़ी सी मात्रा नगण्य होनी चाहिए।
static final
फ़ील्ड बनाते समय जिनके मान स्थिरांक (संख्याओं की तरह) नहीं हैं, उनका प्रारंभिक वास्तव में "static initializer block" पर जाता है। ,
public class Example {
public static final Example FIRST;
public static final Example SECOND;
static {
FIRST = new Example(1);
SECOND = new Example(2);
}
...
}
एक जावा फ़ाइल में आप कई तरह के स्थिर {...} ब्लॉक की अनुमति दी जाती है, जबकि कक्षा में फ़ाइलों को केवल वहाँ कर सकते हैं: इस प्रकार, अपने दूसरे (तब्दील) कोड सूची निम्नलिखित जावा कोड के बराबर है एक बने। इस संकल्प को पूरा करने के लिए जावा कंपाइलर स्वचालित रूप से एकाधिक स्थिर ब्लॉक को विलय करता है। बाइटकोड में हेरफेर करते समय इसका मतलब है कि यदि पहले से कोई स्थिर ब्लॉक नहीं है तो हम एक नया बनाते हैं, जबकि यदि पहले से ही एक स्थिर ब्लॉक मौजूद है तो हमें मौजूदा कोड की शुरुआत में हमारे कोड को प्रीपेड करने की आवश्यकता है (प्रीपेडिंग संलग्न करने से आसान है)।
एएसएम के साथ, स्थिर ब्लॉक विशेष नाम <clinit>
के साथ एक स्थिर विधि की तरह दिखता है, जैसे रचनाकार विशेष नाम <init>
के साथ विधियों की तरह दिखते हैं।
विज़िटर एपीआई का उपयोग करते समय, यह जानने का तरीका कि किसी विधि को पहले से परिभाषित किया गया है, सभी विज़िट मोड() कॉल को सुनना और प्रत्येक कॉल में विधि का नाम देखना है। सभी विधियों का दौरा करने के बाद visitEnd() विधि कहा जाता है, इसलिए यदि कोई विधि नहीं देखी गई है, तो हम जानते हैं कि हमें एक नई विधि बनाने की आवश्यकता है।
मान लिया जाये कि हम बाइट [] प्रारूप में एक orignal वर्ग है, अनुरोध किया परिवर्तन इस तरह किया जा सकता है:
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;
}
के बाद से अपने प्रश्न वास्तव में अपने अंतिम लक्ष्य क्या है, इसकी आगे संकेत नहीं दिया, मैं अपने उदाहरण वर्ग मामले के लिए काम करने के लिए हार्ड-कोडेड एक मूल उदाहरण के साथ जाने का फैसला किया। क्या आप कक्षा के रूपांतरित होने के उदाहरण बनाना चाहते हैं, आपको कक्षा के पूर्ण वर्ग नाम का उपयोग करने के लिए उपरोक्त "उदाहरण" वाले सभी तारों को बदलना होगा, वास्तव में इसके बदले में परिवर्तित किया जा रहा है। या यदि आप विशेष रूप से प्रत्येक रूपांतरित वर्ग में उदाहरण वर्ग के दो उदाहरण चाहते हैं, तो उपर्युक्त उदाहरण इस प्रकार काम करता है।
क्या यह जावा है? क्या मेनन-असेंबली-प्लगइन से संबंधित प्रश्न है? फिर इसे इस तरह टैग करें। –