Rust and Java Interoperability

Rust does not stop for one second to amaze me. It looks like Rust was designed to talk to every other language so easily. No kidding, it's clear way Web Assembly and rust have lots in common. Java is never an easy lang to interop with. Today I will show how easily we can interop Java & Rust. In order to do so, we will need to use the Java and Rust compilers. For Java, we will not require any other lib than the standard JDK. For Rust, we will need to create a lib project in cargo and we will need to use the crate JNI. I love this feature because java does not allow low-level code on the main language. So if we need to do something low level, efficiently Rust is my first choice, not only for safety reasons but because is really fast.  Let's get started.



Cargo.Toml

First of all, we need to create a lib project in cargo. Let's look at the Cargo.toml file.


There are 3 Important things here. First of all and more importantly the *name* this will be the name of the library, well we call RUST from Java we will need to use this exactly same name. What is tricky is that when you compile the SO file won't have that name exactly, but nevertheless in Java ill need reference the name that is here, dont reference the file name.

Secondly, we need to have the dependency of JNI which will do the Java binding for us. Finally but not less important we need to define this is a library, so Rust will generate a SO file. This is done via *[lib]* directive on the cargo file.


The Rust Lib

Now we can take a look at the rust code. This code will be located at the src/ folder and will need to be named as lib.rs. So let's take a look at it.



First of all, we are letting rust know that we will be using an extern crate called JNI. Them we can do the JNI imports we need, in rust imports are done with the keyword *use*. Now we are exposing a public function called Java_HelloWorld_hello. Which is the name of the Java class + method name. Them we need to receive some parameters like the JNI env, the Class, the input(String argument) and we will return a jstring which is a string in java. As you realize we dont use the _class. However, it needs to be there, in Rust we can get rid of the un-used warnings by adding "_" in front of the variable.

Them the code is pretty easy, we are getting the input from Java and calling Rust String format macro and returning to back to java which is done via *output.into_inner()*.

Java Code 

Now let's look the Java code.



In the code above there are 2 important things. First the private static native hello function, this needs to be defined. Secondly, there is the Library loading part. Like I said before this is tricky for 2 reasons: A) Java will look in all wrong places, so we need to pass some paths. B) We should out the name of the lib, as is in cargo file, not the path not the full path.  Them on the main method we just call the method.

Java Header

We also need to generate a C, Header file for the rust lib, this can be done via command:

javac -h . HelloWorld.java

The generated code should be like:


Here we have the JNI Exports that Java need it.

Compile & Run

Now we can compile rust by doing: *cargo build* and run java, here is a script to make it all easy.



Once you run this code you will see the following output:

 ./run.sh

LD_LIBRARY_PATH=/home/diego/github/diegopacheco/rust-playground/jni-fun/target/debug/
Hello, Diego Pacheco!

The complete source code is available on my GitHub here

I hope you guys like it, take care. 

Cheers,
Diego Pacheco

Popular posts from this blog

Kafka Streams with Java 15

HMAC in Java