Skip to content

Instantly share code, notes, and snippets.

@de-sh
Last active January 20, 2022 15:07
Show Gist options
  • Save de-sh/1cf7f95d74268e8c9116150fec818a13 to your computer and use it in GitHub Desktop.
Save de-sh/1cf7f95d74268e8c9116150fec818a13 to your computer and use it in GitHub Desktop.
A note on what I think are best practices for writing Java Native Interface bindings with a rust library

Java is not something I am very happy about working with, personal dislike aside, I have had a lot of peers discourage me from working with it. But when it comes to interesting technical challenges, it is always a good idea to atleast give it a try. Now that I am at a point where I have spent close to a month on the task, I feel I am more than enough experienced to give my first impressions and more importantly a note of caution to folks who might be considering jumping into the depths, in search of an adventure.

JNI is complex, but it isn't like you have to deal with a lot of the complexity yourself. If you have the advantage of being able to use a simple, yet awesome developer tool called flapigen, you are already off to the races! Yes, I had tried writing the bindings myself, but it wasn't a very good idea, the ability to write code with a DSL and have it generate the bindings is as miracle cure to some of the worst problems a maintainer can face. Flapigen gives you a simple rust-macro styled programming language that you can use to define JNI bindings for your library. It is as simple as:

// rust code
pub struct Foo();

impl Foo {
  pub fn new() -> Foo {
    Foo()
  }
}

pub fn hello() -> String {
  "Hello, World".to_owned()
}

// flapigen code
foreign_class!(class Foo {
    self_type Foo;
    constructor Foo::new() -> Foo;
    fn hello() -> String;
});

The above code describes a struct that serves no other purpose than to be a placeholder object that is used to call hello() from Java. Once the equivalent Java code is generated, you'll be able to use the bindings as follows:

import rust.package.Foo;

class Bar {
  public void hello() {
    Foo foo = new Foo();
    System.out.println(foo.hello());
  }
}

NOTE: Given that you have loaded the proper .so that was also generated when building the rust library.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment