我试图通过我使用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 as:
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 + "\");");
但这还不够。我仍然以某种方式添加了所需的模块。
答案 0 :(得分:3)
您可以在代码中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);
指定的路径将添加到类路径的末尾
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);
答案 1 :(得分: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