Discover Azul's high-performance Java platform providing faster speed, startup, & efficiency without code changes
Support
Blog chevron_right Java

Accessing Foreign Programming Languages in Java with Project Panama

You probably heard of Java’s new Project Panama APIs that can access native libraries written in C, but what about libraries written in other languages such as C++ or Rust? Check out these series of articles that will show you how.

If you are new to Java’s Project Panama APIs, please check out the article Accessing Native Code in Java with Project Panama.

In a series of brief problem and solution style articles over at Foojay.io You will learn how to access native libraries written in other languages using Project Panama (Foreign Function & Memory Access APIs). These articles will help you get up to speed on what is new in OpenJDK 19+ and beyond that will give your applications a competitive advantage.

A summary of the four-part series is shown below.

Part 1: Java Panama Polyglot (C++)

In Part 1 It begins with the definition of polyglot as it relates to Java and interoperability with other natively compiled languages. Each article will start with a problem and solution followed up by a detailed example.

In this article you’ll quickly discover that the foreign function access API currently (only) supports the C ABI (Application Binary Interface) Convention which means Java can only access C based functions and symbols. However, you’ll be happy to know that many natively compiled languages supply ways to map foreign functions and are able to export (expose) symbols as C functions publicly.

As an example, you’ll learn how to create a simple C++ library that exposes functions that can be called using Panama’s foreign function APIs. The C++ language can export functions as C functions by prepending a C style function with extern “C” keyword. The implementation code will have C++ code statements.      

Part 2: Java Panama Polyglot (Swift)

In Part 2 you’ll learn how to create a native Swift library on the MacOS operating system. Before getting started you’ll need to install the required software from Apple. When you finish installing the required software, you’ll learn about Swift’s command line tool (Repl) To play around with the Swift programming language.

Like before in Part 1 you learned that other languages also supply a facility to export foreign functions (in this case Swift functions) as C functions in support of the C ABI convention.

Having said this, you’ll be happy to know Apple’s Swift language has a special annotation preceding a native function as follows @_cdecl(“my_native_function“).

Part 3: Java Panama Polyglot (Python/Tensorflow)

After getting the hang of Java talking to natively compile languages what about talking to a locally installed Python language interpreter. In Part 3 You’ll learn how to talk to Python and learn about the popular machine learning library Tensorflow.

What’s cool about this example is you’ll learn how to execute Python script code that was passed in from Java code. In the article’s example will use Tensorflow’s official tutorial written in Python. The tutorial shows the ability to train a neural net model that learns how to recognize bitmap images of several types of clothing.

Since Python itself is written in C you’ll be able to use the jextract tool to generate binding code. Once generated you will simply supply the interpreter with the Python script code to be executed.

Part 4: Java Panama Polyglot (Rust)

The final part 4 of the series talks about how to interoperate with libraries written in the language Rust.

After learning how to install Rust, you’ll learn about its build tool called cargo to create a native library. Also, you’ll learn to create a utility in Rust that can generate a C header file. The C header will later be used with jextract to generate (Panama) binding code.

In Rust it also supports the C ABI convention like C++ and Swift where natively compiled languages supply a way to map foreign functions and export them as C functions, giving Java easy access. To export a function Rust prefixes functions with the following:

#[no_mangle]
pub extern "C"
fn my_native_function()

Well, this sums up the Java Panama Polyglot series and I hope I’ve covered the other commonly used native languages you might meet as a Java developer.

Conclusion

One of the main goals of accessing native libraries is low-level access to hardware and increased performance. So, being able to access native libraries is vital to unlocking these goals. With the up-and-coming Project Panama APIs (JDK 19 Preview Release) these goals can be achieved in pure Java.

In the case of these blog entries the native library code implementor handles creating code that would export (expose) functions that conform to the C ABI, thus giving Java the ability to reference native symbols.