如何在调用.class文件时在运行时提供外部jar

问题描述 投票:1回答:1

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

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

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

有没有办法在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\":\"[email protected]\"},{\"Name\":\"Rahul Dhakad\",\"Email\":\"[email protected]\"}]";

        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)at JSONPRINTERCLASS。(JSONPRINTERCLASS.java:7)at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45 )在StackInLineCompiler.main的java.lang.Class.newInstance(Class.java:442)中的java.lang.reflect.Constructor.newInstance(Constructor.java:423)(StackInLineCompiler.java:137)

请帮忙

java runtime-compilation
1个回答
0
投票

您的代码有几个缺陷:

  1. 它读取jar文件的内容,这绝对不是必需的
  2. 它不检查parentFile是否为null。
  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":"[email protected]","Name":"Prakhar Agrawal"}
============================================
Name = Prakhar Agrawal
Email = [email protected]
jsonObj = {"Email":"[email protected]","Name":"Rahul Dhakad"}
============================================
Name = Rahul Dhakad
Email = [email protected]
© www.soinside.com 2019 - 2024. All rights reserved.