1

我试图在运行时在 eclipse 中编译和运行一个 java 类,它使用一个外部 jar 示例:在这种情况下是 JSON 库。

我已经成功编译了 java 代码,但是当我尝试调用该方法时,它给了我以下错误java.lang.reflect.InvocationTargetException

当我将所需的 jar 添加到 eclipse 的构建路径时,它工作正常。我不想将 jar 添加到 eclipse 的 buildPath,因为它需要从外部路径加载 jar 以及构建eclipse中提供的路径。

在运行时在 JAVACompiler 中调用包含外部 jar 的类时,有什么方法可以添加外部 jar 路径?

请在这个问题上帮助我。

这是要在运行时编译和运行的具有外部 jar 的类。

import org.json.JSONArray;
import org.json.JSONObject;

public class JSONPRINTERCLASS{
    public void printJson() {
        System.out.println("In the printJson method of JSONPRINTERCLASS class");

        String json = "[{\"Name\":\"Prakhar Agrawal\",\"Email\":\"155@abc.com\"},{\"Name\":\"Rahul Dhakad\",\"Email\":\"RD@qwerty.com\"}]";

        JSONArray array = new JSONArray(json);
        for(Object obj : array) {
            JSONObject jsonObj = (JSONObject)obj;
            System.out.println("jsonObj = "+jsonObj);
            System.out.println("============================================");
            System.out.println("Name = "+jsonObj.get("Name"));
            System.out.println("Email = "+jsonObj.get("Email"));

        }
    }
    public static void main(String as[]) {
        System.out.println("In the main method of JSONPRINTERCLASS class");
        new JSONPRINTERCLASS().printJson();
    }



}

这是我正在运行以编译 JSONPRINTERCLASS 的类

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class StackInLineCompiler {

    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder(64);

        StringBuilder stringbuff = new StringBuilder();
        try {
            InputStream is = new FileInputStream(
                    "/home/ist/Oxygen_workspace/NewProject/testcompile/JSONPRINTERCLASS.java");
            BufferedReader buf = new BufferedReader(new InputStreamReader(is));
            String line = buf.readLine();

            while (line != null) {
                stringbuff.append(line).append("\n");

                line = buf.readLine();
            }
        } catch (Exception e) {
            System.out.println();
            e.printStackTrace();
        }

        String fileAsString = stringbuff.toString();
        System.out.println("Contents : " + fileAsString);

        // Read more:
        // http://javarevisited.blogspot.com/2015/09/how-to-read-file-into-string-in-java-7.html#ixzz58OfOY4Rr

        File helloWorldJava = new File("/home/ist/Oxygen_workspace/NewProject/testcompile/JSONPRINTERCLASS.java");
        if (helloWorldJava.getParentFile().exists() || helloWorldJava.getParentFile().mkdirs()) {

            try {
                Writer writer = null;
                try {
                    writer = new FileWriter(helloWorldJava);
                    writer.write(sb.toString());
                    writer.flush();
                } finally {
                    try {
                        writer.close();
                    } catch (Exception e) {
                    }
                }

                /**
                 * Compilation Requirements
                 *********************************************************************************************/
                DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
                JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
                StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);

                // This sets up the class path that the compiler will use.
                // I've added the .jar file that contains the DoStuff interface within in it...
                List<String> optionList = new ArrayList<String>();
                optionList.add("-classpath");
                optionList.add(System.getProperty("java.class.path")
                        + ":/home/ist/Downloads/jar_To_compile/jar/json-20160810.jar");

                System.out.println("optionList = " + optionList);
                Iterable<? extends JavaFileObject> compilationUnit = fileManager
                        .getJavaFileObjectsFromFiles(Arrays.asList(helloWorldJava));
                JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, optionList, null,
                        compilationUnit);
                /*********************************************************************************************
                 * Compilation Requirements
                 **/
                if (task.call()) {
                    /**
                     * Load and execute
                     *************************************************************************************************/
                    System.out.println("Yipe");
                    try {
                        // Create a new custom class loader, pointing to the directory that contains the
                        // compiled
                        // classes, this should point to the top of the package structure!
                        URLClassLoader classLoader = new URLClassLoader(new URL[] { new File("./").toURI().toURL() });
                        // Load the class from the classloader by name....
                        Class<?> loadedClass = classLoader.loadClass("JSONPRINTERCLASS");
                        // Create a new instance...
                        Method declaredMethod = loadedClass.getDeclaredMethod("printJson");
                        // Santity check
                        System.out.println(
                                "Object Loaded Successfully...Now to call the method = " + declaredMethod.getName());
                        declaredMethod.invoke(loadedClass.newInstance(), null);
                        System.out.println("after invoking the method...........");
                    } catch (Exception e) {
                        System.out.println("In the exception while calling the method = " + e);
                    }

                    //
                    // }
                    /*************************************************************************************************
                     * Load and execute
                     **/
                } else {
                    System.out.println("In the error");
                    for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
                        System.out.format("Error on line %d in %s%n", diagnostic.getLineNumber(),
                                diagnostic.getSource().toUri());
                    }
                }
                fileManager.close();
            } catch (IOException exp) {
                exp.printStackTrace();
            }
        }
    }

}

