Java Tips # 01 –  Writing Shebang Scripts in Pure Java

Did you know you can write a CLI script in Java just as easily as you would in a bash script, and run it directly from the shell? This is commonly called a shebang script, though we are mostly familiar with writing them in bash. Bash scripts are great, but they can be obscure to … Read more

Creating a Command Line Tool with JBang and PicoCLI to Generate Release Notes

Lately, I have been playing with JBang and PicoCLI, and I am pretty amazed at what we can do with these tools. I needed to create a script that would go to a specified repository on GitHub, check the commit range, and verify if any tickets were associated with them. Additionally, I wanted to check … Read more

Unsafe is Finally Going Away: Embracing Safer Memory Access with JEP 471

Java’s sun.misc.Unsafe is being phased out. Learn safer memory access using VarHandle and Foreign Function & Memory API to keep your applications secure and up-to-date.

Exploring New Features in JDK 23: Simplifying Java with Primitive Type Patterns with JEP 455

Java continues to evolve, introducing features that streamline coding practices and improve readability. JEP 455 is one such proposal that enhances the switch statement, making it more versatile and expressive. This article delves into how JEP 455 can be utilized to handle complex decision-making scenarios more efficiently. We’ll examine a practical example to illustrate the … Read more

Exploring New Features in JDK 23: A Sneak Peek

The main method and println With JDK 23 on the horizon, I decided to dive into some of its new features by running the following code in the CLI: void main() { println(“Hello World”); var name = readln(“Enter your name: “); println(“Your name is ” + name); var age = readln(“Enter your age: “); println(“Your … Read more

Records for Cleaner and More Expressive Parameterized Tests in JUnit 5

Introduction:  Parameterized testing in JUnit 5 is a potent technique for executing the same test logic with various inputs. While you can use a variety of data structures, such as custom classes, arrays, or collections, Java records offer a compelling advantage in readability, type safety, and expressiveness. Let’s examine how to leverage Java records for … Read more

Accessing Native C Functions from Java Using OpenJDK’s JEP 454: Foreign Function & Memory API

Introduction

Java’s robustness and cross-platform capabilities have made it a staple in enterprise applications. However, there are scenarios where Java applications need to interact with native libraries written in languages like C or C++. The Java Native Interface (JNI) has been the traditional solution for such needs, but it comes with its own complexities and performance overheads. OpenJDK’s JEP 454, aims to offer a more straightforward and efficient alternative. Part of Project Panama, this API is designed to improve Java’s capabilities for interacting with native code. In this article, we’ll walk through a simple example to demonstrate how to use JEP 454 to call a C function from a Java program.

It’s important to note that this JEP is still in preview mode. To experiment with it, you’ll need JDK 22. You can use SDKMan to install JDK 22 on your system easily.

What is in JEP 454?

Java Enhancement-Proposal (JEP) 454 aims to introduce a Foreign Function & Memory API that simplifies the interaction between Java and native code. The API consists of two main components:

  1. Foreign Function Interface (FFI): Enables Java programs to call native functions easily, abstracting much of the boilerplate code required in JNI.
  2. Memory Access API: Provides a set of tools for interacting with native memory, including features for memory allocation, deallocation, and manipulation of native data structures.

JEP 454 is designed to be highly performant and includes various safety checks to prevent common pitfalls like buffer overflows. It is intended to replace JNI for most use cases, offering a more efficient and safer way to access native libraries and manage native memory.

Creating the C Library

First, let’s create a C program that contains a simple function to add two integers. The code for this is as follows:

#include <stdio.h>

int add(int a, int b) {
    return a + b;
}

After writing the code, save it in a file named addition.c. To compile this into a shared library, navigate to the directory where the file is located and run the following command:

gcc -shared -o libaddition.so -fPIC addition.c

This command compiles the C code into a shared library named libaddition.so, ready to be accessed by our Java program.

Writing the Java Program

Next, let’s write a Java program that uses the Foreign Function & Memory API to call the add function from our C library. The Java code is as follows:

import java.lang.foreign.*;
import java.nio.file.Path;

public class Main {
    void main() {

        try (var arena = Arena.ofConfined()) {
            var lib = SymbolLookup.libraryLookup(Path.of("libaddition.so"), arena);
            var linker = Linker.nativeLinker();
            var fd = FunctionDescriptor.of(ValueLayout.JAVA_INT, ValueLayout.JAVA_INT, ValueLayout.JAVA_INT);
            var addFunc = lib.find("add").get();

            var methodHandle = linker.downcallHandle(addFunc, fd);
            var sum = methodHandle.invoke(1, 2);
            System.out.println("sum = " + sum);
        } catch (Throwable e) {
            throw new RuntimeException(e);
        }
    }
}

Replace "libaddition.so" with the actual path to the compiled C library.

Running the Java Program

To compile and run the Java program, use the following command:

java --source 22 --enable-preview Main.java

If everything is set up correctly, the output should display:

sum = 3

Conclusion

OpenJDK’s JEP 454 offers a promising alternative to JNI for interacting with native code. By providing a simpler, safer, and more efficient API, it has the potential to revolutionize how Java developers work with native libraries and memory.

How to Diagnose and Mitigate Pinning in Java’s Virtual Thread Execution

In the context of virtual threads, pinning refers to the condition where a virtual thread is “stuck” to its carrier thread (the platform thread on which it runs).

What is a semaphore, and when to use it?

In Java’s concurrency API, a semaphore is another synchronization tool that simultaneously controls the number of threads accessing a particular resource or section of code. It manages a set of permits; threads must acquire a permit before proceeding. If a permit is available, the thread acquires it and continues execution. If not, the thread is … Read more

What is CyclicBarrier and When to Use It in Java?

In Java’s concurrency API, CyclicBarrier is another kind of synchronizer, similar to CountDownLatch. It enables multiple threads to wait for each other at a predefined execution point before resuming work. For example, consider a financial application that performs complex risk assessments for various portfolios. The reviews could involve multiple steps like data gathering, calculations and … Read more