Platform & Advanced APIs

Native Interop: JNI → Panama

Calling C from Java went from JNI (header files, hand-written glue, catastrophic on mistakes) to the Foreign Function & Memory API (Java 22): pure-Java downcalls through method handles and safe, scoped off-heap memory.
  • JNI: native methods + generated headers + C glue compiled per platform — powerful, painful, unsafe
  • JNI crashes take the whole JVM — a segfault in glue code is not an exception
  • FFM (JEP 454): Linker + SymbolLookup bind C functions to MethodHandles — no glue code
  • MemorySegment + Arena manage off-heap memory with deterministic, scope-checked lifetime
  • jextract generates Java bindings from C headers automatically
  • When possible, avoid interop entirely — a pure-Java library outlives every binding
FFM: calling strlen without writing C
Linker linker = Linker.nativeLinker();
SymbolLookup libc = linker.defaultLookup();

MethodHandle strlen = linker.downcallHandle(
        libc.find("strlen").orElseThrow(),
        FunctionDescriptor.of(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS));

try (Arena arena = Arena.ofConfined()) {
    MemorySegment cString = arena.allocateFrom("Hello, Panama!");
    long len = (long) strlen.invokeExact(cString);      // 14
}   // arena closes → memory freed, further access throws

The safety upgrade over JNI and Unsafe: a MemorySegment carries bounds and a lifetime (its Arena) — out-of-bounds access and use-after-free throw Java exceptions instead of corrupting the process. Layouts (MemoryLayout.structLayout(...)) describe C structs so field access is named and offset-checked. Upcalls (C calling back into Java) get the same treatment via upcallStub.

JNI (Core Java II ch. 13) remains in the ecosystem — JavaCPP, JNA, and countless legacy bindings — and its rules still matter where you meet it: every JNI reference is loader-local, exceptions must be checked manually after every call, and pinned arrays block the GC. New work should not start there; FFM is faster to write, safer to run, and portable by construction (the binding is data, not compiled C).

Sources
  • Core Java, Volume II: Advanced Features (13th ed.)Ch. 13 — Native Methods (incl. 13.11 Foreign Functions)
  • Optimizing Cloud Native Java (2nd ed.)Ch. 15 — Modern Performance and The Future