最后是@AL4建议的更改后的代码

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Stream;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class StackInLineCompiler {

    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder(64);

        StringBuilder stringbuff = new StringBuilder();
        try {
            InputStream is = new FileInputStream(
                    "/home/ist/Oxygen_workspace/NewProject/testcompile/JSONPRINTERCLASS.java");
            BufferedReader buf = new BufferedReader(new InputStreamReader(is));
            String line = buf.readLine();

            while (line != null) {
                stringbuff.append(line).append("\n");

                line = buf.readLine();
            }
        } catch (Exception e) {
            System.out.println();
            e.printStackTrace();
        }

        String fileAsString = stringbuff.toString();
        System.out.println("Contents : " + fileAsString);

        // Read more:
        // http://javarevisited.blogspot.com/2015/09/how-to-read-file-into-string-in-java-7.html#ixzz58OfOY4Rr

        File helloWorldJava = new File("/home/ist/Oxygen_workspace/NewProject/testcompile/JSONPRINTERCLASS.java");
        File parentFile = helloWorldJava.getParentFile();

        final File jsonJarFile = new File("/home/ist/Downloads/jar_To_compile/jar/json-20160810.jar");

            try {


                /**
                 * Compilation Requirements
                 *********************************************************************************************/
                DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<JavaFileObject>();
                JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
                StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);

                // This sets up the class path that the compiler will use.
                // I've added the .jar file that contains the DoStuff interface within in it...
                List<String> optionList = new ArrayList<String>();

//              optionList.add("classpath");
//              
//              optionList.add(System.getProperty("classpath")
//                      + File.pathSeparator + jsonJarFile.getAbsolutePath());

                System.out.println("jar file path = "+jsonJarFile.getAbsolutePath());

                optionList.add("-classpath");
                optionList.add(System.getProperty("java.class.path")
                        + File.pathSeparator + jsonJarFile.getAbsolutePath());

                for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
                    System.out.println(diagnostic.getCode());
                    System.out.println(diagnostic.getKind());
                    System.out.println(diagnostic.getPosition());
                    System.out.println(diagnostic.getStartPosition());
                    System.out.println(diagnostic.getEndPosition());
                    System.out.println(diagnostic.getSource());
                    System.out.println(diagnostic.getMessage(null));
                }

                System.out.println("Now loading the jars at runtime");

                URLClassLoader classLoader = new URLClassLoader(Stream
                        .of(parentFile, jsonJarFile)
                        .filter(Objects::nonNull)
                        .map(StackInLineCompiler::toUrl)
                        .toArray(URL[]::new));



                ///////////////////////////////////////////////////////////////////////////////////////
//              
                System.out.println ("Success!");

//               
                 System.out.println("Jars loaded succesfully....");

                System.out.println("optionList = " + optionList);
                Iterable<? extends JavaFileObject> compilationUnit = fileManager
                        .getJavaFileObjectsFromFiles(Arrays.asList(helloWorldJava));
                JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, optionList, null,
                        compilationUnit);
                /*********************************************************************************************
                 * Compilation Requirements
                 **/
//              if (task.call()) {
                if (task.call()) {
                    /**
                     * Load and execute
                     *************************************************************************************************/
                    System.out.println("Yipe");
                    try {
                        // Create a new custom class loader, pointing to the directory that contains the
                        // compiled
                        // classes, this should point to the top of the package structure!
//                      URLClassLoader classLoader = new URLClassLoader(new URL[] { new File("./").toURI().toURL() });
                        Class<?> loadedClass = Class.forName("JSONPRINTERCLASS", true, classLoader);

                        Method declaredMethod = loadedClass.getDeclaredMethod("printJson");
                        // Santity check
                        System.out.println(
                                "Object Loaded Successfully...Now to call the method = " + declaredMethod.getName());


                        declaredMethod.invoke(loadedClass.newInstance(), null);
                        System.out.println("after invoking the method...........");
                    } catch (Exception e) {
                        System.out.println("In the exception while calling the method = " + e);
                    }

                    //
                    // }
                    /*************************************************************************************************
                     * Load and execute
                     **/
                } else {
                    System.out.println("In the error");
                    for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics.getDiagnostics()) {
                        System.out.format("Error on line %d in %s%n", diagnostic.getLineNumber(),
                                diagnostic.getSource().toUri());
                    }
                }
                fileManager.close();
            } catch (IOException exp) {
                exp.printStackTrace();
            }
//      }
    }

    // helper method
    static URL toUrl(File f) {
        try {
            return f.toURI().toURL();
        } catch (Exception e) {
            throw new RuntimeException(String.valueOf(f), e);
        }
    }

