{"id":22729061,"url":"https://github.com/giovanniberti/robusta","last_synced_at":"2025-05-16T09:05:02.764Z","repository":{"id":40679299,"uuid":"295778091","full_name":"giovanniberti/robusta","owner":"giovanniberti","description":"Easy interop between Rust and Java","archived":false,"fork":false,"pushed_at":"2024-04-15T07:48:26.000Z","size":591,"stargazers_count":355,"open_issues_count":27,"forks_count":17,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-05-13T15:01:52.779Z","etag":null,"topics":["ffi","java","rust"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/giovanniberti.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2020-09-15T15:56:10.000Z","updated_at":"2025-04-22T15:08:19.000Z","dependencies_parsed_at":"2023-09-26T03:58:04.795Z","dependency_job_id":"5f281a17-ddbf-435b-8487-9c54051de7de","html_url":"https://github.com/giovanniberti/robusta","commit_stats":{"total_commits":235,"total_committers":5,"mean_commits":47.0,"dds":0.174468085106383,"last_synced_commit":"f57f728d60c77893742ccd8d7ba2c650c38d766b"},"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giovanniberti%2Frobusta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giovanniberti%2Frobusta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giovanniberti%2Frobusta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/giovanniberti%2Frobusta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/giovanniberti","download_url":"https://codeload.github.com/giovanniberti/robusta/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254501557,"owners_count":22081528,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ffi","java","rust"],"created_at":"2024-12-10T17:19:25.448Z","updated_at":"2025-05-16T09:04:57.740Z","avatar_url":"https://github.com/giovanniberti.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# robusta \u0026mdash; easy interop between Rust and Java\n[![Build Status](https://github.com/giovanniberti/robusta/actions/workflows/test.yml/badge.svg)](https://github.com/giovanniberti/robusta/actions/workflows/test.yml) [![Latest Version](https://img.shields.io/crates/v/robusta_jni.svg)](https://crates.io/crates/robusta_jni) [![Docs](https://docs.rs/robusta_jni/badge.svg?version=0.2.0)](https://docs.rs/robusta_jni)\n\n[Master branch docs](https://giovanniberti.github.io/doc/robusta_jni/)\n\nThis library provides a procedural macro to make easier to write JNI-compatible code in Rust.\n\nIt can perform automatic conversion of Rust-y input and output types (see the [limitations](#limitations)).\n\n```toml\n[dependencies]\nrobusta_jni = \"0.2\"\n```\n\n## Usage\nAll that's needed is a couple of attributes in the right places.\n\nFirst, a `#[bridge]` attribute on a module will enable it to be processed by `robusta`.\n\nThen, we will need a struct for every class with a native method that will be implemented in Rust,\nand each of these structs will have to be annotated with a `#[package]` attribute\nwith the name of the Java package the corresponding class belongs to.\n\nAfter that, the functions implemented can be written as ordinary Rust functions, and the macro will\ntake care of converting to and from Java types for functions marked public and with a `\"jni\"` ABI. By default if a conversion fails a Java exception is thrown.\n\nOn the other hand, if you need to call Java function from Rust, you add a `\"java\"` ABI and add a  `\u0026JNIEnv` parameter after `self`/`\u0026self`/`\u0026mut self` (or as first parameter if the method is static), and leave the function body empty.\n\nOn these methods you can attach a `call_type` attribute that manages how conversions and errors are handled: by default, `#[call_type(safe)]` is implied,\nbut you can switch to `#[call_type(unchecked)]` at any time, most likely with few or no code changes.\n\nYou can also force a Java type on input arguments via `#[input_type]` attribute, which can be useful for Android JNI development for example.\n\n### Android specificities\n\nOn Android App, to call a Java class from rust the JVM use the callstack to find desired class.\nBut when in a rust thread, you don't have a call stack anymore.\\\nSo to be able to call a Java class you have to pass the class reference rather than the string class path.\n\nYou can find an example of this usage in `robusta-android-example/src/thread_func.rs`\n\n## Code example\n\nYou can find an example under `./robusta-example`. To run it you should have `java` and `javac` on your PATH and then execute:\n\n```bash\n$ cd robusta-example\n$ make java_run\n\n# if you don't have `make` installed:\n$ cargo build \u0026\u0026 javac com/example/robusta/HelloWorld.java \u0026\u0026 RUST_BACKTRACE=full java -Djava.library.path=../target/debug com.example.robusta.HelloWorld\n```\n\n### Usage on Android example\n\nYou can find an example of Robusta used for Android in `./robusta-android-example`.\nTo run it, open the project robustaAndroidExample with Android Studio.\n\nCargo build is automatically run by gradle.\n\nThe rust lib.rs is the image of the Java class RobustaAndroidExample.\n\nThis example only gets the files authorized path of the App.\n\n## Example usage\n### Rust side\n```rust\nuse robusta_jni::bridge;\nuse robusta_jni::convert::Signature;\n\n#[bridge]\nmod jni {\n    #[derive(Signature)]\n    #[package(com.example.robusta)]\n    struct HelloWorld;\n\n    impl HelloWorld {\n        pub extern \"jni\" fn special(mut input1: Vec\u003ci32\u003e, input2: i32) -\u003e Vec\u003cString\u003e {\n            input1.push(input2);\n            input1.iter().map(ToString::to_string).collect()\n        }\n    }\n}\n```\n\n### Java side\n```java\npackage com.example.robusta;\n\nimport java.util.*;\n\nclass HelloWorld {\n    private static native ArrayList\u003cString\u003e special(ArrayList\u003cInteger\u003e input1, int input2);\n\n    static {\n        System.loadLibrary(\"robusta_example\");\n    }\n\n    public static void main(String[] args) {\n        ArrayList\u003cString\u003e output = HelloWorld.special(new ArrayList\u003cInteger\u003e(List.of(1, 2, 3)), 4);\n        System.out.println(output)\n    }\n}\n```\n\n## Type conversion details and extension to custom types\nThere are four traits that control how Rust types are converted to/from Java types:\n`(Try)FromJavaValue` and `(Try)IntoJavaValue`.\n\nThese traits are used for input and output types respectively, and implementing them\nis necessary to allow the library to perform automatic type conversion.\n\nThese traits make use of type provided by the  [`jni`](https://crates.io/crates/jni) crate,\nhowever to provide maximum compatibility with `robusta`, we suggest using the re-exported version under `robusta_jni::jni`.\n\n### Raising exceptions\nYou can make a Rust native method raise a Java exception simply by returning a `jni::errors::Result` with an `Err` variant.\n\n### Conversion table\n\n| **Rust**                                                                           | **Java**                          |\n|------------------------------------------------------------------------------------|-----------------------------------|\n| i32                                                                                | int                               |\n| bool                                                                               | boolean                           |\n| char                                                                               | char                              |\n| i8                                                                                 | byte                              |\n| f32                                                                                | float                             |\n| f64                                                                                | double                            |\n| i64                                                                                | long                              |\n| i16                                                                                | short                             |\n| String                                                                             | String                            |\n| Vec\\\u003cT\\\u003e†                                                                          | ArrayList\\\u003cT\\\u003e                    |\n| Box\u003c[u8]\u003e                                                                          | byte[]                            |\n| [jni::JObject\u003c'env\u003e](https://docs.rs/jni/0.17.0/jni/objects/struct.JObject.html) ‡ | *(any Java object as input type)* |\n| [jni::jobject](https://docs.rs/jni/0.17.0/jni/sys/type.jobject.html)               | *(any Java object as output)*     |\n\n† Type parameter `T` must implement proper conversion types\n\n‡ The special `'env` lifetime **must** be used\n\n## Limitations\n\nCurrently there are some limitations in the conversion mechanism:\n * Boxed types are supported only through the opaque `JObject`/`jobject` types\n * Automatic type conversion is limited to the table outlined above, though easily extendable if needed.\n\n\n## Contributing\nI glady accept external contributions! :)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiovanniberti%2Frobusta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgiovanniberti%2Frobusta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgiovanniberti%2Frobusta/lists"}