Embedding Rust in Java

Overview

Java/Rust Example

An example project showing how to call into Rust code from Java.

OSX Linux Windows
OSX Build Status Linux Build Status Windows Build status

Requirements

  • Java 7+
  • Rust (tested with 1.0, nightly)

Contents

So far, the project contains

  • Rust code and Java code
  • A Java interface to the Rust code, using JNA
  • A script to build the Rust code into a library and put it on the classpath where JNA can find it
  • Examples of passing strings, structs, and callback functions between Java and Rust

Getting Started

The best place to start looking at the examples is in the test code (GreetingsTest.java). The test contains lots of executable examples of calling into Rust code from Java. From the test, you can navigate to the Java code and the Rust code. The implementation is heavily commented to explain it.

So far, it contains examples of the following (click the links to see!):

Building and Running the Tests

To build the project, and run the tests, use Maven. This will build a jar containing the Rust code and the Java code. This assumes you have Rust installed, and on the path.

$ mvn package

You can then run the jar that is produced to see the integration work.

$ java -jar target/greeter.jar John
Hello from Rust, John

Platform Support

This project is tested on OSX, Ubuntu, and Windows. It should also work on any 32 bit or 64 bit Gnu/Linux system.

Limitations

Some of the examples leak memory. Any memory that is allocated in Rust needs to be freed manually because it's not managed by JNA. Some examples pass objects back into Rust to be dropped for this reason, but we don't clean up everything properly (strings, for example). This is almost certainly not a limitation of Rust, but a limitation of my current understanding of Rust.

License