//  private static final Class<?>[] parameters = new Class[] { URL.class };

    /**
     * Adds a file to the classpath.
     * 
     * @param s
     *            a String pointing to the file
     * @throws IOException
     */
    /*public static void addFile(String s) throws IOException {
        File f = new File(s);
        addFile(f);
    }*/

    /**
     * Adds a file to the classpath
     * 
     * @param f
     *            the file to be added
     * @throws IOException
     */
    /*public static void addFile(File f) throws IOException {
        addURL(f.toURI().toURL());
    }*/

    /**
     * Adds the content pointed by the URL to the classpath.
     * 
     * @param u
     *            the URL pointing to the content to be added
     * @throws IOException
     */
    /*public static void addURL(URL u) throws IOException {
        URLClassLoader sysloader = (URLClassLoader) ClassLoader.getSystemClassLoader();
        Class<?> sysclass = URLClassLoader.class;
        try {
            Method[] methodarray = sysclass.getDeclaredMethods();
            for (Method method : methodarray) {

                System.out.println("Method name = " + method.getName());
                method.setAccessible(true);
            }

        } catch (Throwable t) {
            t.printStackTrace();
            throw new IOException("Error, could not add URL to system classloader");
        }
    }*/

}

但我仍然得到

java.lang.Error:未解决的编译问题:JSONArray 无法解析为类型 JSONArray 无法解析为类型 JSONObject 无法解析为类型 JSONObject 无法解析为 JSONPRINTERCLASS.printJson(JSONPRINTERCLASS.java:20) 处的类型JSONPRINTERCLASS.(JSONPRINTERCLASS.java:7) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) 在 sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) ) 在 java.lang.reflect.Constructor.newInstance(Constructor.java:423) 在 java.lang.Class.newInstance(Class.java:442) 在 StackInLineCompiler.main(StackInLineCompiler.java:137)

请帮忙

4

1 回答 1

0

您的代码有几个缺陷:

  1. 它读取 jar 文件的内容,这是绝对没有必要的
  2. 它不检查 parentFile 是否为空。
  3. 它通过向源文件写入一个空的 StringBuilder 来删除源文件的内容。
  4. 它用于:设置不可移植的编译类路径(不适用于 Windows)。
  5. 它不检查diagnostics对象以查看编译时是否有错误。
  6. 不正确,URLClassload是在运行时类路径中设置唯一的当前工作目录,你需要的是.class编译源文件的位置(parentFile)和jar文件的位置(jar文件本身)
  7. 它不会初始化加载的类

怎么修

  1. 摆脱这段代码
  2. 只需获取父文件并将其保存以备后用,您将需要它来设置运行时类路径

    File helloWorldJava = new File("java_sources/JSONPRINTERCLASS.java");
    File parentFile = helloWorldJava.getParentFile();
    
  3. 摆脱这段代码

  4. 用户 File.pathSeparator 获取系统特定的路径分隔符,对于 unix 是:,对于 windows 是;

    // define as constant
    private final static File jsonJarFile = new File("3rdparty/json-20180130.jar");
    

    像这样设置你的编译类路径:

    optionList.add(System.getProperty("java.class.path")
                + File.pathSeparator + jsonJarFile.getAbsolutePath());
    
  5. 检查诊断对象的编译问题

    for (Diagnostic diagnostic : diagnostics.getDiagnostics()) {
        System.out.println(diagnostic.getCode());
        System.out.println(diagnostic.getKind());
        System.out.println(diagnostic.getPosition());
        System.out.println(diagnostic.getStartPosition());
        System.out.println(diagnostic.getEndPosition());
        System.out.println(diagnostic.getSource());
        System.out.println(diagnostic.getMessage(null));
    }
    
  6. 正确设置运行时类路径

    在运行时在 JAVACompiler 中调用包含外部 jar 的类时,有什么方法可以添加外部 jar 路径?

    URLClassLoader classLoader = new URLClassLoader(Stream
        .of(parentFile, jsonJarFile)
        .filter(Objects::nonNull)
        .map(StackInLineCompiler::toUrl)
        .toArray(URL[]::new));
    
    // helper method
    public static URL toUrl(File f) {
        try {
            return f.toURI().toURL();
        } catch (Exception e) {
            throw new RuntimeException(String.valueOf(f), e);
        }
    }
    
  7. 加载和初始化类

    Class<?> loadedClass = Class.forName("JSONPRINTERCLASS", true, classLoader);
    

应用这些步骤后,您应该能够运行printJson应该输出的方法:

In the printJson method of JSONPRINTERCLASS class
jsonObj = {"Email":"155@abc.com","Name":"Prakhar Agrawal"}
============================================
Name = Prakhar Agrawal
Email = 155@abc.com
jsonObj = {"Email":"RD@qwerty.com","Name":"Rahul Dhakad"}
============================================
Name = Rahul Dhakad
Email = RD@qwerty.com
于 2018-02-28T14:46:09.440 回答