Skip to content
This repository was archived by the owner on Apr 7, 2026. It is now read-only.

Commit a313c4e

Browse files
committed
doc: add MutableCredentials Example
1 parent e238990 commit a313c4e

2 files changed

Lines changed: 99 additions & 1 deletion

File tree

samples/install-without-bom/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
<dependency>
3434
<groupId>com.google.cloud</groupId>
3535
<artifactId>google-cloud-spanner</artifactId>
36-
<version>6.110.0</version>
36+
<version>6.111.1</version>
3737
</dependency>
3838
<!-- [END spanner_install_without_bom] -->
3939

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/*
2+
* Copyright 2026 Google LLC
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.example.spanner;
18+
19+
// [START spanner_mutable_credentials]
20+
21+
import com.google.auth.oauth2.ServiceAccountCredentials;
22+
import com.google.cloud.spanner.Spanner;
23+
import com.google.cloud.spanner.SpannerOptions;
24+
import com.google.cloud.spanner.admin.database.v1.DatabaseAdminClient;
25+
import com.google.cloud.spanner.connection.MutableCredentials;
26+
import java.io.FileInputStream;
27+
import java.io.IOException;
28+
import java.nio.file.Files;
29+
import java.nio.file.Path;
30+
import java.nio.file.Paths;
31+
import java.nio.file.attribute.FileTime;
32+
import java.util.concurrent.Executors;
33+
import java.util.concurrent.ScheduledExecutorService;
34+
import java.util.concurrent.ThreadFactory;
35+
import java.util.concurrent.TimeUnit;
36+
37+
public class MutableCredentialsExample {
38+
39+
static void createClientWithMutableCredentials() throws IOException {
40+
final String credentialsPath = "location_of_service_account_credential_json";
41+
Path path = Paths.get(credentialsPath);
42+
// Use an array to hold the mutable lastModifiedTime so it can be accessed in the lambda
43+
FileTime[] lastModifiedTime = new FileTime[] {Files.getLastModifiedTime(path)};
44+
45+
// 1 - create service account credentials
46+
ServiceAccountCredentials serviceAccountCredentials;
47+
try (FileInputStream is = new FileInputStream(credentialsPath)) {
48+
serviceAccountCredentials = ServiceAccountCredentials.fromStream(is);
49+
}
50+
51+
// 2 - wrap credentials from step 1 in a MutableCredentials instance
52+
MutableCredentials mutableCredentials = new MutableCredentials(serviceAccountCredentials);
53+
54+
// 3 - set credentials on your SpannerOptions builder to your mutableCredentials
55+
SpannerOptions options = SpannerOptions.newBuilder().setCredentials(mutableCredentials).build();
56+
57+
// 4 - include logic for when/how to update your mutableCredentials
58+
// In this example we'll use a SchedulerExecutorService to periodically check for updates
59+
ThreadFactory daemonThreadFactory =
60+
runnable -> {
61+
Thread thread = new Thread(runnable, "spanner-mutable-credentials-rotator");
62+
thread.setDaemon(true);
63+
return thread;
64+
};
65+
ScheduledExecutorService executorService =
66+
Executors.newSingleThreadScheduledExecutor(daemonThreadFactory);
67+
executorService.scheduleAtFixedRate(
68+
() -> {
69+
try {
70+
FileTime currentModifiedTime = Files.getLastModifiedTime(path);
71+
if (currentModifiedTime.compareTo(lastModifiedTime[0]) > 0) {
72+
lastModifiedTime[0] = currentModifiedTime;
73+
try (FileInputStream is = new FileInputStream(credentialsPath)) {
74+
ServiceAccountCredentials credentials = ServiceAccountCredentials.fromStream(is);
75+
mutableCredentials.updateCredentials(credentials);
76+
}
77+
}
78+
} catch (IOException e) {
79+
System.err.println("Failed to check or update credentials: " + e.getMessage());
80+
}
81+
},
82+
15,
83+
15,
84+
TimeUnit.MINUTES);
85+
86+
// 5. Use the client
87+
try (Spanner spanner = options.getService();
88+
DatabaseAdminClient databaseAdminClient = spanner.createDatabaseAdminClient()) {
89+
// Perform operations...
90+
// long running client operations will always use the latest credentials wrapped in
91+
// mutableCredentials
92+
} finally {
93+
// Ensure the executor is shut down when the application exits or the client is closed
94+
executorService.shutdown();
95+
}
96+
}
97+
}
98+
// [END spanner_mutable_credentials]

0 commit comments

Comments
 (0)