Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jvm and thread safety #72

Closed
SeeRich opened this issue Aug 30, 2023 · 8 comments
Closed

jvm and thread safety #72

SeeRich opened this issue Aug 30, 2023 · 8 comments

Comments

@SeeRich
Copy link

SeeRich commented Aug 30, 2023

I am working on a rust application with a REST API. Some of the REST endpoints need to make java function calls. I am using the Rust GUI framework Tauri. My managed state for the REST API endpoints is:

struct AppJvm(Mutex<Option<Jvm>>);

And the error I am getting is:

 `*mut *const JNINativeInterface_` cannot be sent between threads safely

Is there a way to handle this? I am essentially using this crate to create the JVM and then create a databases connection object (by called Java methods) and finally sharing this connection between REST endpoints.

@astonbitecode
Copy link
Owner

The Jvm cannot be sent between threads because it contains JNI components that also cannot be sent between threads.
Specifically, the JNIEnv needs to be attached to a thread.

All you need to do, is to create a Jvm once during your application lifetime (eg. during the startup), so that the JNI JVM is started. Then, when you get to serve a request in a thread, create other Jvm struct, by just attaching the current thread, using:

let jvm: Jvm = Jvm::attach_thread()?;

You will have a working Jvm by then.

If you want to do Jvm caching, the only thing you could do is to cache it in a thread_local.

That being said, results of Jvm invocations (ie Instances) are Send and can be sent between threads without problem.

@SeeRich
Copy link
Author

SeeRich commented Sep 2, 2023

I get this output when I call:

let jvm = JvmBuilder::new().build()
WARNING: java_locator found 3 possible java locations: C:\Program Files\Microsoft\jdk-11.0.20.101-hotspot\bin\java.exe, C:\Program Files (x86)\Common Files\Oracle\Java\javapath\java.exe, C:\Program Files\Java\jre-1.8\bin\java.exe. Using the last one.
Error occurred during initialization of VM
java.lang.NoSuchMethodError: java.net.URLClassLoader.<init>(Ljava/lang/String;[Ljava/net/URL;Ljava/lang/ClassLoader;)V
        at org.astonbitecode.j4rs.api.deploy.J4rsClassLoader.<init>(J4rsClassLoader.java:22)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
        at java.lang.reflect.Constructor.newInstance(Unknown Source)
        at java.lang.SystemClassLoaderAction.run(Unknown Source)
        at java.lang.SystemClassLoaderAction.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.lang.ClassLoader.initSystemClassLoader(Unknown Source)
        at java.lang.ClassLoader.getSystemClassLoader(Unknown Source)

@astonbitecode
Copy link
Owner

Please make sure the JAVA_HOME environmental variable is set up and points to the Java installation you prefer.

@SeeRich
Copy link
Author

SeeRich commented Sep 4, 2023

I set JAVA_HOME to C:\Program Files\Java\jre-1.8 and that got rid of the first warning. However, I am still getting the error related to java.net.URLClassLoader. Any recommendation?

System information: Windows 11

@astonbitecode
Copy link
Owner

Either use Java version > 8 or do what is documented here.

@SeeRich
Copy link
Author

SeeRich commented Sep 4, 2023

Sorry about that, I should've noticed that in the documentation.

One final question since the README includes information about shipping/deploying a j4rs application.

Is it possible to bundle my create in such a way that the end user of the application wouldn't even need the JRE installed (would be included with j4rs jassets? For example, I already have a folder that contains other JAR files needed by the application, could I somehow put the entire jre in this folder as well and point j4rs at it?

@astonbitecode
Copy link
Owner

Theoretically, you could ship the whole JRE along with a j4rs application, but you should include instructions on how someone would set the JAVA_HOME in their environment, or, you should create your own startup scripts that would do so in a hardcoded way. However, the JRE location should not be inside the jassets. This is more of a location for libraries/jars.

IMO, maybe a better approach would be to use snap, flatpack, or appimage, so that you have the JRE in the app in a more "official" way.

@SeeRich
Copy link
Author

SeeRich commented Sep 4, 2023

Theoretically, you could ship the whole JRE along with a j4rs application, but you should include instructions on how someone would set the JAVA_HOME in their environment, or, you should create your own startup scripts that would do so in a hardcoded way. However, the JRE location should not be inside the jassets. This is more of a location for libraries/jars.

IMO, maybe a better approach would be to use snap, flatpack, or appimage, so that you have the JRE in the app in a more "official" way.

Perfect, thank you so much! I will mark this as closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants