Search code examples
javajsongradleresourcesgraalvm

Glob pattern to include all files in 'src/main/resources' into GraalVM binary


I have a Java project using Gradle to build. The folder structure is as below:

<project name>
|- app
   |- bin/
   |- build/
   |- src/
   |  |- main/
   |     |- java
   |     |  |- <package path>
   |     |- resources/
   |        |- <.json files>
   |- build.gradle

In my app/build.gradle file, I use the Gradle plugin org.graalvm.buildtools.native to build a binary file using GraalVM:

plugins {
  id 'application'
  id 'org.graalvm.buildtools.native' version '0.9.4'
}

nativeBuild {
  imageName = <image name>
  mainClass = "<package path>.App"
  verbose = true
  fallback = false
  buildArgs.add('-H:IncludeResources=".*\\.json$"')
}

The plugin supports adding extra build arguments to GraalVM. So I use -H:IncludeResources to try to include all JSON files located in src/main/resources/. When building using the command ./gradlew nativeBuild, the build process finished successfully. But when running, the getResourceAsStream function returns null which means it couldn't find those JSON files.

My code to load file content:

import org.apache.commons.io.IOUtils;

private String loadTextResourcesFile(String filePath) {
  try {
    String fileText = IOUtils.toString(getClass().getClassLoader()
        .getResourceAsStream(filePath), "UTF-8");
    return fileText;
  } catch (IOException e) {
    e.printStackTrace();
    return null;
  }
}
String fileContent = loadTextResourcesFile("a.json");

I think the problem is at buildArgs.add('-H:IncludeResources=".*\\.json$"'). Maybe the pattern I used .*\\.json$ doesn't point to my app/src/main/resources/*.json files. But I couldn't find a correct pattern works for my case. Could you please help?


Solution

  • I removed the nativeBuild section in build.gradle and then add the following:

    graalvmNative {
      binaries.all {
        resources.autodetect()
      }
      toolchainDetection = false
    }
    

    This command helps to generate binary file:

    ./gradlew nativeCompile --warning-mode all
    

    And the plugin also generates the resource-config.json file used for native-image. You can find the list of resources included:

    cat app/build/native/generated/generateResourcesConfigFile/resource-config.json
    

    Reference: https://www.graalvm.org/22.2/reference-manual/native-image/guides/use-native-image-gradle-plugin/#build-a-native-executable-with-resources-autodetection

    If you're using Picocli you may also need this in the build.gradle file:

    compileJava {
      options.compilerArgs += [
        "-Aproject=${project.group}/${project.name}",
        "-Aother.resource.patterns=.*"
      ]
    }
    
    

    (.* will include all files under src/main/resources that you want to embed into the binary. For more details about other.resource.patterns, please refer to https://github.com/remkop/picocli/tree/main/picocli-codegen#222-other-options)