diff --git a/README.md b/README.md
index 2445a62f..b967617c 100644
--- a/README.md
+++ b/README.md
@@ -57,13 +57,13 @@ implementation 'com.google.cloud:google-cloud-secretmanager'
If you are using Gradle without BOM, add this to your dependencies
```Groovy
-implementation 'com.google.cloud:google-cloud-secretmanager:2.1.1'
+implementation 'com.google.cloud:google-cloud-secretmanager:2.1.2'
```
If you are using SBT, add this to your dependencies
```Scala
-libraryDependencies += "com.google.cloud" % "google-cloud-secretmanager" % "2.1.1"
+libraryDependencies += "com.google.cloud" % "google-cloud-secretmanager" % "2.1.2"
```
## Authentication
@@ -107,6 +107,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-secretmanager
| Sample | Source Code | Try it |
| --------------------------- | --------------------------------- | ------ |
+| Native Image Secret Manager Sample | [source code](https://github.com/googleapis/java-secretmanager/blob/main/samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-secretmanager&page=editor&open_in_editor=samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java) |
| Access Secret Version | [source code](https://github.com/googleapis/java-secretmanager/blob/main/samples/snippets/src/main/java/secretmanager/AccessSecretVersion.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-secretmanager&page=editor&open_in_editor=samples/snippets/src/main/java/secretmanager/AccessSecretVersion.java) |
| Add Secret Version | [source code](https://github.com/googleapis/java-secretmanager/blob/main/samples/snippets/src/main/java/secretmanager/AddSecretVersion.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-secretmanager&page=editor&open_in_editor=samples/snippets/src/main/java/secretmanager/AddSecretVersion.java) |
| Create Secret | [source code](https://github.com/googleapis/java-secretmanager/blob/main/samples/snippets/src/main/java/secretmanager/CreateSecret.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-secretmanager&page=editor&open_in_editor=samples/snippets/src/main/java/secretmanager/CreateSecret.java) |
diff --git a/samples/native-image-sample/README.md b/samples/native-image-sample/README.md
new file mode 100644
index 00000000..326375d2
--- /dev/null
+++ b/samples/native-image-sample/README.md
@@ -0,0 +1,78 @@
+# Secret Manager Sample Application with Native Image
+
+The Secret Manager sample application demonstrates some common operations with [Google Cloud Secret Manager](https://cloud.google.com/secret-manager) and is compatible with Native Image compilation.
+
+This application will create a new secret named `native-secretmanager-test-secret` if it does not already exist.
+It will then add a new version of the secret and then attempt to read it.
+
+## Setup Instructions
+
+You will need to follow these prerequisite steps in order to run these samples:
+
+1. If you have not already, [create a Google Cloud Platform Project](https://cloud.google.com/resource-manager/docs/creating-managing-projects#creating_a_project).
+
+2. Install the [Google Cloud SDK](https://cloud.google.com/sdk/) which will allow you to run the sample with your project's credentials.
+
+ Once installed, log in with Application Default Credentials using the following command:
+
+ ```
+ gcloud auth application-default login
+ ```
+
+ **Note:** Authenticating with Application Default Credentials is convenient to use during development, but we recommend [alternate methods of authentication](https://cloud.google.com/docs/authentication/production) during production use.
+
+3. Install the GraalVM compiler.
+
+ You can follow the [official installation instructions](https://www.graalvm.org/docs/getting-started/#install-graalvm) from the GraalVM website.
+ After following the instructions, ensure that you install the Native Image extension installed by running:
+
+ ```
+ gu install native-image
+ ```
+
+ Once you finish following the instructions, verify that the default version of Java is set to the GraalVM version by running `java -version` in a terminal.
+
+ You will see something similar to the below output:
+
+ ```
+ $ java -version
+
+ openjdk version "11.0.7" 2020-04-14
+ OpenJDK Runtime Environment GraalVM CE 20.1.0 (build 11.0.7+10-jvmci-20.1-b02)
+ OpenJDK 64-Bit Server VM GraalVM CE 20.1.0 (build 11.0.7+10-jvmci-20.1-b02, mixed mode, sharing)
+ ```
+
+4. [Enable the Secret Manager APIs](https://console.cloud.google.com/apis/api/secretmanager.googleapis.com).
+
+### Run with Native Image Compilation
+
+Navigate to this directory in a new terminal.
+
+1. Compile the application using the Native Image Compiler. This step may take a few minutes.
+
+ ```
+ mvn package -P native -DskipTests
+ ```
+
+2. Run the application:
+
+ ```
+ ./target/native-image-sample
+ ```
+
+3. The application runs through some basic Secret Manager operations (create, update, read) and then prints some results of the operations.
+
+ ```
+ Created secret: projects/xxxxxx/secrets/graal-secretmanager-test-secret
+ Added Secret Version: projects/xxxxxx/secrets/graal-secretmanager-test-secret/versions/1
+ Reading secret value: Hello World
+ (Note: Don't print secret values in prod!)
+ ```
+
+## Sample Integration test with Native Image Support
+
+In order to run the sample integration test as a native image, call the following command:
+
+ ```
+ mvn test -Pnative
+ ```
\ No newline at end of file
diff --git a/samples/native-image-sample/pom.xml b/samples/native-image-sample/pom.xml
new file mode 100644
index 00000000..73150240
--- /dev/null
+++ b/samples/native-image-sample/pom.xml
@@ -0,0 +1,173 @@
+
+
+ 4.0.0
+ com.google.cloud
+ native-image-sample
+ Native Image Sample
+ https://github.com/googleapis/java-secretmanager
+
+
+
+ com.google.cloud.samples
+ shared-configuration
+ 1.2.0
+
+
+
+
+ 1.8
+ 1.8
+ UTF-8
+
+
+
+
+
+ com.google.cloud
+ libraries-bom
+ 24.3.0
+ pom
+ import
+
+
+
+
+
+
+ com.google.cloud
+ google-cloud-core
+
+
+ com.google.cloud
+ google-cloud-secretmanager
+
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+ com.google.truth
+ truth
+ 1.1.3
+ test
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.2.2
+
+
+
+ true
+ dependency-jars/
+ secretmanager.NativeImageSecretManagerSample
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 3.2.0
+
+
+ copy-dependencies
+ package
+
+ copy-dependencies
+
+
+
+ ${project.build.directory}/dependency-jars/
+
+
+
+
+
+
+
+
+
+
+
+ native
+
+
+
+ com.google.cloud
+ native-image-support
+ 0.12.0
+
+
+ org.junit.vintage
+ junit-vintage-engine
+ 5.8.2
+ test
+
+
+ org.graalvm.buildtools
+ junit-platform-native
+ 0.9.9
+ test
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+
+ 2.22.2
+
+
+ **/*IT
+
+
+
+
+ org.graalvm.buildtools
+ native-maven-plugin
+ 0.9.9
+ true
+
+ secretmanager.NativeImageSecretManagerSample
+
+ --no-fallback
+ --no-server
+
+
+
+
+ build-native
+
+ build
+ test
+
+ package
+
+
+ test-native
+
+ test
+
+ test
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java b/samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java
new file mode 100644
index 00000000..b4b660a9
--- /dev/null
+++ b/samples/native-image-sample/src/main/java/secretmanager/NativeImageSecretManagerSample.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package secretmanager;
+
+import com.google.cloud.ServiceOptions;
+import com.google.cloud.secretmanager.v1.AccessSecretVersionResponse;
+import com.google.cloud.secretmanager.v1.ProjectName;
+import com.google.cloud.secretmanager.v1.Replication;
+import com.google.cloud.secretmanager.v1.Secret;
+import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
+import com.google.cloud.secretmanager.v1.SecretManagerServiceClient.ListSecretsPagedResponse;
+import com.google.cloud.secretmanager.v1.SecretName;
+import com.google.cloud.secretmanager.v1.SecretPayload;
+import com.google.cloud.secretmanager.v1.SecretVersion;
+import com.google.protobuf.ByteString;
+import java.io.IOException;
+
+/**
+ * Sample application demonstrating Native Image compatibility with Google Cloud Secret Manager
+ * APIs.
+ */
+public class NativeImageSecretManagerSample {
+
+ private static final String NATIVE_TEST_SECRET_ID = "native-secretmanager-test-secret";
+
+ /** Runs the Secret Manager sample application. */
+ public static void main(String[] args) throws IOException {
+ String projectId = ServiceOptions.getDefaultProjectId();
+
+ try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) {
+ if (!hasSecret(client, projectId, NATIVE_TEST_SECRET_ID)) {
+ createSecret(client, projectId, NATIVE_TEST_SECRET_ID);
+ } else {
+ System.out.println("Project already has secret: " + NATIVE_TEST_SECRET_ID);
+ }
+
+ SecretVersion version = addSecretVersion(client, projectId, NATIVE_TEST_SECRET_ID);
+ printSecretVersion(client, version);
+ }
+ }
+
+ static void createSecret(SecretManagerServiceClient client, String projectId, String secretId) {
+
+ Secret secret =
+ Secret.newBuilder()
+ .setReplication(
+ Replication.newBuilder()
+ .setAutomatic(Replication.Automatic.newBuilder().build())
+ .build())
+ .build();
+ ProjectName projectName = ProjectName.of(projectId);
+ Secret createdSecret = client.createSecret(projectName, secretId, secret);
+ System.out.println("Created secret: " + createdSecret.getName());
+ }
+
+ static boolean hasSecret(SecretManagerServiceClient client, String projectId, String secretId) {
+
+ ProjectName projectName = ProjectName.of(projectId);
+ ListSecretsPagedResponse pagedResponse = client.listSecrets(projectName);
+
+ for (Secret secret : pagedResponse.iterateAll()) {
+ String otherSecretId = extractSecretId(secret);
+ if (secretId.equals(otherSecretId)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ static SecretVersion addSecretVersion(
+ SecretManagerServiceClient client, String projectId, String secretId) {
+
+ SecretName secretName = SecretName.of(projectId, secretId);
+ SecretPayload payload =
+ SecretPayload.newBuilder().setData(ByteString.copyFromUtf8("Hello World")).build();
+
+ SecretVersion version = client.addSecretVersion(secretName, payload);
+ System.out.println("Added Secret Version: " + version.getName());
+ return version;
+ }
+
+ static void printSecretVersion(SecretManagerServiceClient client, SecretVersion version) {
+ AccessSecretVersionResponse response = client.accessSecretVersion(version.getName());
+ String payload = response.getPayload().getData().toStringUtf8();
+ System.out.println("Reading secret value: " + payload);
+ System.out.println("(Note: Don't print secret values in prod!)");
+ }
+
+ /**
+ * Returns the secret ID from the fully-qualified secret name which has the format:
+ * projects/YOUR_PROJECT_ID/secrets/YOUR_SECRET_ID.
+ */
+ private static String extractSecretId(Secret secret) {
+ String[] secretNameTokens = secret.getName().split("/");
+ return secretNameTokens[secretNameTokens.length - 1];
+ }
+}
diff --git a/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java b/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java
new file mode 100644
index 00000000..653c6b41
--- /dev/null
+++ b/samples/native-image-sample/src/test/java/secretmanager/NativeImageSecretManagerSampleIT.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package secretmanager;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.cloud.ServiceOptions;
+import com.google.cloud.secretmanager.v1.DeleteSecretRequest;
+import com.google.cloud.secretmanager.v1.SecretManagerServiceClient;
+import com.google.cloud.secretmanager.v1.SecretName;
+import com.google.cloud.secretmanager.v1.SecretVersion;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.UUID;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+public class NativeImageSecretManagerSampleIT {
+
+ private static final String NATIVE_TEST_SECRET_ID = "native-test-secret" + UUID.randomUUID();
+ private static String PROJECT_ID = ServiceOptions.getDefaultProjectId();
+ private ByteArrayOutputStream bout;
+
+ @Before
+ public void setUp() {
+ bout = new ByteArrayOutputStream();
+ System.setOut(new PrintStream(bout));
+ }
+
+ @AfterClass
+ public static void afterAll() throws Exception {
+ try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) {
+
+ // Delete the secret created by quickstart
+ SecretName name = SecretName.of(PROJECT_ID, NATIVE_TEST_SECRET_ID);
+ DeleteSecretRequest deleteRequest =
+ DeleteSecretRequest.newBuilder().setName(name.toString()).build();
+
+ client.deleteSecret(deleteRequest);
+ }
+ }
+
+ @Test
+ public void testCreateAndPrintSecret() throws IOException {
+ try (SecretManagerServiceClient client = SecretManagerServiceClient.create()) {
+ NativeImageSecretManagerSample.createSecret(client, PROJECT_ID, NATIVE_TEST_SECRET_ID);
+ SecretVersion version =
+ NativeImageSecretManagerSample.addSecretVersion(
+ client, PROJECT_ID, NATIVE_TEST_SECRET_ID);
+ NativeImageSecretManagerSample.printSecretVersion(client, version);
+ assertThat(bout.toString()).contains("Reading secret value: Hello World");
+ }
+ }
+}
diff --git a/samples/pom.xml b/samples/pom.xml
index 4a0dcba6..b8efa4c0 100644
--- a/samples/pom.xml
+++ b/samples/pom.xml
@@ -31,6 +31,7 @@
install-without-bom
snapshot
snippets
+ native-image-sample