# Compile-time validation of JNI signatures

DevFeed: [Compile-time validation of JNI signatures](<https://devfeed.tech/articles/compile-time-validation-of-jni-signatures-20924.md>)

Original publisher: [Read original article](<https://jakewharton.com/compile-time-validation-of-jni-signatures/>)

Published: 2025-03-12T00:00:00Z

Content type: tutorial

Language: en

Sources: [Jake Wharton](<https://devfeed.tech/sources/jake-wharton.md>)

Topics: [Java](<https://devfeed.tech/topics/java.md>), [C](<https://devfeed.tech/topics/c.md>), [Gradle](<https://devfeed.tech/topics/gradle.md>), [Code](<https://devfeed.tech/topics/code.md>)

Tags: [c](<https://devfeed.tech/tags/c.md>), [compiler](<https://devfeed.tech/tags/compiler.md>), [exception](<https://devfeed.tech/tags/exception.md>), [gradle](<https://devfeed.tech/tags/gradle.md>), [java](<https://devfeed.tech/tags/java.md>), [validation](<https://devfeed.tech/tags/validation.md>)

## AI overview

This article explains how to use Java's JNI header generation to validate native method signatures at compile time. It shows how javac's -h flag generates C headers from Java declarations, allowing the native compiler to detect mismatches before runtime, including when Gradle is used.

## Source excerpt

JNI allows managed code inside the JVM or ART to call into native code. Java methods can be declared as native, and then a corresponding C function1 can be written and automatically wired together when the native library is loaded. Native code lacks mechanisms like packages and overloads, so a special format is used to encode the Java method signature. A Java method defined as: package com.example; class Things { static native long createThing(String name, int count); } Requires a matching C declaration which looks like: jlong Java_com_example_Things_createThing( JNIEnv *env, jclass type, jstring name, jint count) { // ... } If you add parameter overloading into the mix, the C declaration must include the parameter signature as well: jlong Java_com_example_Things_createThing_Ljava_lang_String_2I( JNIEnv *env, jclass type, jstring name, jint count) { // ... } Woof! And if you get any part of the encoding wrong, the method call will fail at runtime: Exception in thread "main" java.lang.UnsatisfiedLinkError: 'long Things.createThing(java.lang.String, int)' at Things.createThing(Native Method) at Main.main(example.java:6) In my experience, these signatures do not change frequently. Once they're correct you can mostly just leave them untouched. However, it's a class of problem that would be nice to eliminate completely. Especially if within your projects they do change frequently. JNI header generation When compiling native code, a header represents a series of functions implemented somewhere else. It allows consumers of a library to compile against its API without requiring the full implementation. When compiling the library itself, the compiler requires all header functions have corresponding implementations. Defining a manually-written header for our C functions would be redundant and subject to all the same problems above. Instead, we want to automatically derive the header from the corresponding Java code. As of Java 8, javac can do this for us with its -h flag. Let's l