有没有办法修改模块路径和程序化 JShell 实例的添加模块?
Is there a way to modify module path and added modules of a programmatic JShell instance?
我正在尝试通过我使用 JShell API 创建的 JShell 实例在 运行 时 运行 一些 Java 代码。为了演示我的问题,我将分享我的简单代码。
根据我当前的设置,我有一个名为 lib 的目录,其中包含 MySQL Java 驱动程序:mysql -连接器-java-5.1.35.jar.
通过命令工具启动 JShell 并添加所需的模块:
jshell --module-path lib --add-modules mysql.connector.java
然后加载 mysql 驱动程序对我有用:
jshell> Class.forName("com.mysql.jdbc.Driver").newInstance();
==> 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);
}
}
building/packaging之后:
java -p lib -m example.loadmysql
com.mysql.jdbc.Driver@6a4f787b
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
很明显,即使 example.loadmysql 模块需要 mysql 连接器,但创建的 JShell 实例不需要。所以它找不到 class.
关于如何以编程方式将模块添加到 JShell 实例,使其像直接 JShell 编码示例一样工作的任何想法?
UPDATE - 我已经知道如何设置模块路径了:
String modulePath = System.getProperty("jdk.module.path");
js.eval("System.setProperty(\"jdk.module.path\", \""
+ modulePath + "\");");
但这还不够。我仍然以某种方式添加了所需的模块。
可以使用/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
您可以在代码中的 eval
之前使用 addToClassPath
作为:
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);
The specified path is added to the end of the classpath used in
eval()
. Note that the unnamed package is not accessible from the
package in which eval(String)
code is placed.
从文档看来,JShell 的状态返回 post eval
执行基于 class 路径的代码,因此为了向其添加任何进一步的依赖项,您需要使用相同的方法将其添加到 class 路径。
在你的情况下,我在这里猜测,虽然你这样做,mysql-connector-java-5.1.35.jar理想情况下,将被视为存在于 class 路径上的 自动模块 ,因此 class com.mysql.jdbc.Driver
将可访问。
Update :- 进一步探索我认为实现这一目标的更好方法可能是尝试使用 Jshell.Builder
and its option 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);
我正在尝试通过我使用 JShell API 创建的 JShell 实例在 运行 时 运行 一些 Java 代码。为了演示我的问题,我将分享我的简单代码。
根据我当前的设置,我有一个名为 lib 的目录,其中包含 MySQL Java 驱动程序:mysql -连接器-java-5.1.35.jar.
通过命令工具启动 JShell 并添加所需的模块:
jshell --module-path lib --add-modules mysql.connector.java
然后加载 mysql 驱动程序对我有用:
jshell> Class.forName("com.mysql.jdbc.Driver").newInstance();
==> 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);
}
}
building/packaging之后:
java -p lib -m example.loadmysql
com.mysql.jdbc.Driver@6a4f787b
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
很明显,即使 example.loadmysql 模块需要 mysql 连接器,但创建的 JShell 实例不需要。所以它找不到 class.
关于如何以编程方式将模块添加到 JShell 实例,使其像直接 JShell 编码示例一样工作的任何想法?
UPDATE - 我已经知道如何设置模块路径了:
String modulePath = System.getProperty("jdk.module.path");
js.eval("System.setProperty(\"jdk.module.path\", \""
+ modulePath + "\");");
但这还不够。我仍然以某种方式添加了所需的模块。
可以使用/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
您可以在代码中的 eval
之前使用 addToClassPath
作为:
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);
The specified path is added to the end of the classpath used in
eval()
. Note that the unnamed package is not accessible from the package in whicheval(String)
code is placed.
从文档看来,JShell 的状态返回 post eval
执行基于 class 路径的代码,因此为了向其添加任何进一步的依赖项,您需要使用相同的方法将其添加到 class 路径。
在你的情况下,我在这里猜测,虽然你这样做,mysql-connector-java-5.1.35.jar理想情况下,将被视为存在于 class 路径上的 自动模块 ,因此 class com.mysql.jdbc.Driver
将可访问。
Update :- 进一步探索我认为实现这一目标的更好方法可能是尝试使用 Jshell.Builder
and its option 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);