my experience while developing java bindings for foreign libs

Sebastian Stenzel sebastian.stenzel at gmail.com
Thu Jan 20 10:31:10 UTC 2022


Hi Panamanians,

No questions today. Instead, I wanted to share my recent experience with Panama.

Those of you, who read my previous posts to this mailing lists know that I've been experimenting with Panama for quite some time in order to create Java bindings for FUSE. Now that Panama's API is slowly but steadily becoming stable, I decided to promote my experiments to an actual library [1] that I want to maintain long-term. That said, it will obviously not make it to a 1.0 as long as Panama is still incubating.

During my work on this, I learned to love Panama and here are the reasons why:

1. We have been dependent on other libs in order to use FUSE for virtual file systems in our application Cryptomator since the beginning. While they work great and we're going to continue using them for some time, they pull in tons of transitive dependencies via JNR/JNA, which gives us a hard time with the module system (including split packages). Using Panama, we can now create library bindings with zero dependencies.

2. Given, with JNI this would have been possible as well, but...

3. No foreign language/tools required. Today I used macOS (x86_64) to jextract Linux aarch64 headers [2], simply by installing `libc6-dev-aarch64-cross` in a Debian container and making the files accessible to the host system. This is a game changer for what used to require cross compilation.

4. Simple usage in downstream projects. Just add a dependency, set the library search path, add two flags (`--add-modules jdk.incubator.foreign --enable-native-access=org.cryptomator.jfuse.mac`) and that's it. Unpopular opinion: When packaging an app for distribution, vendors need to set certain flags anyway. ;-)

5. Easy migration path, if upstream headers change. Seeing compilation errors after incompatible changes have been jextracted is **so much more comfortable** than waiting for runtime errors to occur (that usually just say "access violation").

6. No need to distribute .so, .dll, .dylib with your jar. When using JNI-based solutions you need to worry about bundling your bridging lib and making it accessible at runtime. Most devs decide to write it to a tmp directory. E.g. JNR's jffi lib is extracted to java.io.tmpdir, which may pose a security problem. Or it may cause problems, if /tmp is mounted with noexec flag.

7. Having the complete implementation in just one language makes it easier for static code analysis tools to find issues. With JNI on the other hand, there is a boundary between C and Java code. Tools have (to my knowledge) no chance to track the flow of data beyond this boundary, leading to incorrect data scopes and lots of false positives as well as unnoticed errors.


Conclusion: I can't recall many examples where a technology made things both easier _and_ more secure at the same time. I just can encourage people to give Panama a try, when they want to create Java bindings for some native lib. I truly believe, Panama will have a huge impact on what kinds of projects Java can be used for and can't wait to see what solutions people will come up with.

Thank you all for making this a reality!

Sebastian


[1]: https://github.com/cryptomator/jfuse <https://github.com/cryptomator/jfuse>
[2]: https://github.com/cryptomator/jfuse/pull/1 <https://github.com/cryptomator/jfuse/pull/1>



More information about the panama-dev mailing list