Java Deployment Options
You have two choices for deploying a Java function:
- From source. For a general discussion of this topic, see Deploy a Cloud Function.
- From a pre-packaged JAR file.
Deploy from source
Your function's source code must be in the usual place for Maven projects
(src/main/java
). The sample functions in this document are directly in
src/main/java
, with no package declaration in the .java
source file. For
non-trivial code, you would likely introduce a package. If that package is
com.example
, then your hierarchy would look like this:
myfunction/ ├─ pom.xml ├─ src ├─main ├─ java ├─ com ├─ example ├─ MyFunction.java
Use the following command to deploy an HTTP function:
gcloud functions deploy $name --trigger-http \
--entry-point $function_class --runtime java21
Where:
$name
is an arbitrary, descriptive name that will be the name of the function once deployed.$name
can only contain letters, numbers, underscores, and hyphens.$function_class
is the fully qualified name of your class (for example,com.example.MyFunction
or justMyFunction
if you don't use a package).
Use the following command to deploy an event-driven function:
gcloud functions deploy $name --no-gen2 --entry-point $function_class \
--trigger-resource $resource_name \
--trigger-event $event_name \
--runtime java21
Where:
$name
is an arbitrary, descriptive name that will be the name of the function once deployed.$function_class
is the fully qualified name of your class (for example,com.example.MyFunction
or justMyFunction
if you don't use a package).$resource_name
and$event_name
are specific to the events that trigger your function. Examples of supported resources and events are Google Cloud Pub/Sub and Google Cloud Storage.
When deploying a function from source, the Google Cloud CLI uploads
the source directory (and everything in it) to Google Cloud to build. To avoid
sending unnecessary files, you can use the .gcloudignore
file. Edit the .gcloudignore
file
to ignore common directories like .git
and target/
. For example, a
.gcloudignore
file might contain the following:
.git
target
build
.idea
Deploy from a JAR
You can deploy a pre-built JAR that contains the function. This is useful
especially if you need to deploy a function that uses dependencies from a
private artifact repository that cannot be accessed from Google Cloud's
build pipeline when building from source. The JAR can be an uber JAR that
contains the function class and all of its dependency classes, or a thin JAR
that has Class-Path
entries for dependency JARs in the META-INF/MANIFEST.MF
file.
Build and deploy an Uber JAR
An uber JAR is a JAR file that contains the function classes as well as all of its dependencies. You can build an uber JAR with both Maven and Gradle. To deploy a Uber JAR, it must be the only JAR file in its own directory, for example:
my-function-deployment/ ├─ my-function-with-all-dependencies.jar
You can either copy the file into this directory structure, or use Maven and Gradle plugins to generate the correct deployment directory.
Maven
Use the Maven Shade plugin to build an uber JAR. Configure your
pom.xml
with Shade plugin:
<?xml version="1.0" encoding="UTF-8"?>
<project ...>
...
<build>
...
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
<configuration>
<outputFile>${project.build.directory}/deployment/${build.finalName}.jar</outputFile>
<transformers>
<!-- This may be needed if you need to shade a signed JAR -->
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
<resource>.SF</resource>
<resource>.DSA</resource>
<resource>.RSA</resource>
</transformer>
<!-- This is needed if you have dependencies that use Service Loader. Most Google Cloud client libraries does. -->
<transformer implementation=
"org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Build the uber JAR:
mvn package
Then deploy with the following command:
gcloud functions deploy jar-example \
--entry-point=Example \
--runtime=java21 \
--trigger-http \
--source=target/deployment
Gradle
Use the Shadow plugin for Gradle. Setup the plugin in your
build.gradle
file:
buildscript { repositories { jcenter() } dependencies { ... classpath "com.github.jengelman.gradle.plugins:shadow:5.2.0" } } plugins { id 'java' ... } sourceCompatibility = '17.0' targetCompatibility = '17.0' apply plugin: 'com.github.johnrengelman.shadow' shadowJar { mergeServiceFiles() } ...
Now you can run Gradle with the shadowJar
command:
gradle shadowJar
Then deploy with the following command:
gcloud functions deploy jar-example \
--entry-point=Example \
--runtime=java21 \
--trigger-http \
--source=build/libs
Build and deploy a thin JAR with external dependencies
You can build and deploy a thin JAR file rather than an uber JAR. A thin JAR is a JAR file that contains only the function classes without the dependencies embedded in the same JAR file. Because the dependencies are still needed for deployment, you need to set things up as follows:
- The dependencies must be in a subdirectory relative to the JAR to be deployed.
- The JAR must have a
META-INF/MANIFEST.MF
file that includes aClass-Path
attribute whose value lists the required dependency paths.
For example, your JAR file my-function.jar has a META-INF/MANIFEST.MF
file
that has 2 dependencies in the libs/
directory (a space-separated list of
relative paths):
Manifest-Version: 1.0
Class-Path: libs/dep1.jar libs/dep2.jar
Your deployment directory should then contain your main function JAR file, as well as a subdirectory with the two dependencies your function depends on:
function-deployment/ ├─ my-function.jar ├─ libs ├─ dep1.jar ├─ dep2.jar
You can build a thin JAR with both Maven and Gradle:
Maven
Use Maven JAR plugin to automatically configure MANIFEST.MF
with the paths
to the dependencies, and then use the Maven Dependency plugin to copy the dependencies.
<?xml version="1.0" encoding="UTF-8"?>
<project ...>
...
<build>
...
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>libs/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<overWriteReleases>false</overWriteReleases>
<includeScope>runtime</includeScope>
<outputDirectory>${project.build.directory}/libs</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals><goal>copy-resources</goal></goals>
<configuration>
<outputDirectory>${project.build.directory}/deployment</outputDirectory>
<resources>
<resource>
<directory>${project.build.directory}</directory>
<includes>
<include>${build.finalName}.jar</include>
<include>libs/**</include>
</includes>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Build the thin JAR:
mvn package
Then deploy with the following command:
gcloud functions deploy jar-example \
--entry-point=Example \
--runtime=java21 \
--trigger-http \
--source=target/deployment
Gradle
Update your build.gradle
project file to add a new task to fetch the
dependencies:
dependencies { // API available at compilation only, but provided at runtime compileOnly 'com.google.cloud.functions:functions-framework-api:1.0.1' // dependencies needed by the function // ... } jar { manifest { attributes( "Class-Path": provider { configurations.runtimeClasspath .collect { "libs/${it.name}" }.join(' ') } ) } } task prepareDeployment(type: Copy) { into("${buildDir}/deployment") into('.') { from jar } into('libs') { from configurations.runtimeClasspath } }