具有动态生成和编译的源代码的ClassNotFoundException

时间:2015-06-27 00:18:42

标签: java file

以下代码正常工作但在某些情况下Class.forName方法访问文件时会抛出ClassNotFoundException,因为文件未完全写入,我通过增加睡眠时间解决了这些问题。

但是我想要一种强制线程休眠的方式,直到文件完全写入而不是静态sleep(5000)

public void run(String className, String code) {
    String pkgname = "pkg" + (int) (Math.random() * 10000);
    String sb = "";
    sb += "package " + pkgname + ";\n";
    sb += code;

    File javaFile = new File(serverPath + pkgname + "/" + className + ".java");
    if (javaFile.getParentFile()
            .exists() || javaFile.getParentFile().mkdirs()) {
                try {
                FileWriter writer = new FileWriter(javaFile);
                writer.write(sb);
                writer.flush();
                writer.close();
                try {
                    Thread.sleep(5000);// here is the problem 
                } catch (InterruptedException ex) {
                    Logger.getLogger(InlineCompiler.class.getName()).log(Level.SEVERE, null, ex);
                }
                JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
                int compilationResult = compiler.run(null, null, null, javaFile.getPath());
                try {
                    String[] params = new String[0];
                    Method method = Class.forName(pkgname + "." + className).getMethod("main", String[].class);
                    method.invoke(null, (Object) params);

                } catch (NoSuchMethodException | SecurityException | IllegalArgumentException | InvocationTargetException | IllegalAccessException ex) {
                    Logger.getLogger(InlineCompiler.class.getName()).log(Level.SEVERE, null, ex);

                }

            } catch (IOException | ClassNotFoundException exp) {
                Logger.getLogger(InlineCompiler.class.getName()).log(Level.SEVERE, null, exp);

            }
}}

再次:我的问题不是代码的逻辑,也不是动态编译和执行文件的逻辑,但它只与休眠时间有关。

当我将睡眠减少到2000时的例外

    Jun 27, 2015 3:06:28 AM compile.InlineCompiler run
SEVERE: null
java.lang.ClassNotFoundException: pkg5958.test
    at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
    at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
    at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
    at java.lang.Class.forName0(Native Method)
    at java.lang.Class.forName(Class.java:259)
    at compile.InlineCompiler.run(InlineCompiler.java:49)

1 个答案:

答案 0 :(得分:0)

编写文件不是问题:

java.lang.ClassNotFoundException: pkg5958.test表示运行时试图引用的名为test的包中的某个名为pkg5989的类不在类路径上。这与Thread.sleep()无关。

您生成.class文件的目录在类路径上不是

  

我无法重现你的问题,我想不到。   这是有效的,并且没有一次调用Thread.sleep()

Q31083880.java

import javax.annotation.Nonnull;
import javax.tools.JavaCompiler;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Enumeration;

public class Q31083880
{
    public static int compile(@Nonnull final File file)
    {
        final JavaCompiler c = ToolProvider.getSystemJavaCompiler();
        return c.run(null, null, null, file.getAbsolutePath());
    }

    public static void invoke(@Nonnull final String name)
    {
        try
        {
            final URLClassLoader cl = (URLClassLoader) ClassLoader.getSystemClassLoader();
            final Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class);
            method.setAccessible(true);
            final File f = new File(System.getProperty("user.home"));
            method.invoke(cl, f.toURI().toURL());
            final Method m;
            try
            {
                m = Class.forName(name).getMethod("main", String[].class);
            }
            catch (ClassNotFoundException e)
            {
                throw new RuntimeException(e);
            }
            final String[] args = new String[0];
            m.invoke(null, new Object[]{args});
        }
        catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException | MalformedURLException e)
        {
            throw new RuntimeException(e);
        }
    }

    public static void main(final String[] args)
    {
        final File f = new File(System.getProperty("user.home"), "Test.java");
        try
        {
            final FileWriter fw = new FileWriter(f);
            try
            {
                final String source = "public class Test { public static void main(String[] args) { System.out.println(\"Testing\"); } }";
                fw.write(source);
            }
            catch (IOException e)
            {
                throw new RuntimeException(e);
            }
            finally
            {
                try { fw.close(); } catch (final IOException e) { System.err.println(e.getMessage()); }
            }
            System.out.println(compile(f));
            invoke("Test");
        }
        catch (IOException e)
        {
            throw new RuntimeException(e);
        }
    }
}

这会编译为System.getProperty("user.home");作为示例。

读者改变这种行为是一种练习,应该很容易。