2011-02-18 13 views
11

मुझे मौजूदा कक्षाओं से नई कक्षाएं (जावा बाइट कोड की पीढ़ी के माध्यम से) उत्पन्न करने की आवश्यकता है। मैं कक्षा के तरीकों के शरीर (अभिव्यक्ति) का विश्लेषण करूंगा। अभिव्यक्ति निर्धारित करेंगे कि मैं कौन सा कोड उत्पन्न करूंगा।रेखा संख्याओं को नियंत्रित करते समय क्या बाइटकोड लाइब्रेरी?

मेरे लिए यह नई कक्षाओं (बेस जावा फ़ाइल के समान) के लिए स्रोत फ़ाइल सेट करने के साथ-साथ लाइन नंबरों को नियंत्रित करने के लिए आयात फ़ाइल आयात करने के लिए आयात किया जाता है (जब अपवाद को फेंक दिया जाता है तो स्टैकट्रैक में आधार जावा फ़ाइल की रेखा संख्या होनी चाहिए)।

उदाहरण: मेरे पास फ़ाइल BaseClass.java है। संकलक इस से BaseClass.class उत्पन्न करता है। मैं इस कक्षा फ़ाइल का विश्लेषण करना चाहता हूं और जेनरेट क्लास.क्लास के लिए बाइट कोड उत्पन्न करना चाहता हूं। जब सी पर एक अपवाद फेंक दिया जाता है तो स्टैकट्रैक में "BaseClass.java लाइन 3" होना चाहिए।

BaseClass.java 
1: class BaseClass { 
2: void method() { 
3:  call(); 
4: } 
5:} 

GeneratesClaas.class 
a: class GeneratedClass { 
b: void generatedMethod() { 
c:  generatedCall(); 
d: } 
e:} 

मेरा प्रश्न: क्या इस आवश्यकता का समर्थन करने वाले पुस्तकालय हैं? जावासिस्ट, एएसएम या बीसीईएल? इस उद्देश्य के लिए क्या उपयोग करें? संकेत यह कैसे करें या उदाहरण कोड विशेष रूप से सहायक होगा।

संपादित करें: संकेत क्या पुस्तकालय का उपयोग करने के लिए नहीं है, क्योंकि आवश्यकता नहीं fullfiled जा सकती है मददगार भी हो सकता है :)।

+0

अधिकांश डीकम्पाइलर कोड में प्रिंटआउट कर सकते हैं (टिप्पणियां) जहां कोड के मूल लाइनों थे। आप इसे पार्स कर सकते हैं और कोड को पुनर्व्यवस्थित कर सकते हैं। आपको जो समस्या मिल सकती है वह यह है कि विघटित कोड एक ही क्रम में नहीं हो सकता है क्योंकि यह बिल्कुल वही नहीं है। –

+0

डीकंपलर नहीं हैं जो मैं कर रहा हूं। मुझे नया बाइट कोड उत्पन्न करने के लिए रनटाइम पर इस जानकारी की आवश्यकता है। – Arne

उत्तर

5

asm के साथ, आप उत्पन्न कक्षा में इस डीबगिंग जानकारी को बनाने के लिए visitSource और visitLineNumber विधियों का उपयोग कर सकते हैं।

संपादित करें:

import java.io.File; 
import org.objectweb.asm.Label; 
import org.objectweb.asm.MethodVisitor; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import org.objectweb.asm.ClassWriter; 
import org.objectweb.asm.util.CheckClassAdapter; 
import static org.objectweb.asm.Opcodes.*; 

public class App { 
    public static void main(String[] args) throws IOException { 
     ClassWriter cw = new ClassWriter(0); 
     CheckClassAdapter ca = new CheckClassAdapter(cw); 
     ca.visit(V1_5, ACC_PUBLIC + ACC_SUPER, "test/Test", null, "java/lang/Object", null); 
     ca.visitSource("this/file/does/not/exist.txt", null); // Not sure what the second parameter does 
     MethodVisitor mv = ca.visitMethod(ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); 

     mv.visitCode(); 
     Label label = new Label(); 
     mv.visitLabel(label); 
     mv.visitLineNumber(123, label); 
     mv.visitTypeInsn(NEW, "java/lang/RuntimeException"); 
     mv.visitInsn(DUP); 
     mv.visitMethodInsn(INVOKESPECIAL, "java/lang/RuntimeException", "<init>", "()V"); 
     mv.visitInsn(ATHROW); 
     mv.visitInsn(RETURN); 
     mv.visitMaxs(2, 1); 
     mv.visitEnd(); 

     ca.visitEnd(); 

     File target = new File("target/classes/test/"); 
     target.mkdirs(); 
     FileOutputStream out = new FileOutputStream(new File(target, "Test.class")); 
     out.write(cw.toByteArray()); 
     out.close(); 
    } 
} 

चल रहा है यह एक वर्ग एक मुख्य विधि फेंकता है कि एक RuntimeException सिर्फ स्टैक ट्रेस में लाइन नंबर देखने के लिए युक्त उत्पन्न करता है: यहाँ एक न्यूनतम उदाहरण है। सबसे पहले देखते हैं कि क्या एक disassembler इस का बना देता है की सुविधा देता है:

$ javap -classpath target/classes/ -c -l test.Test 
Compiled from "this.file.does.not.exist.txt" 
public class test.Test extends java.lang.Object{ 
public static void main(java.lang.String[]); 
    Code: 
    0: new #9; //class java/lang/RuntimeException 
    3: dup 
    4: invokespecial #13; //Method java/lang/RuntimeException."<init>":()V 
    7: athrow 
    8: return 

    LineNumberTable: 
    line 123: 0 
} 

तो इस वर्ग के एक txt फ़ाइल जो मौजूद नहीं है :) से संकलित किया गया था, LineNumberTable कहते बाईटकोड से शुरू 0 इस काल्पनिक के 123 लाइन से मेल खाती है ऑफसेट कि फ़ाइल। इस फाइल चल रहा है पता चलता है कि इस फाइल और LineNumber भी स्टैक ट्रेस में निहित है:

$ java -cp target/classes/ test.Test 
Exception in thread "main" java.lang.RuntimeException 
     at test.Test.main(this/file/does/not/exist.txt:123) 
2

बीसीईएल में कक्षाएं संख्या और लाइन नम्बरटेबल है जो क्लासफ़ाइल में लाइन नंबर की जानकारी का प्रतिनिधित्व करती है। इसे देखकर, आप कुछ वर्गों के लिए तालिका बना और सेट कर सकते हैं जिन्हें आप कोड उत्पन्न कर रहे हैं। संभवतः, जानकारी कक्षा फ़ाइल में लिखी जाती है।

संबंधित मुद्दे