I'm trying to run some Java code at run-time through a JShell instance I created using the JShell API. To demonstrate my problem, I'm going to share my simple code.
With my current setup I have a directory called lib that has the MySQL Java driver: mysql-connector-java-5.1.35.jar.
Launching JShell via command tool and adding the needed module as:
jshell --module-path lib --add-modules mysql.connector.java
and then loading the mysql driver works for me :
jshell> Class.forName("com.mysql.jdbc.Driver").newInstance();
$1 ==> com.mysql.jdbc.Driver@42f93a98
I've created a similar Java 9 module with module-info.java
as:
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);
}
}
After building/packaging:
java -p lib -m example.loadmysql
com.mysql.jdbc.Driver@6a4f787b
java.lang.ClassNotFoundException: com.mysql.jdbc.Driver
It's clear that even though the example.loadmysql module requires the mysql connector, the created JShell instance doesn't. So it can't find the class.
Any ideas on how to programmatically add modules to a JShell instance, so it works like the direct JShell coding example?
UPDATE - I've figured out how to set the module path:
String modulePath = System.getProperty("jdk.module.path");
js.eval("System.setProperty(\"jdk.module.path\", \""
+ modulePath + "\");");
But that's not quite enough. I still have add the needed module somehow.
You can probably use addToClassPath
before eval
in your code as:
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.
It seems from the documentation that the state of JShell returned post eval
executes the code based on the classpath, hence in order to add any further dependencies to it, you would need to add it to the classpath using the same method.
In your case I am guessing here though as you do so, the mysql-connector-java-5.1.35.jar would ideally be treated to as an automatic module present on the classpath and hence the class com.mysql.jdbc.Driver
would be accessible.
Update :- Exploring further I think a better way to achieve this could be though trying to use Jshell.Builder
and its option compilerOptions
to create an instance with default compiling options somewhat like(not tested) -
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);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With