Skip to content

Setup Guide

This setup guide covers the standard use-case of generating and integrating native bindings into a Java project with a main source set.

You should have these things in place before you start:

  • JVM 17 or above
  • A Gradle project using Gradle v8.8 or above

This will configure the project to download and use Jextract 22 which is determined from the Java toolchain.

build.gradle.kts
plugins {
`java-library`
id("de.infolektuell.jextract") version "x.y.z"
}
repositories {
mavenCentral()
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(25)
}
}

Libraries often consist of a name.h file and binaries like libname.dylib or name.dll. Put them in your source folder like this:

  • Directorylib
    • Directorysrc
      • Directorymain
        • Directoryjava
          • Directorycom
            • Directoryexample
              • Directorygreeting
                • greeting.java
        • Directorynative
          • Directorymacos
            • libgreeting.dylib the macOS binary
          • Directorywindows
            • greeting.dll the windows binary
        • Directorypublic
          • greeting.h the header file
    • build.gradle.kts
  • settings.gradle.kts

Configure the plugin via DSL extension, so it can find the library files.

build.gradle.kts
jextract.libraries {
val greeting by registering {
header = layout.projectDirectory.file("src/main/public/greeting.h")
headerClassName = "Greeting"
targetPackage = "com.example.greeting"
}
sourceSets.named("main") {
jextract.libraries.addLater(greeting)
}
}

Now the project is ready for its first build.

Building the project
gradlew.bat build

This will result in the following output file structure:

  • Directory.gradle
    • Directoryjextract Cache for Jextract downloads and installations
      • downloads
      • installation
  • Directorylib
    • Directorybuild
      • Directorygenerated
        • Directorysources
          • Directoryjextract
            • Directorygreeting the library bindings
              • Directorycom
                • Directoryexample
                  • Directorygreeting
                    • Greeting.java the bindings to import and use in Java code
    • build.gradle.kts
  • settings.gradle.kts

There are mainly two approaches how the generated code can load and access the correct binaries. Please see this stackoverflow question for more details and explanation.

The code searches in the OS-specific paths for the binary files and tries to load them via system.loadLibrary. The java.library.path property can be augmented to search in more paths or in the deployed app distribution. This approach is activated in a library config in the plugin DSL.

build.gradle.kts
jextract.libraries {
val greeting by registering {
useSystemLoadLibrary = true
libraries.add("greeting")
}
}

Instead of configuring the libraries in the DSL, custom logic for loading the files can be implemented. This is a typical approach for bundling natives as resources of a jar file for more portable deployment.