2012-04-15 123 views
0

我試圖如何用java ASM生成類文件?

ClassWriter t = new ClassWriter(0); 

    t.visitSource("testing.java", null); 

    t.visitEnd(); 

    byte d[] = t.toByteArray(); 

    FileOutputStream p = null; 

    try 
    { 
     p = new FileOutputStream("testing.class"); 
    } 
    catch (FileNotFoundException e) 
    { 
     e.printStackTrace(); 
    } 

    try 
    { 
     p.write(d); 
    } 
    catch (IOException e) 
    { 
     e.printStackTrace(); 
    } 

而且testing.java中的文字是:

public class testing 
{ 
    public static void main(String args[]) 
    { 
     System.out.println("Works!"); 
    } 
} 

然而,當我試圖運行的類文件,它給了我這個錯誤:

Exception in thread "main" java.lang.UnsupportedClassVersionError: testing : Unsupported major.minor version 0.0 
at java.lang.ClassLoader.defineClass1(Native Method) 
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631) 
at java.lang.ClassLoader.defineClass(ClassLoader.java:615) 
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141) 
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283) 
at java.net.URLClassLoader.access$000(URLClassLoader.java:58) 
at java.net.URLClassLoader$1.run(URLClassLoader.java:197) 
at java.security.AccessController.doPrivileged(Native Method) 
at java.net.URLClassLoader.findClass(URLClassLoader.java:190) 
at java.lang.ClassLoader.loadClass(ClassLoader.java:306) 
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) 
at java.lang.ClassLoader.loadClass(ClassLoader.java:247) 

我該如何修復它,以便類文件輸出「Works!」到控制檯?

編輯:

我不希望它有訪問的jdk文件! (< - 例如javax.tools)這就是爲什麼我試圖讓ASM工作。

+1

您似乎正在編譯一個版本的Java並以較低版本運行。 – 2012-04-15 01:46:33

+0

您還沒有關閉流,請在完成後調用p.close() – Cristian 2012-04-15 01:55:45

回答

3

我相信問題是,圖書館期望一定數量的某些方法將被調用,我相信你沒有足夠的方法讓它產生一個完整的類。

我建議你使用ASMifier來生成一些模板。


您以某種方式破壞了文件。沒有版本0.0

+0

這就是它的生成方式。我錯了嗎? – 2012-04-15 19:31:43

+0

添加了一個關於我認爲是錯誤的編輯。 – 2012-04-15 20:06:17

+0

@PeterLawrey如您所說,在任何其他訪問*()方法之前,必須始終調用ClassWriter#visit()。 – LppEdd 2017-11-25 23:55:57

0

您可以從您的源代碼調用Java編譯器來編譯任何Java源代碼到類文件。編譯器是用Java本身編寫的,也是標準jdk發行版的一部分。嘗試尋找一個名爲javac的類。

4

似乎您正試圖將Java源文件編譯爲類文件。這可以通過Java編譯器 - javac命令行程序或javax.tools package中的工具完成。

ASM是用於不同的目的。 ASM可以用來創建類文件,無需任何源代碼。閱讀ASM's documentation以瞭解Java字節碼以及如何使用ASM生成和讀取它。

下面是如何使用javax.tools包編譯文件。或者你可以使用Process來調用命令行工具。檢查其他參數的文件 - 什麼classpath中使用,在哪裏寫的文件等

import javax.tools.JavaCompiler; 
import javax.tools.ToolProvider; 

public class TestingCompile { 
    public static void main(String[] args) { 
     JavaCompiler javac = ToolProvider.getSystemJavaCompiler(); 
     int result = javac.run(null, null, null, "C:\\path\\to\\Testing.java"); 
     if (result != 0) { 
      throw new RuntimeException("compile failed: exit " + result); 
     } 
    } 
} 

下面是如何創建使用ASM相同的類文件,而無需使用源文件。我很確定這不是你想要做的 - 否則你不會問這個問題。 ;)

這只是ASMifierClassVisitor的輸出,所以字節仍然需要寫入文件或動態加載到類加載器中。我使用了-debug參數,這樣ASMifier將顯示源文件名和行號(visitSource,visitLineNumbervisitLocalVariable調用是可選的,因此如果不需要調試信息,可以省略它們和相關標籤)。

import org.objectweb.asm.*; 

public class TestingDump implements Opcodes { 

    public static byte[] dump() throws Exception { 

     ClassWriter cw = new ClassWriter(0); 
     FieldVisitor fv; 
     MethodVisitor mv; 
     AnnotationVisitor av0; 

     cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, "Testing", null, "java/lang/Object", null); 

     cw.visitSource("Testing.java", null); 

     { 
      mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 
      mv.visitCode(); 
      Label l0 = new Label(); 
      mv.visitLabel(l0); 
      mv.visitLineNumber(1, l0); 
      mv.visitVarInsn(ALOAD, 0); 
      mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V"); 
      mv.visitInsn(RETURN); 
      Label l1 = new Label(); 
      mv.visitLabel(l1); 
      mv.visitLocalVariable("this", "LTesting;", null, l0, l1, 0); 
      mv.visitMaxs(1, 1); 
      mv.visitEnd(); 
     } 
     { 
      mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null); 
      mv.visitCode(); 
      Label l0 = new Label(); 
      mv.visitLabel(l0); 
      mv.visitLineNumber(3, l0); 
      mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;"); 
      mv.visitLdcInsn("Works!"); 
      mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V"); 
      Label l1 = new Label(); 
      mv.visitLabel(l1); 
      mv.visitLineNumber(4, l1); 
      mv.visitInsn(RETURN); 
      Label l2 = new Label(); 
      mv.visitLabel(l2); 
      mv.visitLocalVariable("args", "[Ljava/lang/String;", null, l0, l2, 0); 
      mv.visitMaxs(2, 1); 
      mv.visitEnd(); 
     } 
     cw.visitEnd(); 

     return cw.toByteArray(); 
    } 
}