Java/Rust Example Copyright (C) 2015 drrb

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Comments
  • JVM crash

    JVM crash

    Hi,

    first of all, thanks for your project!

    I just tried it on mac, and the JVM crash:

    -------------------------------------------------------
     T E S T S
    -------------------------------------------------------
    Running com.github.drrb.javarust.GreetingsTest
    Starting shouldGetAStructFromRustByValue(com.github.drrb.javarust.GreetingsTest)
    Starting shouldAcceptStringParameterFromJavaToRust(com.github.drrb.javarust.GreetingsTest)
    SUREFIRE-859: Hello from Rust, World
    Starting shouldGetAStructFromRustByReference(com.github.drrb.javarust.GreetingsTest)
    Starting shouldAcceptStringFromJavaToRustAndReturnAnotherOne(com.github.drrb.javarust.GreetingsTest)
    Starting shouldAcceptAStructFromJavaToRust(com.github.drrb.javarust.GreetingsTest)
    Starting shouldGetAStructFromRustContainingAnArrayOfStructs(com.github.drrb.javarust.GreetingsTest)
    #
    # A fatal error has been detected by the Java Runtime Environment:
    #
    SUREFIRE-859: #  SIGSEGV (0xb) at pc=0x00007fff98c60152, pid=6353, tid=0x0000000000001703
    #
    # JRE version: Java(TM) SE Runtime Environment (8.0_92-b14) (build 1.8.0_92-b14)
    # Java VM: Java HotSpot(TM) 64-Bit Server VM (25.92-b14 mixed mode bsd-amd64 compressed oops)
    # Problematic frame:
    # C  [libsystem_c.dylib+0x1152]  strlen+0x12
    #
    SUREFIRE-859: # Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
    #
    # An error report file with more information is saved as:
    # /Users/yannsimon/projects/rust/java-rust-example/hs_err_pid6353.log
    #
    SUREFIRE-859: # If you would like to submit a bug report, please visit:
    #   http://bugreport.java.com/bugreport/crash.jsp
    # The crash happened outside the Java Virtual Machine in native code.
    # See problematic frame for where to report the bug.
    #
    /bin/sh: line 1:  6353 Abort trap: 6           /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/bin/java -Djna.nosys=true -jar /Users/yannsimon/projects/rust/java-rust-example/target/surefire/surefirebooter3340298246630967947.jar /Users/yannsimon/projects/rust/java-rust-example/target/surefire/surefire2630333911108497694tmp /Users/yannsimon/projects/rust/java-rust-example/target/surefire/surefire_08200565017308027989tmp
    
    Results :
    
    Tests run: 0, Failures: 0, Errors: 0, Skipped: 0
    
    [INFO] ------------------------------------------------------------------------
    [INFO] BUILD FAILURE
    [INFO] ------------------------------------------------------------------------
    [INFO] Total time: 2.787 s
    [INFO] Finished at: 2016-06-18T16:11:30+02:00
    [INFO] Final Memory: 17M/211M
    [INFO] ------------------------------------------------------------------------
    [ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.18.1:test (default-test) on project java-rust-example: ExecutionException: java.lang.RuntimeException: The forked VM terminated without properly saying goodbye. VM crash or System.exit called?
    [ERROR] Command was /bin/sh -c cd /Users/yannsimon/projects/rust/java-rust-example && /Library/Java/JavaVirtualMachines/jdk1.8.0_92.jdk/Contents/Home/jre/bin/java -Djna.nosys=true -jar /Users/yannsimon/projects/rust/java-rust-example/target/surefire/surefirebooter3340298246630967947.jar /Users/yannsimon/projects/rust/java-rust-example/target/surefire/surefire2630333911108497694tmp /Users/yannsimon/projects/rust/java-rust-example/target/surefire/surefire_08200565017308027989tmp
    [ERROR] -> [Help 1]
    [ERROR]
    [ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
    [ERROR] Re-run Maven using the -X switch to enable full debug logging.
    [ERROR]
    [ERROR] For more information about the errors and possible solutions, please read the following articles:
    [ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
    

    If I can help debugging the issue, please just tell me what you need.

    opened by yanns 8
  • GreetingSet should not include explicit size on Rust side

    GreetingSet should not include explicit size on Rust side

    First of all, thank you very much for this example project! It really helped me get started on using Rust from Java.

    As for the problem, greetings.rs defines GreetingSet as follows:

    pub struct GreetingSet {
        // A pointer to an array of Greetings. This is converted to a Greeting.ByReference by JNA.
        greetings: Box<[Greeting]>,
        // The size of the array. We need to pass it back to Java so that we know how long the array
        // is (JNA can't guess the size). We need to do this with all arrays created in Java and read
        // in Rust (or vise-versa). This c_int is converted to a Java int by JNA.
        number_of_greetings: c_int
    }
    

    This is actually incorrect. It won't crop up if you have a single GreetingSet, but if you had a contiguous array of them, you would run into problems.

    The issue is apparent when you check mem::size_of::<GreetingSet>(). On a 64-bit platform, you probably expect it to be 16: 8 for the pointer, 4 for the int, and another 4 for alignment. If you test it out, though, it will actually be 24!

    It turns out that the Box<[Greeting]> is basically a struct, itself: it contains the 8-byte pointer, and an 8-byte usize size field. Then, GreetingSet (as it's currently defined) tacks on a redundant 4-byte size and 4 bytes for alignment. JNA is already reading the size as provided by the Box<[]>, not your number_of_greetings field (you can test it out by putting a junk value in there).

    To sum it up, GreetingSet on the Rust side should look like this:

    pub struct GreetingSet {
        // A struct that includes a pointer to an array of Greetings and a size. JNA will convert this
        // to two fields: a Greeting.ByReference and an int.
        greetings: Box<[Greeting]>,
    }
    

    As the updated comment indicates, the Java code remains the same. You could optionally use a size-dependent type (com.sun.jna.IntegerType?), but Java will break on arrays longer than Integer.MAX_VALUE, anyway.

    Without this change, JNA expects GreetingSetto be 16 bytes in length, but as indicated above, it's actually 24 bytes, and this leads to improper alignment if you have a GreetingSet[].

    In case it's relevant, I tested this behavior on Rust nightly (1.4).

    opened by mintern 3
  • Calling Method Within Struct Impl

    Calling Method Within Struct Impl

    Thank you for taking the time to put together this example project. This has been very useful for my introduction into calling Rust libs from Java. Can you please provide an example illustrating the changes required to allow a Java program to call a function declared within a Struct impl? For example, assume you add a new fn called "string" within the existing "Greeting" impl that accepts a param called length (u32 or whatever) and returns a const char * that acts as a String in Java. How would I call this on the Java side? Would I create a new "string" method in Greeting.java that matches the signature? Is this even possible? I'm trying to understand if I can preserve the OOP abstractions from Rust in Java or if I have to have all C-like flat function representations for Java/JNA to work.

    opened by esheri3 2
  • Handling Errors from Rust

    Handling Errors from Rust

    What is the recommended way to communicate errors from Rust back to Java? It appears that use of the 'Result' object is the standard way to communicate errors from method invocations. Would it be idiomatic to return a Result from Rust to Java to communicate to Java if an "exception" occurred when invoking the Rust code?

    opened by esheri3 1
  • Possible to call Java from Rust?

    Possible to call Java from Rust?

    In all the (super awesome) examples in this repo, it seems that Java is invoking Rust functions.

    Based on your experience with this repo, is it possible to use Rust-lang to create objects from Java classes and invoke Java methods on those objects?

    opened by brycefisher 1
  • Improve Travis CI build Performance

    Improve Travis CI build Performance

    Caching Dependencies and Directories Travis CI can cache content that does not often change, to speed up the build process.

    According to the official document Fast Finishing, if some rows in the build matrix are allowed to fail, we can add fast_finish: true to the .travis.yml to get faster feedbacks.

    ===================== If there are any inappropriate modifications in this PR, please give me a reply and I will change them.

    opened by YunLemon 0
  • Bump junit from 4.11 to 4.13.1

    Bump junit from 4.11 to 4.13.1

    Bumps junit from 4.11 to 4.13.1.

    Release notes

    Sourced from junit's releases.

    JUnit 4.13.1

    Please refer to the release notes for details.

    JUnit 4.13

    Please refer to the release notes for details.

    JUnit 4.13 RC 2

    Please refer to the release notes for details.

    JUnit 4.13 RC 1

    Please refer to the release notes for details.

    JUnit 4.13 Beta 3

    Please refer to the release notes for details.

    JUnit 4.13 Beta 2

    Please refer to the release notes for details.

    JUnit 4.13 Beta 1

    Please refer to the release notes for details.

    JUnit 4.12

    Please refer to the release notes for details.

    JUnit 4.12 Beta 3

    Please refer to the release notes for details.

    JUnit 4.12 Beta 2

    No release notes provided.

    JUnit 4.12 Beta 1

    No release notes provided.

    Commits
    • 1b683f4 [maven-release-plugin] prepare release r4.13.1
    • ce6ce3a Draft 4.13.1 release notes
    • c29dd82 Change version to 4.13.1-SNAPSHOT
    • 1d17486 Add a link to assertThrows in exception testing
    • 543905d Use separate line for annotation in Javadoc
    • 510e906 Add sub headlines to class Javadoc
    • 610155b Merge pull request from GHSA-269g-pwp5-87pp
    • b6cfd1e Explicitly wrap float parameter for consistency (#1671)
    • a5d205c Fix GitHub link in FAQ (#1672)
    • 3a5c6b4 Deprecated since jdk9 replacing constructor instance of Double and Float (#1660)
    • Additional commits viewable in compare view

    Dependabot compatibility score

    Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


    Dependabot commands and options

    You can trigger Dependabot actions by commenting on this PR:

    • @dependabot rebase will rebase this PR
    • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
    • @dependabot merge will merge this PR after your CI passes on it
    • @dependabot squash and merge will squash and merge this PR after your CI passes on it
    • @dependabot cancel merge will cancel a previously requested merge and block automerging
    • @dependabot reopen will reopen this PR if it is closed
    • @dependabot close will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
    • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
    • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
    • @dependabot use these labels will set the current labels as the default for future PRs for this repo and language
    • @dependabot use these reviewers will set the current reviewers as the default for future PRs for this repo and language
    • @dependabot use these assignees will set the current assignees as the default for future PRs for this repo and language
    • @dependabot use this milestone will set the current milestone as the default for future PRs for this repo and language

    You can disable automated security fix PRs for this repo from the Security Alerts page.

    dependencies 
    opened by dependabot[bot] 0
  • Use Java 8 idioms

    Use Java 8 idioms

    This PR improves the readability of the Java code used in this example by adopting idioms introduced in Java 8 and earlier.

    These changes intend to make the intent and behavior of the code more visible by reducing the amount of boilerplate code.

    This change also updates various dependencies to the latest compatible minor version, in order to fix the build process on Java 8+ JDKs.

    opened by brownian-motion 0
Owner
drrb
drrb
Run Java code from Rust!

Java Native Interface Bindings for Rust This library provides complete FFI bindings to the Java Native Interface, as well as a safe and intuitive wrap

Ben Anderson 66 Nov 28, 2022
Guarding 是一个用于 Java、JavaScript、Rust、Golang 等语言的架构守护工具。借助于易于理解的 DSL,来编写守护规则。Guarding is a guardians for code, architecture, layered.

Guarding Guarding is a guardians for code, architecture, layered. Using git hooks and DSL for design guard rules. Usage install cargo install guarding

Inherd OS Team (硬核开源小组) 47 Dec 5, 2022
eJNI is a Rust crate to make working with Java's JNI less painful by providing abstractions.

eJNI provides abstractions for often-used classes from the Java standard library, like Map and List. Besides this eJNI also provides easy ways to work with Java's primitives and their object counterparts (e.g int and Integer).

Tobias de Bruijn 11 Feb 13, 2022
Java for Rust

j4rs j4rs stands for 'Java for Rust' and allows effortless calls to Java code from Rust and vice-versa. Features Rust to Java direction support (call

aston 355 Dec 28, 2022
Rust bindings to the Java Native Interface — JNI

JNI Bindings for Rust This project provides complete JNI bindings for Rust, allowing to: Implement native Java methods for JVM and Android in Rust Cal

null 768 Dec 30, 2022
Slitter is a C- and Rust-callable slab allocator implemented primarily in Rust, with some C for performance or to avoid unstable Rust features.

Slitter is a less footgunny slab allocator Slitter is a classically structured thread-caching slab allocator that's meant to help write reliable long-

Backtrace Labs 133 Dec 5, 2022
A Rust crate for automatically generating C header files from Rust source file.

Please be aware that this crate is no longer actively maintained, please look into the much more feature rich cbindgen instead. rusty-cheddar rusty-ch

Sean Marshallsay 190 Nov 12, 2022
Rust-ffi-guide - A guide for doing FFI using Rust

Using unsafe for Fun and Profit A guide to traversing the FFI boundary between Rust and other languages. A rendered version is available here. This gu

Michael Bryan 261 Dec 1, 2022
Rust library for build scripts to compile C/C++ code into a Rust library

A library to compile C/C++/assembly into a Rust library/application.

Alex Crichton 1.3k Dec 21, 2022
Rust based WASM/JS bindings for ur-rust

ur-wasm-js WASM/JS bindings for the ur-rust rust library Getting started Installation Either build the library yourself with wasm-pack or install for

Lightning Digital Entertainment 5 Feb 28, 2024
A project for generating C bindings from Rust code

cbindgen   Read the full user docs here! cbindgen creates C/C++11 headers for Rust libraries which expose a public C API. While you could do this by h

Ryan Hunt 1.7k Jan 3, 2023
Automatically generates Rust FFI bindings to C (and some C++) libraries.

bindgen bindgen automatically generates Rust FFI bindings to C (and some C++) libraries. For example, given the C header doggo.h: typedef struct Doggo

The Rust Programming Language 3.2k Jan 4, 2023
Safe interop between Rust and C++

CXX — safe FFI between Rust and C++ This library provides a safe mechanism for calling C++ code from Rust and Rust code from C++, not subject to the m

David Tolnay 4.4k Jan 7, 2023
Safe Rust bridge for creating Erlang NIF functions

Rustler Documentation | Getting Started | Example Rustler is a library for writing Erlang NIFs in safe Rust code. That means there should be no ways t

Rusterlium 3.5k Jan 7, 2023
Bridge the gap between Haskell and Rust

Curryrs Curryrs (a play on the name of Haskell Curry, rs for Rust libraries, and it's pronunciation couriers) is a library for providing easy to use b

Michael Gattozzi 296 Oct 18, 2022
Rust in Haskell FFI Example

Provides an example for using Rust in Haskell. To use this you'll need cargo, rustc, cabal and GHC installed. To execute the example run the following

Michael Gattozzi 21 Oct 1, 2022
Rust-JDBC bindings

jdbc A Rust library that allows you to use JDBC and JDBC drivers. Usage First, add the following to your Cargo.toml: [dependencies] jdbc = "0.1" Next,

Aurora 18 Feb 9, 2022
Lua 5.3 bindings for Rust

rust-lua53 Aims to be complete Rust bindings for Lua 5.3 and beyond. Currently, master is tracking Lua 5.3.3. Requires a Unix-like environment. On Win

J.C. Moyer 150 Dec 14, 2022
Safe Rust bindings to Lua 5.1

rust-lua Copyright 2014 Lily Ballard Description This is a set of Rust bindings to Lua 5.1. The goal is to provide a (relatively) safe interface to Lu

Lily Ballard 124 Jan 5, 2023