Creating Java Code-only Functions

Find out how to package and create Java code-only functions in OCI Functions.

Use a Java code-only function when you want to deploy Java function code without building a container image.

Use this flow when the function can run on a supported Java runtime.

Before creating a Java code-only function, package the Java function as an uber/fat JAR file, or as a ZIP archive that contains exactly one root-level uber/fat JAR file. For general code-only function prerequisites, see Creating Code-only Functions. For supported Java runtime versions and runtime names, see Languages supported for code-only functions.

In addition, for packaging and creating Java code-only functions, you need:

  • A Java development environment.
  • Maven, Gradle, or another Java build tool.
  • A Java function packaged as an uber/fat JAR file, or as a ZIP archive containing exactly one root-level uber/fat JAR file.
  • A valid Java handler value.

Java archive requirements

For Java code-only functions:

  • Use a JAR file for a simple Java function.
  • Use a ZIP file when the function includes resources or native dependencies.
  • The Java JAR must be an uber/fat JAR that includes the function code and required Java dependencies.
  • Create the uber/fat JAR by using an appropriate Maven or Gradle plugin, such as the Maven Shade Plugin or a Gradle shadow JAR plugin.
  • If you provide a ZIP file, the ZIP file must contain exactly one root-level uber/fat JAR file at the archive root.
  • The .jar extension is case-insensitive.
  • resources/ is optional.
  • native/ is optional, but if present it must follow architecture-specific rules.
  • A handler is required.
  • The handler tells OCI Functions which Java method to invoke.

Java handler

Use the handler format expected by the selected Java runtime.

Example:

com.example.HelloFunction::handleRequest

Simple Java archive

Use a JAR file when the function does not require resources or native dependencies.

Example layout before upload:

main.jar

The JAR file contains the compiled function classes and required Java dependencies.

Rules:

  • The JAR file can have any name.
  • The JAR file must be an uber/fat JAR.
  • The JAR file must include the function code and required Java dependencies.

Build an uber/fat JAR

An uber/fat JAR is a JAR file that contains your compiled function classes and the Java libraries required by the function. Packaging dependencies into the JAR makes the function self-contained.

You can create an uber/fat JAR with build-tool plugins, such as the Maven Shade Plugin for Maven or a Shadow plugin for Gradle.

For Maven projects, configure the Maven Shade Plugin to build an uber/fat JAR, and then run:

mvn clean package

For Gradle projects, configure a Shadow plugin or equivalent plugin to build an uber/fat JAR, and then run:

./gradlew clean build

After the build completes, copy the uber/fat JAR to a clean packaging directory. If the function is a simple Java function, you can use the JAR file as the function archive. If the function includes resources or native dependencies, create a ZIP archive that contains the JAR file at the archive root and includes the additional files in the required locations.

Java ZIP archive

Use a ZIP archive when the function includes additional resources or native dependencies.

Use this structure:

archive-root/
          ├── main.jar
          └── resources/ # optional

Rules:

  • main.jar represents the single uber/fat JAR at the archive root. The JAR can have any name.
  • resources/ is optional and must be at the archive root if used.

To create a ZIP file that includes the JAR and resources, run:

zip -r function.zip main.jar resources/

Configure Java runtime options

For Java code-only functions, do not package runtime option files or argument files in the function archive. Configure JVM startup options by setting function configuration variables, such as JAVA_TOOL_OPTIONS.

For example, the following command sets a function configuration parameter with the key JAVA_TOOL_OPTIONS and the value -Dapp.environment=production:

fn config function <app-name> <function-name> JAVA_TOOL_OPTIONS "-Dapp.environment=production"

At runtime, the Java runtime reads the JAVA_TOOL_OPTIONS value and applies the JVM option. In this example, the option sets the Java system property app.environment to production.

For more information about configuring functions, see Specifying Custom Configuration Parameters to Pass to Functions.

Java archive with native dependencies

Java functions are typically architecture-independent. However, if the Java function uses native libraries, such as .so files loaded through JNI or another native mechanism, bundle the native libraries in the deployment archive and make sure they match the architecture of the OCI Functions application.

For an x86 application:

archive-root/
├── main.jar
├── resources/  # optional
└── native/
    └── fn-arch-x86/

For an ARM application:

archive-root/
├── main.jar
├── resources/  # optional
└── native/
    └── fn-arch-arm/

For a multi-architecture application:

archive-root/
├── main.jar
├── resources/  # optional
└── native/
    ├── fn-arch-x86/
    └── fn-arch-arm/

Rules:

  • native/ is optional.
  • If native/ exists, do not place files directly under native/.
  • For x86 applications, native/ must contain only fn-arch-x86/.
  • For ARM applications, native/ must contain only fn-arch-arm/.
  • For multi-architecture applications, native/ must contain both fn-arch-x86/ and fn-arch-arm/.
  • Native binaries must be compiled for Linux and the correct architecture.

Java runtime behavior

For Java code-only functions, OCI Functions uses the handler value that you specify to invoke the Java method in the function archive.

You are responsible for packaging the function code and required Java dependencies in an uber/fat JAR file.

Creating a Java code-only function

To create a Java code-only function, follow the instructions in Creating Code-only Functions. For example, to create a Java code-only function using the Console:

  1. On the Applications list page, select the application in which you want to create the Java code-only function. If you need help finding the list page or the application, see Listing Applications.
  2. Select the Functions tab.

    The Functions list page opens. All functions in the selected application are displayed in a table.

  3. Select Create from archive and specify details for the Java code-only function, including the file source, the Java archive, a supported Java runtime, and a Java handler.

    For Java code-only functions, you must specify a handler when you create the function.

  4. Specify other details for the function as required (see Creating Code-only Functions).
  5. Select Create to create the function.

    The Java code-only function is created and can be invoked like any other function.

Troubleshooting

Error Code Problem Likely cause Recommended fix
400 Archive validation fails because no root JAR exists The JAR is nested under a folder such as target/ instead of at the archive root Place exactly one JAR at the archive root.
400 Archive validation fails because multiple root JARs exist More than one .jar file is present at the archive root Package a single fat or uber JAR.
400 Function fails because dependencies are missing The JAR does not include required dependencies Build a fat or uber JAR that includes dependencies.
400 Handler error Handler is missing, misspelled, or points to the wrong class or method Confirm the handler value and class/method signature.
400 Native dependency error Native library was built for the wrong architecture or OS Rebuild the native library for Linux and the correct architecture.
400 Native archive validation fails Files were placed directly under native/ Move files under native/fn-arch-x86/ or native/fn-arch-arm/.
400 Multi-architecture native archive fails validation One native architecture directory is missing Include both native/fn-arch-x86/ and native/fn-arch-arm/.