diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9f935e9b83..9e8c39bca6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# Changelog
+## [3.30.10](https://github.com/googleapis/java-firestore/compare/v3.30.9...v3.30.10) (2025-03-06)
+
+
+### Bug Fixes
+
+* Use lazy encoding in UTF-8 encoded string comparison ([#2021](https://github.com/googleapis/java-firestore/issues/2021)) ([11a4c74](https://github.com/googleapis/java-firestore/commit/11a4c743beddbc7415ef0157bbc4f545a27509f7))
+
+
+### Dependencies
+
+* Update dependency com.google.api.grpc:proto-google-cloud-trace-v1 to v2.59.0 ([#2030](https://github.com/googleapis/java-firestore/issues/2030)) ([38d80ac](https://github.com/googleapis/java-firestore/commit/38d80ac587351c2c675e669f126a7825bba7235c))
+* Update dependency com.google.cloud:google-cloud-trace to v2.59.0 ([#2031](https://github.com/googleapis/java-firestore/issues/2031)) ([73a68a6](https://github.com/googleapis/java-firestore/commit/73a68a69e156cff1bf1ca6652ddd6e8dc58cf3f3))
+
## [3.30.9](https://github.com/googleapis/java-firestore/compare/v3.30.8...v3.30.9) (2025-02-26)
diff --git a/README.md b/README.md
index d3ec77054b..474b687e1c 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,7 @@ If you are using Maven with [BOM][libraries-bom], add this to your pom.xml file:
com.google.cloud
libraries-bom
- 26.55.0
+ 26.56.0
pom
import
@@ -41,7 +41,7 @@ If you are using Maven without the BOM, add this to your dependencies:
com.google.cloud
google-cloud-firestore
- 3.30.8
+ 3.30.9
```
@@ -56,13 +56,13 @@ implementation 'com.google.cloud:google-cloud-firestore'
If you are using Gradle without BOM, add this to your dependencies:
```Groovy
-implementation 'com.google.cloud:google-cloud-firestore:3.30.9'
+implementation 'com.google.cloud:google-cloud-firestore:3.30.10'
```
If you are using SBT, add this to your dependencies:
```Scala
-libraryDependencies += "com.google.cloud" % "google-cloud-firestore" % "3.30.9"
+libraryDependencies += "com.google.cloud" % "google-cloud-firestore" % "3.30.10"
```
## Authentication
@@ -219,7 +219,7 @@ Java is a registered trademark of Oracle and/or its affiliates.
[kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-firestore/java11.html
[stability-image]: https://img.shields.io/badge/stability-stable-green
[maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-firestore.svg
-[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-firestore/3.30.9
+[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-firestore/3.30.10
[authentication]: https://github.com/googleapis/google-cloud-java#authentication
[auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes
[predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles
diff --git a/google-cloud-firestore-admin/pom.xml b/google-cloud-firestore-admin/pom.xml
index 9aff119575..abfbe6deda 100644
--- a/google-cloud-firestore-admin/pom.xml
+++ b/google-cloud-firestore-admin/pom.xml
@@ -4,7 +4,7 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0
google-cloud-firestore-admin
- 3.30.9
+ 3.30.10
jar
Google Cloud Firestore Admin Client
https://github.com/googleapis/java-firestore
@@ -14,7 +14,7 @@
com.google.cloud
google-cloud-firestore-parent
- 3.30.9
+ 3.30.10
diff --git a/google-cloud-firestore-bom/pom.xml b/google-cloud-firestore-bom/pom.xml
index 794a6e7439..9c0d745eb1 100644
--- a/google-cloud-firestore-bom/pom.xml
+++ b/google-cloud-firestore-bom/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.google.cloud
google-cloud-firestore-bom
- 3.30.9
+ 3.30.10
pom
com.google.cloud
@@ -52,37 +52,37 @@
com.google.cloud
google-cloud-firestore
- 3.30.9
+ 3.30.10
com.google.cloud
google-cloud-firestore-admin
- 3.30.9
+ 3.30.10
com.google.api.grpc
grpc-google-cloud-firestore-admin-v1
- 3.30.9
+ 3.30.10
com.google.api.grpc
grpc-google-cloud-firestore-v1
- 3.30.9
+ 3.30.10
com.google.api.grpc
proto-google-cloud-firestore-admin-v1
- 3.30.9
+ 3.30.10
com.google.api.grpc
proto-google-cloud-firestore-v1
- 3.30.9
+ 3.30.10
com.google.cloud
proto-google-cloud-firestore-bundle-v1
- 3.30.9
+ 3.30.10
diff --git a/google-cloud-firestore/pom.xml b/google-cloud-firestore/pom.xml
index 217fa4e743..5ae64d5450 100644
--- a/google-cloud-firestore/pom.xml
+++ b/google-cloud-firestore/pom.xml
@@ -2,7 +2,7 @@
4.0.0
google-cloud-firestore
- 3.30.9
+ 3.30.10
jar
Google Cloud Firestore
https://github.com/googleapis/java-firestore
@@ -12,7 +12,7 @@
com.google.cloud
google-cloud-firestore-parent
- 3.30.9
+ 3.30.10
google-cloud-firestore
@@ -228,13 +228,13 @@
com.google.api.grpc
proto-google-cloud-trace-v1
- 2.58.0
+ 2.59.0
test
com.google.cloud
google-cloud-trace
- 2.58.0
+ 2.59.0
test
diff --git a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Order.java b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Order.java
index 4cd58c95bf..7f37d8e05f 100644
--- a/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Order.java
+++ b/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Order.java
@@ -136,9 +136,44 @@ public int compare(@Nonnull Value left, @Nonnull Value right) {
/** Compare strings in UTF-8 encoded byte order */
public static int compareUtf8Strings(String left, String right) {
- ByteString leftBytes = ByteString.copyFromUtf8(left);
- ByteString rightBytes = ByteString.copyFromUtf8(right);
- return compareByteStrings(leftBytes, rightBytes);
+ int i = 0;
+ while (i < left.length() && i < right.length()) {
+ int leftCodePoint = left.codePointAt(i);
+ int rightCodePoint = right.codePointAt(i);
+
+ if (leftCodePoint != rightCodePoint) {
+ if (leftCodePoint < 128 && rightCodePoint < 128) {
+ // ASCII comparison
+ return Integer.compare(leftCodePoint, rightCodePoint);
+ } else {
+ // UTF-8 encode the character at index i for byte comparison.
+ ByteString leftBytes = ByteString.copyFromUtf8(getUtf8SafeBytes(left, i));
+ ByteString rightBytes = ByteString.copyFromUtf8(getUtf8SafeBytes(right, i));
+ int comp = compareByteStrings(leftBytes, rightBytes);
+ if (comp != 0) {
+ return comp;
+ } else {
+ // EXTREMELY RARE CASE: Code points differ, but their UTF-8 byte representations are
+ // identical. This can happen with malformed input (invalid surrogate pairs), where
+ // Java's encoding leads to unexpected byte sequences. Meanwhile, any invalid surrogate
+ // inputs get converted to "?" by protocol buffer while round tripping, so we almost
+ // never receive invalid strings from backend.
+ // Fallback to code point comparison for graceful handling.
+ return Integer.compare(leftCodePoint, rightCodePoint);
+ }
+ }
+ }
+ // Increment by 2 for surrogate pairs, 1 otherwise.
+ i += Character.charCount(leftCodePoint);
+ }
+
+ // Compare lengths if all characters are equal
+ return Integer.compare(left.length(), right.length());
+ }
+
+ private static String getUtf8SafeBytes(String str, int index) {
+ int firstCodePoint = str.codePointAt(index);
+ return str.substring(index, index + Character.charCount(firstCodePoint));
}
private int compareBlobs(Value left, Value right) {
@@ -147,7 +182,7 @@ private int compareBlobs(Value left, Value right) {
return compareByteStrings(leftBytes, rightBytes);
}
- private static int compareByteStrings(ByteString leftBytes, ByteString rightBytes) {
+ static int compareByteStrings(ByteString leftBytes, ByteString rightBytes) {
int size = Math.min(leftBytes.size(), rightBytes.size());
for (int i = 0; i < size; i++) {
// Make sure the bytes are unsigned
diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/OrderTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/OrderTest.java
index c4993b4444..076cbf2db3 100644
--- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/OrderTest.java
+++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/OrderTest.java
@@ -16,7 +16,10 @@
package com.google.cloud.firestore;
+import static com.google.cloud.firestore.Order.compareByteStrings;
+import static com.google.cloud.firestore.Order.compareUtf8Strings;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.fail;
import com.google.firestore.v1.ArrayValue;
import com.google.firestore.v1.MapValue;
@@ -25,7 +28,9 @@
import com.google.protobuf.NullValue;
import com.google.protobuf.Timestamp;
import com.google.type.LatLng;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Random;
import org.junit.Test;
public class OrderTest {
@@ -194,4 +199,184 @@ private Value objectValue(String key, Value value, Object... keysAndValues) {
return Value.newBuilder().setMapValue(mapBuilder.build()).build();
}
+
+ @Test
+ public void compareUtf8StringsShouldReturnCorrectValue() {
+ ArrayList errors = new ArrayList<>();
+ int seed = new Random().nextInt(Integer.MAX_VALUE);
+ int passCount = 0;
+ StringGenerator stringGenerator = new StringGenerator(29750468);
+ StringPairGenerator stringPairGenerator = new StringPairGenerator(stringGenerator);
+ for (int i = 0; i < 1_000_000 && errors.size() < 10; i++) {
+ StringPairGenerator.StringPair stringPair = stringPairGenerator.next();
+ final String s1 = stringPair.s1;
+ final String s2 = stringPair.s2;
+
+ int actual = compareUtf8Strings(s1, s2);
+
+ ByteString b1 = ByteString.copyFromUtf8(s1);
+ ByteString b2 = ByteString.copyFromUtf8(s2);
+ int expected = compareByteStrings(b1, b2);
+
+ if (actual == expected) {
+ passCount++;
+ } else {
+ errors.add(
+ "compareUtf8Strings(s1=\""
+ + s1
+ + "\", s2=\""
+ + s2
+ + "\") returned "
+ + actual
+ + ", but expected "
+ + expected
+ + " (i="
+ + i
+ + ", s1.length="
+ + s1.length()
+ + ", s2.length="
+ + s2.length()
+ + ")");
+ }
+ }
+
+ if (!errors.isEmpty()) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(errors.size()).append(" test cases failed, ");
+ sb.append(passCount).append(" test cases passed, ");
+ sb.append("seed=").append(seed).append(";");
+ for (int i = 0; i < errors.size(); i++) {
+ sb.append("\nerrors[").append(i).append("]: ").append(errors.get(i));
+ }
+ fail(sb.toString());
+ }
+ }
+
+ private static class StringPairGenerator {
+
+ private final StringGenerator stringGenerator;
+
+ public StringPairGenerator(StringGenerator stringGenerator) {
+ this.stringGenerator = stringGenerator;
+ }
+
+ public StringPair next() {
+ String prefix = stringGenerator.next();
+ String s1 = prefix + stringGenerator.next();
+ String s2 = prefix + stringGenerator.next();
+ return new StringPair(s1, s2);
+ }
+
+ public static class StringPair {
+ public final String s1, s2;
+
+ public StringPair(String s1, String s2) {
+ this.s1 = s1;
+ this.s2 = s2;
+ }
+ }
+ }
+
+ private static class StringGenerator {
+
+ private static final float DEFAULT_SURROGATE_PAIR_PROBABILITY = 0.33f;
+ private static final int DEFAULT_MAX_LENGTH = 20;
+
+ private static final int MIN_HIGH_SURROGATE = 0xD800;
+ private static final int MAX_HIGH_SURROGATE = 0xDBFF;
+ private static final int MIN_LOW_SURROGATE = 0xDC00;
+ private static final int MAX_LOW_SURROGATE = 0xDFFF;
+
+ private final Random rnd;
+ private final float surrogatePairProbability;
+ private final int maxLength;
+
+ public StringGenerator(int seed) {
+ this(new Random(seed), DEFAULT_SURROGATE_PAIR_PROBABILITY, DEFAULT_MAX_LENGTH);
+ }
+
+ public StringGenerator(Random rnd, float surrogatePairProbability, int maxLength) {
+ this.rnd = rnd;
+ this.surrogatePairProbability = validateProbability(surrogatePairProbability);
+ this.maxLength = validateLength(maxLength);
+ }
+
+ private static float validateProbability(float probability) {
+ if (!Float.isFinite(probability)) {
+ throw new IllegalArgumentException(
+ "invalid surrogate pair probability: "
+ + probability
+ + " (must be between 0.0 and 1.0, inclusive)");
+ } else if (probability < 0.0f) {
+ throw new IllegalArgumentException(
+ "invalid surrogate pair probability: "
+ + probability
+ + " (must be greater than or equal to zero)");
+ } else if (probability > 1.0f) {
+ throw new IllegalArgumentException(
+ "invalid surrogate pair probability: "
+ + probability
+ + " (must be less than or equal to 1)");
+ }
+ return probability;
+ }
+
+ private static int validateLength(int length) {
+ if (length < 0) {
+ throw new IllegalArgumentException(
+ "invalid maximum string length: "
+ + length
+ + " (must be greater than or equal to zero)");
+ }
+ return length;
+ }
+
+ public String next() {
+ final int length = rnd.nextInt(maxLength + 1);
+ final StringBuilder sb = new StringBuilder();
+ while (sb.length() < length) {
+ int codePoint = nextCodePoint();
+ sb.appendCodePoint(codePoint);
+ }
+ return sb.toString();
+ }
+
+ private boolean isNextSurrogatePair() {
+ return nextBoolean(rnd, surrogatePairProbability);
+ }
+
+ private static boolean nextBoolean(Random rnd, float probability) {
+ if (probability == 0.0f) {
+ return false;
+ } else if (probability == 1.0f) {
+ return true;
+ } else {
+ return rnd.nextFloat() < probability;
+ }
+ }
+
+ private int nextCodePoint() {
+ if (isNextSurrogatePair()) {
+ return nextSurrogateCodePoint();
+ } else {
+ return nextNonSurrogateCodePoint();
+ }
+ }
+
+ private int nextSurrogateCodePoint() {
+ int highSurrogate =
+ rnd.nextInt(MAX_HIGH_SURROGATE - MIN_HIGH_SURROGATE + 1) + MIN_HIGH_SURROGATE;
+ int lowSurrogate = rnd.nextInt(MAX_LOW_SURROGATE - MIN_LOW_SURROGATE + 1) + MIN_LOW_SURROGATE;
+ return Character.toCodePoint((char) highSurrogate, (char) lowSurrogate);
+ }
+
+ private int nextNonSurrogateCodePoint() {
+ int codePoint;
+ do {
+ codePoint = rnd.nextInt(0x10000); // BMP range
+ } while (codePoint >= MIN_HIGH_SURROGATE
+ && codePoint <= MAX_LOW_SURROGATE); // Exclude surrogate range
+ return codePoint;
+ }
+ }
}
diff --git a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryTest.java b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryTest.java
index 5ffb80d2a8..d688f10a1b 100644
--- a/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryTest.java
+++ b/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITQueryTest.java
@@ -1169,6 +1169,10 @@ public void snapshotListenerSortsUnicodeStringsSameWayAsServer() throws Exceptio
.set(col.document("e"), map("value", "P"))
.set(col.document("f"), map("value", "︒"))
.set(col.document("g"), map("value", "🐵"))
+ .set(col.document("h"), map("value", "你好"))
+ .set(col.document("i"), map("value", "你顥"))
+ .set(col.document("j"), map("value", "😁"))
+ .set(col.document("k"), map("value", "😀"))
.commit()
.get();
@@ -1192,7 +1196,7 @@ public void snapshotListenerSortsUnicodeStringsSameWayAsServer() throws Exceptio
latch.await();
registration.remove();
- assertEquals(queryOrder, Arrays.asList("b", "a", "c", "f", "e", "d", "g"));
+ assertEquals(queryOrder, Arrays.asList("b", "a", "h", "i", "c", "f", "e", "d", "g", "k", "j"));
assertEquals(queryOrder, listenerOrder);
}
@@ -1209,6 +1213,10 @@ public void snapshotListenerSortsUnicodeStringsInArraySameWayAsServer() throws E
.set(col.document("e"), map("value", Arrays.asList("P")))
.set(col.document("f"), map("value", Arrays.asList("︒")))
.set(col.document("g"), map("value", Arrays.asList("🐵")))
+ .set(col.document("h"), map("value", Arrays.asList("你好")))
+ .set(col.document("i"), map("value", Arrays.asList("你顥")))
+ .set(col.document("j"), map("value", Arrays.asList("😁")))
+ .set(col.document("k"), map("value", Arrays.asList("😀")))
.commit()
.get();
@@ -1232,7 +1240,7 @@ public void snapshotListenerSortsUnicodeStringsInArraySameWayAsServer() throws E
latch.await();
registration.remove();
- assertEquals(queryOrder, Arrays.asList("b", "a", "c", "f", "e", "d", "g"));
+ assertEquals(queryOrder, Arrays.asList("b", "a", "h", "i", "c", "f", "e", "d", "g", "k", "j"));
assertEquals(queryOrder, listenerOrder);
}
@@ -1249,6 +1257,10 @@ public void snapshotListenerSortsUnicodeStringsInMapSameWayAsServer() throws Exc
.set(col.document("e"), map("value", map("foo", "P")))
.set(col.document("f"), map("value", map("foo", "︒")))
.set(col.document("g"), map("value", map("foo", "🐵")))
+ .set(col.document("h"), map("value", map("foo", "你好")))
+ .set(col.document("i"), map("value", map("foo", "你顥")))
+ .set(col.document("j"), map("value", map("foo", "😁")))
+ .set(col.document("k"), map("value", map("foo", "😀")))
.commit()
.get();
@@ -1272,7 +1284,7 @@ public void snapshotListenerSortsUnicodeStringsInMapSameWayAsServer() throws Exc
latch.await();
registration.remove();
- assertEquals(queryOrder, Arrays.asList("b", "a", "c", "f", "e", "d", "g"));
+ assertEquals(queryOrder, Arrays.asList("b", "a", "h", "i", "c", "f", "e", "d", "g", "k", "j"));
assertEquals(queryOrder, listenerOrder);
}
@@ -1289,6 +1301,10 @@ public void snapshotListenerSortsUnicodeStringsInMapKeySameWayAsServer() throws
.set(col.document("e"), map("value", map("P", "foo")))
.set(col.document("f"), map("value", map("︒", "foo")))
.set(col.document("g"), map("value", map("🐵", "foo")))
+ .set(col.document("h"), map("value", map("你好", "foo")))
+ .set(col.document("i"), map("value", map("你顥", "foo")))
+ .set(col.document("j"), map("value", map("😁", "foo")))
+ .set(col.document("k"), map("value", map("😀", "foo")))
.commit()
.get();
@@ -1312,7 +1328,7 @@ public void snapshotListenerSortsUnicodeStringsInMapKeySameWayAsServer() throws
latch.await();
registration.remove();
- assertEquals(queryOrder, Arrays.asList("b", "a", "c", "f", "e", "d", "g"));
+ assertEquals(queryOrder, Arrays.asList("b", "a", "h", "i", "c", "f", "e", "d", "g", "k", "j"));
assertEquals(queryOrder, listenerOrder);
}
@@ -1329,6 +1345,10 @@ public void snapshotListenerSortsUnicodeStringsInDocumentKeySameWayAsServer() th
.set(col.document("P"), map("value", "foo"))
.set(col.document("︒"), map("value", "foo"))
.set(col.document("🐵"), map("value", "foo"))
+ .set(col.document("你好"), map("value", "你好"))
+ .set(col.document("你顥"), map("value", "你顥"))
+ .set(col.document("😁"), map("value", "😁"))
+ .set(col.document("😀"), map("value", "😀"))
.commit()
.get();
@@ -1353,7 +1373,50 @@ public void snapshotListenerSortsUnicodeStringsInDocumentKeySameWayAsServer() th
registration.remove();
assertEquals(
- queryOrder, Arrays.asList("Sierpiński", "Łukasiewicz", "岩澤", "︒", "P", "🄟", "🐵"));
+ queryOrder,
+ Arrays.asList(
+ "Sierpiński", "Łukasiewicz", "你好", "你顥", "岩澤", "︒", "P", "🄟", "🐵", "😀", "😁"));
+ assertEquals(queryOrder, listenerOrder);
+ }
+
+ @Test
+ public void snapshotListenerSortsInvalidUnicodeStringsSameWayAsServer() throws Exception {
+ CollectionReference col = createEmptyCollection();
+
+ // Note: Protocol Buffer converts any invalid surrogates to "?".
+ firestore
+ .batch()
+ .set(col.document("a"), map("value", "Z"))
+ .set(col.document("b"), map("value", "你好"))
+ .set(col.document("c"), map("value", "😀"))
+ .set(col.document("d"), map("value", "ab\uD800")) // Lone high surrogate
+ .set(col.document("e"), map("value", "ab\uDC00")) // Lone low surrogate
+ .set(col.document("f"), map("value", "ab\uD800\uD800")) // Unpaired high surrogate
+ .set(col.document("g"), map("value", "ab\uDC00\uDC00")) // Unpaired low surrogate
+ .commit()
+ .get();
+
+ Query query = col.orderBy("value", Direction.ASCENDING);
+
+ QuerySnapshot snapshot = query.get().get();
+ List queryOrder =
+ snapshot.getDocuments().stream().map(doc -> doc.getId()).collect(Collectors.toList());
+
+ CountDownLatch latch = new CountDownLatch(1);
+ List listenerOrder = new ArrayList<>();
+ ListenerRegistration registration =
+ query.addSnapshotListener(
+ (value, error) -> {
+ listenerOrder.addAll(
+ value.getDocuments().stream()
+ .map(doc -> doc.getId())
+ .collect(Collectors.toList()));
+ latch.countDown();
+ });
+ latch.await();
+ registration.remove();
+
+ assertEquals(queryOrder, Arrays.asList("a", "d", "e", "f", "g", "b", "c"));
assertEquals(queryOrder, listenerOrder);
}
}
diff --git a/grpc-google-cloud-firestore-admin-v1/pom.xml b/grpc-google-cloud-firestore-admin-v1/pom.xml
index cbe0a8734c..6932039197 100644
--- a/grpc-google-cloud-firestore-admin-v1/pom.xml
+++ b/grpc-google-cloud-firestore-admin-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
grpc-google-cloud-firestore-admin-v1
- 3.30.9
+ 3.30.10
grpc-google-cloud-firestore-admin-v1
GRPC library for grpc-google-cloud-firestore-admin-v1
com.google.cloud
google-cloud-firestore-parent
- 3.30.9
+ 3.30.10
diff --git a/grpc-google-cloud-firestore-v1/pom.xml b/grpc-google-cloud-firestore-v1/pom.xml
index fc8544ae73..b9b02f4595 100644
--- a/grpc-google-cloud-firestore-v1/pom.xml
+++ b/grpc-google-cloud-firestore-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
grpc-google-cloud-firestore-v1
- 3.30.9
+ 3.30.10
grpc-google-cloud-firestore-v1
GRPC library for grpc-google-cloud-firestore-v1
com.google.cloud
google-cloud-firestore-parent
- 3.30.9
+ 3.30.10
diff --git a/pom.xml b/pom.xml
index d1247b978a..480a59be4f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,7 +4,7 @@
com.google.cloud
google-cloud-firestore-parent
pom
- 3.30.9
+ 3.30.10
Google Cloud Firestore Parent
https://github.com/googleapis/java-firestore
@@ -150,32 +150,32 @@
com.google.api.grpc
proto-google-cloud-firestore-admin-v1
- 3.30.9
+ 3.30.10
com.google.cloud
google-cloud-firestore
- 3.30.9
+ 3.30.10
com.google.cloud
proto-google-cloud-firestore-bundle-v1
- 3.30.9
+ 3.30.10
com.google.api.grpc
proto-google-cloud-firestore-v1
- 3.30.9
+ 3.30.10
com.google.api.grpc
grpc-google-cloud-firestore-admin-v1
- 3.30.9
+ 3.30.10
com.google.api.grpc
grpc-google-cloud-firestore-v1
- 3.30.9
+ 3.30.10
diff --git a/proto-google-cloud-firestore-admin-v1/pom.xml b/proto-google-cloud-firestore-admin-v1/pom.xml
index bd87759412..1b061eb908 100644
--- a/proto-google-cloud-firestore-admin-v1/pom.xml
+++ b/proto-google-cloud-firestore-admin-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
proto-google-cloud-firestore-admin-v1
- 3.30.9
+ 3.30.10
proto-google-cloud-firestore-admin-v1
PROTO library for proto-google-cloud-firestore-admin-v1
com.google.cloud
google-cloud-firestore-parent
- 3.30.9
+ 3.30.10
diff --git a/proto-google-cloud-firestore-bundle-v1/pom.xml b/proto-google-cloud-firestore-bundle-v1/pom.xml
index c92782ce3d..024110b891 100644
--- a/proto-google-cloud-firestore-bundle-v1/pom.xml
+++ b/proto-google-cloud-firestore-bundle-v1/pom.xml
@@ -5,14 +5,14 @@
4.0.0
proto-google-cloud-firestore-bundle-v1
- 3.30.9
+ 3.30.10
proto-google-cloud-firestore-bundle-v1
PROTO library for proto-google-cloud-firestore-bundle-v1
com.google.cloud
google-cloud-firestore-parent
- 3.30.9
+ 3.30.10
diff --git a/proto-google-cloud-firestore-v1/pom.xml b/proto-google-cloud-firestore-v1/pom.xml
index 00e6290ee2..d34c4a429a 100644
--- a/proto-google-cloud-firestore-v1/pom.xml
+++ b/proto-google-cloud-firestore-v1/pom.xml
@@ -4,13 +4,13 @@
4.0.0
com.google.api.grpc
proto-google-cloud-firestore-v1
- 3.30.9
+ 3.30.10
proto-google-cloud-firestore-v1
PROTO library for proto-google-cloud-firestore-v1
com.google.cloud
google-cloud-firestore-parent
- 3.30.9
+ 3.30.10
diff --git a/samples/install-without-bom/pom.xml b/samples/install-without-bom/pom.xml
index 3dbf2072f8..00e9e8630d 100644
--- a/samples/install-without-bom/pom.xml
+++ b/samples/install-without-bom/pom.xml
@@ -30,7 +30,7 @@
com.google.cloud
google-cloud-firestore
- 3.30.8
+ 3.30.9
diff --git a/samples/snapshot/pom.xml b/samples/snapshot/pom.xml
index 64d5a3d4ce..e32bc2a267 100644
--- a/samples/snapshot/pom.xml
+++ b/samples/snapshot/pom.xml
@@ -29,7 +29,7 @@
com.google.cloud
google-cloud-firestore
- 3.30.8
+ 3.30.9
diff --git a/samples/snippets/pom.xml b/samples/snippets/pom.xml
index fbf4f5bfef..7e2e2e5bcb 100644
--- a/samples/snippets/pom.xml
+++ b/samples/snippets/pom.xml
@@ -34,7 +34,7 @@
com.google.cloud
libraries-bom
- 26.55.0
+ 26.56.0
pom
import
diff --git a/versions.txt b/versions.txt
index 7710c8eb88..cb2a8ded4d 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,11 +1,11 @@
# Format:
# module:released-version:current-version
-google-cloud-firestore:3.30.9:3.30.9
-google-cloud-firestore-admin:3.30.9:3.30.9
-google-cloud-firestore-bom:3.30.9:3.30.9
-grpc-google-cloud-firestore-admin-v1:3.30.9:3.30.9
-grpc-google-cloud-firestore-v1:3.30.9:3.30.9
-proto-google-cloud-firestore-admin-v1:3.30.9:3.30.9
-proto-google-cloud-firestore-v1:3.30.9:3.30.9
-proto-google-cloud-firestore-bundle-v1:3.30.9:3.30.9
+google-cloud-firestore:3.30.10:3.30.10
+google-cloud-firestore-admin:3.30.10:3.30.10
+google-cloud-firestore-bom:3.30.10:3.30.10
+grpc-google-cloud-firestore-admin-v1:3.30.10:3.30.10
+grpc-google-cloud-firestore-v1:3.30.10:3.30.10
+proto-google-cloud-firestore-admin-v1:3.30.10:3.30.10
+proto-google-cloud-firestore-v1:3.30.10:3.30.10
+proto-google-cloud-firestore-bundle-v1:3.30.10:3.30.10