diff --git a/.github/workflows/NativeTests.yaml b/.github/workflows/NativeTests.yaml
index 49fdc8202c..9b7351c3b4 100644
--- a/.github/workflows/NativeTests.yaml
+++ b/.github/workflows/NativeTests.yaml
@@ -86,6 +86,10 @@ jobs:
components: 'native-image'
github-token: ${{ secrets.GITHUB_TOKEN }}
native-image-job-reports: 'true'
+ - name: Setup env for test
+ run: echo "SPRING_CLOUD_GCP_CI_NATIVE_SA_KEY_BASE64=$(echo -n $SA_KEY | base64 -w 0)" >> "$GITHUB_ENV"
+ env:
+ SA_KEY: ${{ secrets.SPRING_CLOUD_GCP_CI_NATIVE_SA_KEY }}
- name: Native Tests in Modules
id: intTest
env:
diff --git a/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHints.java b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHints.java
new file mode 100644
index 0000000000..2cb48a4c81
--- /dev/null
+++ b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHints.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2024 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 com.google.cloud.spring.autoconfigure.core;
+
+import com.google.cloud.spring.core.Credentials;
+import org.springframework.aot.hint.MemberCategory;
+import org.springframework.aot.hint.RuntimeHints;
+import org.springframework.aot.hint.RuntimeHintsRegistrar;
+import org.springframework.aot.hint.TypeReference;
+
+public class CredentialsRuntimeHints implements RuntimeHintsRegistrar {
+
+ @Override
+ public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
+ hints
+ .reflection()
+ .registerType(
+ TypeReference.of(Credentials.class),
+ hint ->
+ hint.withMembers(
+ MemberCategory.INVOKE_DECLARED_CONSTRUCTORS,
+ MemberCategory.INVOKE_DECLARED_METHODS,
+ MemberCategory.DECLARED_FIELDS));
+ }
+}
diff --git a/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/GcpProperties.java b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/GcpProperties.java
index 7138958224..c29a98db59 100644
--- a/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/GcpProperties.java
+++ b/spring-cloud-gcp-autoconfigure/src/main/java/com/google/cloud/spring/autoconfigure/core/GcpProperties.java
@@ -20,9 +20,11 @@
import com.google.cloud.spring.core.CredentialsSupplier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.NestedConfigurationProperty;
+import org.springframework.context.annotation.ImportRuntimeHints;
/** Top-level auto-config settings. */
@ConfigurationProperties("spring.cloud.gcp")
+@ImportRuntimeHints(CredentialsRuntimeHints.class)
public class GcpProperties implements CredentialsSupplier {
/** GCP project ID where services are running. */
diff --git a/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHintsTest.java b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHintsTest.java
new file mode 100644
index 0000000000..9c8ec26f42
--- /dev/null
+++ b/spring-cloud-gcp-autoconfigure/src/test/java/com/google/cloud/spring/autoconfigure/core/CredentialsRuntimeHintsTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2024 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 com.google.cloud.spring.autoconfigure.core;
+
+import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
+import static org.springframework.aot.hint.predicate.RuntimeHintsPredicates.reflection;
+
+import com.google.cloud.spring.core.Credentials;
+import org.junit.jupiter.api.Test;
+import org.springframework.aot.hint.RuntimeHints;
+
+class CredentialsRuntimeHintsTest {
+ @Test
+ void registerCredentials() {
+ RuntimeHints runtimeHints = new RuntimeHints();
+ CredentialsRuntimeHints registrar = new CredentialsRuntimeHints();
+ registrar.registerHints(runtimeHints, null);
+ assertThat(runtimeHints).matches(reflection().onType(Credentials.class));
+ }
+}
diff --git a/spring-cloud-gcp-samples/pom.xml b/spring-cloud-gcp-samples/pom.xml
index e993507d60..fdb1a5a746 100644
--- a/spring-cloud-gcp-samples/pom.xml
+++ b/spring-cloud-gcp-samples/pom.xml
@@ -143,6 +143,7 @@
true
true
true
+ true
true
true
true
@@ -160,6 +161,7 @@
${env.DB_PASSWORD}
projects/spring-cloud-gcp-ci-native/locations/us-central1/clusters/testcluster/instances/testpostgres
code_samples_test_db
+ ${env.SPRING_CLOUD_GCP_CI_NATIVE_SA_KEY_BASE64}
diff --git a/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/main/java/com/example/FirestoreSampleApp.java b/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/main/java/com/example/FirestoreSampleApp.java
index c9c11f9676..5e8309d6b5 100644
--- a/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/main/java/com/example/FirestoreSampleApp.java
+++ b/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/main/java/com/example/FirestoreSampleApp.java
@@ -31,6 +31,7 @@
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ImportRuntimeHints;
@@ -53,6 +54,7 @@ public static void main(String[] args) {
}
@Bean
+ @ConditionalOnProperty(name = "run.commandline.runner", havingValue = "true", matchIfMissing = true)
public CommandLineRunner commandLineRunner() {
return args -> {
writeDocumentFromMap();
diff --git a/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/test/java/com/example/FirestoreSampleAppNativeIntegrationTests.java b/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/test/java/com/example/FirestoreSampleAppNativeIntegrationTests.java
new file mode 100644
index 0000000000..4af36460d5
--- /dev/null
+++ b/spring-cloud-gcp-samples/spring-cloud-gcp-starter-firestore-sample/src/test/java/com/example/FirestoreSampleAppNativeIntegrationTests.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2024 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 com.example;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import com.google.cloud.spring.autoconfigure.firestore.GcpFirestoreProperties;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.context.ApplicationContext;
+import org.springframework.test.context.TestPropertySource;
+import org.springframework.test.context.junit.jupiter.SpringExtension;
+
+@EnabledIfSystemProperty(named = "it.firestore.native", matches = "true")
+@ExtendWith(SpringExtension.class)
+@TestPropertySource("classpath:application-test.properties")
+@SpringBootTest(properties = "run.commandline.runner=off")
+public class FirestoreSampleAppNativeIntegrationTests {
+
+ private final Logger logger =
+ LoggerFactory.getLogger(FirestoreSampleAppNativeIntegrationTests.class);
+ @Autowired private ApplicationContext applicationContext;
+
+ @Test
+ void credentialsPropertiesAreAccessibleTest() {
+ logger.info(
+ "This test is only needed for graalvm compilation test"
+ + " to verify the encoded-key property is accessible."
+ + " Turn on by it.firestore.native=true");
+ String encodedKeyFromAutoConfig =
+ applicationContext.getBean(GcpFirestoreProperties.class).getCredentials().getEncodedKey();
+ assertNotNull(encodedKeyFromAutoConfig);
+ }
+}