2

文字列を .java ファイルに書き込み、javax.toolsその .java ファイルを .class ファイルにコンパイルするために使用するプログラムがあります。次に、変更された ClassLoader を使用してクラスのインスタンスを取得しようとしRunnableます (バイトに変換することにより)。配列を使用ClassLoader.defineClassしてインスタンスを取得します)。しかし、私は問題を抱えています。プログラムがクラスのインスタンスを取得しようとすると、それが正しい方法でコンパイルされていないことがわかります。を取得ClassFormatErrorしますIncompatible magic value 1885430635 in class file <Unknown>。これが私の(現時点ではかなりずさんな)コードです:

import java.io.*;
import java.security.SecureClassLoader;

public class EnhancedClassLoader extends SecureClassLoader
{
    public Object createObjectFromFile(String fileName) throws 
    InstantiationException, IOException, IllegalAccessException
    {
        File file = new File(fileName);
        definePackage("compClassPack", null, null, null, null, null, null, file.toURI().toURL());
        byte[] classBytes = null;
        //ReadFileToByteArray
        {
            FileInputStream fis = new FileInputStream(file);
            int size = (int)file.length();
            classBytes = new byte[size];
            int offset = 0;
            int readed;
            while (offset < size && (readed = fis.read(classBytes, offset, size - offset)) != -1)
            {
                offset += readed;
            }
        fis.close();
        }
        Class<?> clazz = defineClass(null, classBytes, 0, classBytes.length);
            //The error is thrown here! ^^^

        return clazz.newInstance();
    }
}

.

import java.io.*;
import javax.tools.*;

public class Main
{
    public static void main(String[] args)throws Exception
    {
        File file = new File("Sample.java");
        FileWriter fw = new FileWriter(file);
        BufferedWriter bw = new BufferedWriter(fw);

        String code =
                "package compClassPack;\n" +
                "public class Sample implements Runnable\n" +
                "{\n" +
                "    public Sample(){}\n\n" +
                "    public static void main(String[] args)\n" +
                "    {\n" +
                "        new Sample().run();\n" +
                "    }\n\n" +
                "    public void run()\n" +
                "    {\n" +
                "        System.out.println(\"It worked! :D\");\n" +
                "    }\n" +
                "}";

        for(byte ch : code.getBytes())
        {
            if((char)ch!='\n')
                bw.write((char)ch);
            else
                bw.newLine();
        }
        bw.flush();
        bw.close();

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
        Iterable<? extends JavaFileObject> compilationUnits = fileManager.getJavaFileObjects(file);
        JavaCompiler.CompilationTask ct = compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits);
        ct.call();

        for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics())
            System.out.format("Error on line %d in %d%n",
                    diagnostic.getLineNumber(),
                    ((FileObject)diagnostic.getSource()).toUri());

        fileManager.close();

        EnhancedClassLoader loader = new EnhancedClassLoader();
        Runnable runs = (Runnable) loader.createObjectFromFile(file.getAbsolutePath());
        runs.run(); 
    }
}
4

1 に答える 1

2

あなたのバイト配列は有効なバイトコードではありません。もしそうなら、それは魔法の文字列 (hex) で始まります0xCAFEBABE。代わりに、最初のバイトは1885430635(decimal) で、これは hexであり、一度に 1 バイトを読み取ると、パッケージ宣言の始まりにすぎない0x7061636bASCII 文字が得られます。pack

つまり、テキスト ファイルをあたかもバイトコードであるかのように読み込もうとしており、明らかに Java はそのようなバイト ストリームからクラスを構築できません。

于 2012-12-05T09:20:19.750 に答える