DDL_STATEMENTS =
+ ImmutableList.of(
+ "CREATE TABLE Singers (SingerId INT64 NOT NULL, FirstName "
+ + "STRING(1024), LastName STRING(1024)) PRIMARY KEY (SingerId)");
+
+ static void createDatabase(
+ DatabaseAdminClient databaseAdminClient, String instanceId, String databaseId) {
+
+ if (databaseExists(databaseAdminClient, instanceId, databaseId)) {
+ databaseAdminClient.dropDatabase(instanceId, databaseId);
+ }
+ databaseAdminClient.createDatabase(instanceId, databaseId, DDL_STATEMENTS);
+ }
+
+ static boolean databaseExists(
+ DatabaseAdminClient databaseAdminClient, String instanceId, String databaseId) {
+
+ for (Database database : databaseAdminClient.listDatabases(instanceId).iterateAll()) {
+ if (databaseId.equals(database.getId().getDatabase())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static void insertUsingDml(DatabaseClient dbClient) {
+ dbClient
+ .readWriteTransaction()
+ .run(
+ transaction -> {
+ String sql =
+ "INSERT INTO Singers (SingerId, FirstName, LastName) "
+ + " VALUES (10, 'Virginia', 'Watson')";
+ transaction.executeUpdate(Statement.of(sql));
+ return null;
+ });
+ }
+
+ static void insertUsingMutation(DatabaseClient dbClient) {
+ Mutation mutation =
+ Mutation.newInsertBuilder("Singers")
+ .set("SingerId")
+ .to(12)
+ .set("FirstName")
+ .to("Bob")
+ .set("LastName")
+ .to("Loblaw")
+ .build();
+ dbClient.write(Collections.singletonList(mutation));
+ }
+
+ static ResultSet performRead(DatabaseClient dbClient) {
+ return dbClient.singleUse().executeQuery(Statement.of("SELECT * FROM Singers"));
+ }
+
+ static void deleteDatabase(DatabaseClient dbClient) {
+ dbClient.write(Collections.singletonList(Mutation.delete("Singers", KeySet.all())));
+ System.out.println("Records deleted.");
+ }
+}
diff --git a/samples/native-image/src/main/java/com/example/spanner/InstanceOperations.java b/samples/native-image/src/main/java/com/example/spanner/InstanceOperations.java
new file mode 100644
index 0000000000..75efd6b45b
--- /dev/null
+++ b/samples/native-image/src/main/java/com/example/spanner/InstanceOperations.java
@@ -0,0 +1,57 @@
+/*
+ * 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
+ *
+ * http://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 com.example.spanner;
+
+import com.google.cloud.spanner.Instance;
+import com.google.cloud.spanner.InstanceAdminClient;
+import com.google.cloud.spanner.InstanceConfigId;
+import com.google.cloud.spanner.InstanceId;
+import com.google.cloud.spanner.InstanceInfo;
+
+/** Helper methods to manage Spanner instances. */
+public class InstanceOperations {
+
+ static void createTestInstance(
+ InstanceAdminClient instanceAdminClient, String projectId, String instanceId)
+ throws Exception {
+
+ if (instanceExists(instanceAdminClient, instanceId)) {
+ instanceAdminClient.deleteInstance(instanceId);
+ }
+
+ InstanceInfo instanceInfo =
+ InstanceInfo.newBuilder(InstanceId.of(projectId, instanceId))
+ .setInstanceConfigId(InstanceConfigId.of(projectId, "regional-us-central1"))
+ .setNodeCount(1)
+ .setDisplayName(instanceId)
+ .build();
+ try {
+ instanceAdminClient.createInstance(instanceInfo).get();
+ } catch (Exception e) {
+ throw new Exception("Failed to create Spanner instance.", e);
+ }
+ }
+
+ static boolean instanceExists(InstanceAdminClient instanceAdminClient, String instanceName) {
+ for (Instance instance : instanceAdminClient.listInstances().iterateAll()) {
+ if (instanceName.equals(instance.getId().getInstance())) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/samples/native-image/src/main/java/com/example/spanner/NativeImageSpannerSample.java b/samples/native-image/src/main/java/com/example/spanner/NativeImageSpannerSample.java
new file mode 100644
index 0000000000..b71404daf0
--- /dev/null
+++ b/samples/native-image/src/main/java/com/example/spanner/NativeImageSpannerSample.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
+ *
+ * http://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 com.example.spanner;
+
+import com.google.cloud.spanner.DatabaseAdminClient;
+import com.google.cloud.spanner.DatabaseClient;
+import com.google.cloud.spanner.DatabaseId;
+import com.google.cloud.spanner.InstanceAdminClient;
+import com.google.cloud.spanner.ResultSet;
+import com.google.cloud.spanner.Spanner;
+import com.google.cloud.spanner.SpannerOptions;
+
+/** Sample Spanner application compiled with Native Image. */
+public class NativeImageSpannerSample {
+
+ private static final String TEST_INSTANCE_ID = "test-instance";
+ private static final String TEST_DATABASE_ID = "test-database";
+
+ /**
+ * Runs the Spanner sample application.
+ *
+ * This application should be run with the Spanner emulator for testing purposes.
+ */
+ public static void main(String[] args) throws Exception {
+ System.out.println("Running the Spanner Sample.");
+
+ SpannerOptions options = SpannerOptions.newBuilder().build();
+ Spanner spanner = options.getService();
+
+ // Setup the Spanner environment.
+ InstanceAdminClient instanceAdminClient = spanner.getInstanceAdminClient();
+ DatabaseAdminClient databaseAdminClient = spanner.getDatabaseAdminClient();
+
+ InstanceOperations.createTestInstance(
+ instanceAdminClient, options.getProjectId(), TEST_INSTANCE_ID);
+ DatabaseOperations.createDatabase(databaseAdminClient, TEST_INSTANCE_ID, TEST_DATABASE_ID);
+
+ // Insert data
+ DatabaseClient dbClient =
+ spanner.getDatabaseClient(
+ DatabaseId.of(options.getProjectId(), TEST_INSTANCE_ID, TEST_DATABASE_ID));
+ DatabaseOperations.insertUsingDml(dbClient);
+ DatabaseOperations.insertUsingMutation(dbClient);
+
+ // Run some queries.
+ ResultSet resultSet = DatabaseOperations.performRead(dbClient);
+ System.out.println("Singers Registered in Spanner:");
+ while (resultSet.next()) {
+ System.out.println(resultSet.getString("FirstName") + " " + resultSet.getString("LastName"));
+ }
+ if (DatabaseOperations.databaseExists(
+ databaseAdminClient, TEST_INSTANCE_ID, TEST_DATABASE_ID)) {
+ DatabaseOperations.deleteDatabase(dbClient);
+ }
+ }
+}
diff --git a/samples/native-image/src/test/java/com/example/spanner/NativeImageSpannerSampleIT.java b/samples/native-image/src/test/java/com/example/spanner/NativeImageSpannerSampleIT.java
new file mode 100644
index 0000000000..ce47de9273
--- /dev/null
+++ b/samples/native-image/src/test/java/com/example/spanner/NativeImageSpannerSampleIT.java
@@ -0,0 +1,36 @@
+/*
+ * 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
+ *
+ * http://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 com.example.spanner;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import com.google.cloud.testing.junit4.StdOutCaptureRule;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class NativeImageSpannerSampleIT {
+
+ @Rule public StdOutCaptureRule stdOut = new StdOutCaptureRule();
+
+ @Test
+ public void testStoreAndRead() throws Exception {
+ NativeImageSpannerSample.main(new String[] {});
+ assertThat(stdOut.getCapturedOutputAsUtf8String()).contains("Singers Registered in Spanner:");
+ assertThat(stdOut.getCapturedOutputAsUtf8String()).contains("Virginia Watson");
+ assertThat(stdOut.getCapturedOutputAsUtf8String()).contains("Bob Loblaw");
+ }
+}
diff --git a/samples/pom.xml b/samples/pom.xml
index b46876310d..2556f678e8 100644
--- a/samples/pom.xml
+++ b/samples/pom.xml
@@ -31,6 +31,7 @@
install-without-bom
snapshot
snippets
+ native-image