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

时间:2018-02-28 13:33:52

标签: java runtime-compilation

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

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

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

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

请帮助解决此问题

1 个答案:

答案 0 :(得分:0)

您的代码存在一些缺陷:

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

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

      .class
    3. 摆脱此代码

    4. 用户File.pathSeparator获取系统特定的路径分隔符,对于unix,它是File helloWorldJava = new File("java_sources/JSONPRINTERCLASS.java"); File parentFile = helloWorldJava.getParentFile(); ,对于windows,它是:

      ;

      设置你的编译类路径:

      // define as constant
      private final static File jsonJarFile = new File("3rdparty/json-20180130.jar");
      
    5. 检查诊断对象是否存在编译问题

      optionList.add(System.getProperty("java.class.path")
                  + File.pathSeparator + jsonJarFile.getAbsolutePath());
      
    6. 正确设置运行时类路径

        

      在JAVACompiler中调用运行时包含外部jar的类时,有没有办法添加外部jar路径?

      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));
      }
      
    7. 加载并初始化类

      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);
          }
      }
      
    8. 应用这些步骤后,您应该能够运行应输出的方法Class<?> loadedClass = Class.forName("JSONPRINTERCLASS", true, classLoader);

      printJson