Есть ли способ изменить путь к модулю и добавить модули программного экземпляра JShell?
Я пытаюсь запустить некоторый код Java во время выполнения через экземпляр JShell, который я создал с помощью JShell API. Чтобы продемонстрировать свою проблему, я собираюсь поделиться своим простым кодом.
С моей текущей установкой у меня есть каталог с именем 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 + "\");");
Но этого не достаточно. Я все еще должен добавить необходимый модуль как-то.
2 ответа
Вы можете, вероятно, использовать addToClassPath
до eval
в вашем коде как:
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 вернуло пост eval
выполняет код, основанный на пути к классам, следовательно, чтобы добавить к нему какие-либо дополнительные зависимости, вам необходимо добавить его в путь к классам, используя тот же метод.
В вашем случае я предполагаю, что при этом mysql-connector-java-5.1.35.jar в идеале должен рассматриваться как автоматический модуль, присутствующий в classpath и, следовательно, в классе. 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);
Вы можете использовать /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