5

我试图通过我使用JShell API创建的 JShell 实例在运行时运行一些 Java 代码。为了演示我的问题,我将分享我的简单代码。

使用我当前的设置,我有一个名为lib的目录,其中包含 MySQL Java 驱动程序:mysql-connector-java-5.1.35.jar

通过命令工具启动 JShell 并将所需的模块添加为:

jshell --module-path lib --add-modules mysql.connector.java

然后加载mysql驱动程序对我有用:

jshell> Class.forName("com.mysql.jdbc.Driver").newInstance();
$1 ==> com.mysql.jdbc.Driver@42f93a98

我创建了一个类似的 Java 9 模块module-info.java

module example.loadmysql {
    requires java.sql;
    requires mysql.connector.java;
    requires jdk.jshell;
}

src/example/loadmysql/Runner.java为:

package example.loadmysql;

import jdk.jshell.*;
import java.sql.*;

public class Runner {
    public static void main(String[] args) throws Exception {
        // this works because this module requires mysql.connector.java
        System.out.println(Class.forName("com.mysql.jdbc.Driver").newInstance());

        JShell js = JShell.create();
        String code = ""
            + "try {"
            + "    Class.forName(\"com.mysql.jdbc.Driver\").newInstance();"
            + "} catch (Exception e) {"
            + "    System.out.println(e.toString());"
            + "}";
        js.eval(code);
    }
}

构建/打包后:

java -p lib -m example.loadmysql
com.mysql.jdbc.Driver@6a4f787b
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver

很明显,即使example.loadmysql模块需要 mysql 连接器,创建的 JShell 实例也不需要。所以它找不到类。

关于如何以编程方式将模块添加到 JShell 实例的任何想法,因此它像直接 JShell 编码示例一样工作?

更新- 我已经弄清楚如何设置模块路径:

String modulePath = System.getProperty("jdk.module.path");
js.eval("System.setProperty(\"jdk.module.path\", \""
    + modulePath + "\");");

但这还不够。我仍然以某种方式添加了所需的模块。

4

2 回答 2

3

您可能可以在代码中使用addToClassPathbeforeeval作为:

JShell js = JShell.create();
js.addToClasspath("path/to/add/to/the/classpath");
String code = ""
        + "try {"
        + "    Class.forName(\"com.mysql.jdbc.Driver\").newInstance();"
        + "} catch (Exception e) {"
        + "    System.out.println(e.toString());"
        + "}";
js.eval(code);

指定的路径被添加到 中使用的类路径 eval()的末尾。请注意,无法从放置代码的包中访问未命名的包。eval(String)

从文档看来,JShell 返回的 post 的状态eval基于类路径执行代码,因此为了向其添加任何进一步的依赖项,您需要使用相同的方法将其添加到类路径中。


在您的情况下,我在这里猜测虽然您这样做,但mysql-connector-java-5.1.35.jar理想情况下会被视为类路径上存在的自动模块,因此该类com.mysql.jdbc.Driver将是可访问的。


更新: - 进一步探索我认为实现这一目标的更好方法可能是尝试使用Jshell.Builder它的选项compilerOptions来创建具有默认编译选项的实例有点像(未测试) -

JShell js = JShell.builder()
                 .compilerOptions("--module-path lib","--add-modules mysql.connector.java").build();
String code = ""
    + "try {"
    + "    Class.forName(\"com.mysql.jdbc.Driver\").newInstance();"
    + "} catch (Exception e) {"
    + "    System.out.println(e.toString());"
    + "}";
js.eval(code);
于 2017-09-25T08:11:55.253 回答
0

可以使用/env命令添加模块,查看帮助:

/env [-class-path <path>] [-module-path <path>] [-add-modules <modules>] ...
|   view or change the evaluation context

细节:

jshell> /help context
|  
|  context
|  
|  These options configure the evaluation context, they can be specified when
|  jshell is started: on the command-line, or restarted with the commands /env,
|  /reload, or /reset.
|  
|  They are:
|   --class-path <class search path of directories and zip/jar files>
|       A list of directories, JAR archives,
|       and ZIP archives to search for class files.
|       The list is separated with the path separator
|       (a : on unix/linux/mac, and ; on windows).
|   --module-path <module path>...
|       A list of directories, each directory
|       is a directory of modules.
|       The list is separated with the path separator
|       (a : on unix/linux/mac, and ; on windows).
|   --add-modules <modulename>[,<modulename>...]
|       root modules to resolve in addition to the initial module.
|       <modulename> can also be ALL-DEFAULT, ALL-SYSTEM,
|       ALL-MODULE-PATH.
|   --add-exports <module>/<package>=<target-module>(,<target-module>)*
|       updates <module> to export <package> to <target-module>,
|       regardless of module declaration.
|       <target-module> can be ALL-UNNAMED to export to all
|       unnamed modules. In jshell, if the <target-module> is not
|       specified (no =) then ALL-UNNAMED is used.
|  
|  On the command-line these options must have two dashes, e.g.: --module-path
|  On jshell commands they can have one or two dashes, e.g.: -module-path
于 2017-09-25T08:08:46.963 回答