diff --git a/gapic-libraries-bom/pom.xml b/gapic-libraries-bom/pom.xml
index 329f86d25e5a..fadd93e25cf8 100644
--- a/gapic-libraries-bom/pom.xml
+++ b/gapic-libraries-bom/pom.xml
@@ -301,13 +301,6 @@
pom
import
-
- com.google.cloud
- google-cloud-bigtable-deps-bom
- 2.78.1-SNAPSHOT
- pom
- import
-
com.google.cloud
google-cloud-billing-bom
diff --git a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Blob.java b/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Blob.java
index cedef20fda83..9f0ed5d2716c 100644
--- a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Blob.java
+++ b/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Blob.java
@@ -27,31 +27,89 @@ public final class Blob implements Serializable {
private static final long serialVersionUID = 1441087101882481208L;
private final ByteString byteString;
+ private final int subtype;
- private Blob(ByteString byteString) {
+ private Blob(ByteString byteString, int subtype) {
+ if (subtype < 0 || subtype > 255) {
+ throw new IllegalArgumentException(
+ "The subtype for Blob must be a value in the inclusive [0, 255] range.");
+ }
this.byteString = byteString;
+ this.subtype = subtype;
}
/**
- * Creates a new Blob instance from the provided ByteString.
+ * Creates a new Blob instance from the provided ByteString. Defaults to subtype 0 and native
+ * representation.
*
* @param byteString The byteString to use for this Blob instance.
* @return The new Blob instance
*/
@Nonnull
public static Blob fromByteString(@Nonnull ByteString byteString) {
- return new Blob(byteString);
+ return new Blob(byteString, 0);
}
/**
* Creates a new Blob instance from the provided bytes. Makes a copy of the bytes passed in.
+ * Defaults to subtype 0 and native representation.
*
* @param bytes The bytes to use for this Blob instance.
* @return The new Blob instance
*/
@Nonnull
public static Blob fromBytes(@Nonnull byte[] bytes) {
- return new Blob(ByteString.copyFrom(bytes));
+ return new Blob(ByteString.copyFrom(bytes), 0);
+ }
+
+ /**
+ * Creates a new Blob instance representing a BSON binary data type. Sets subtype to 0 and
+ * representation to BSON.
+ *
+ * @param bytes The bytes to use for this Blob instance.
+ * @return The new Blob instance
+ */
+ @Nonnull
+ public static Blob createBsonBinary(@Nonnull byte[] bytes) {
+ return new Blob(ByteString.copyFrom(bytes), 0);
+ }
+
+ /**
+ * Creates a new Blob instance representing a BSON binary data type. Sets subtype to 0 and
+ * representation to BSON.
+ *
+ * @param data The ByteString to use for this Blob instance.
+ * @return The new Blob instance
+ */
+ @Nonnull
+ public static Blob createBsonBinary(@Nonnull ByteString data) {
+ return new Blob(data, 0);
+ }
+
+ /**
+ * Creates a new Blob instance representing a BSON binary data type with a specific subtype. Sets
+ * representation to BSON.
+ *
+ * @param subtype The subtype to use for this instance.
+ * @param bytes The bytes to use for this Blob instance.
+ * @return The new Blob instance
+ */
+ @Nonnull
+ public static Blob createBsonBinary(int subtype, @Nonnull byte[] bytes) {
+ return new Blob(ByteString.copyFrom(bytes), subtype);
+ }
+
+ /**
+ * Creates a new Blob instance representing a BSON binary data type with a specific subtype. Sets
+ * representation to BSON.
+ *
+ * @param subtype The subtype to use for this instance.
+ * @param data The ByteString to use for this Blob instance.
+ * @return The new Blob instance
+ */
+ @Nonnull
+ public static Blob createBsonBinary(int subtype, @Nonnull ByteString data) {
+ return new Blob(data, subtype);
}
/**
@@ -74,6 +132,16 @@ public byte[] toBytes() {
return byteString.toByteArray();
}
+ /**
+ * Returns the subtype of this binary data. Defaults to 0 for both native binary and BSON binary
+ * if not specified.
+ *
+ * @return The subtype of the binary data.
+ */
+ public int subtype() {
+ return this.subtype;
+ }
+
/**
* Returns true if this Blob is equal to the provided object.
*
@@ -89,11 +157,32 @@ public boolean equals(Object obj) {
return false;
}
Blob blob = (Blob) obj;
- return Objects.equals(byteString, blob.byteString);
+ return this.subtype == blob.subtype && Objects.equals(byteString, blob.byteString);
}
@Override
public int hashCode() {
- return Objects.hash(byteString);
+ return Objects.hash(byteString, subtype);
+ }
+
+ @Nonnull
+ @Override
+ public String toString() {
+ String dataStr;
+ if (this.byteString.size() <= 100) {
+ dataStr =
+ com.google.common.io.BaseEncoding.base16()
+ .lowerCase()
+ .encode(this.byteString.toByteArray());
+ } else {
+ dataStr =
+ com.google.common.io.BaseEncoding.base16()
+ .lowerCase()
+ .encode(this.byteString.substring(0, 20).toByteArray())
+ + "... (size="
+ + this.byteString.size()
+ + ")";
+ }
+ return "Blob{subtype=" + this.subtype + ", data=" + dataStr + "}";
}
}
diff --git a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/BsonBinaryData.java b/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/BsonBinaryData.java
deleted file mode 100644
index 62a5cfb30de4..000000000000
--- a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/BsonBinaryData.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2025 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.google.cloud.firestore;
-
-import com.google.firestore.v1.MapValue;
-import com.google.protobuf.ByteString;
-import java.io.Serializable;
-import java.util.Objects;
-import javax.annotation.Nonnull;
-
-/** Represents a BSON Binary Data type in Firestore documents. */
-public class BsonBinaryData implements Serializable {
- private static final long serialVersionUID = 1830984831902814656L;
- private final int subtype;
- @Nonnull private final ByteString data;
-
- private BsonBinaryData(int subtype, @Nonnull ByteString data) {
- // By definition the subtype should be 1 byte and should therefore
- // have a value between 0 and 255
- if (subtype < 0 || subtype > 255) {
- throw new IllegalArgumentException(
- "The subtype for Blob must be a value in the inclusive [0, 255] range.");
- }
- this.subtype = subtype;
- this.data = data;
- }
-
- /**
- * Creates a new BsonBinaryData instance from the provided ByteString and subtype.
- *
- * @param subtype The subtype to use for this instance.
- * @param byteString The byteString to use for this instance.
- * @return The new BsonBinaryData instance
- */
- @Nonnull
- public static BsonBinaryData fromByteString(int subtype, @Nonnull ByteString byteString) {
- return new BsonBinaryData(subtype, byteString);
- }
-
- /**
- * Creates a new BsonBinaryData instance from the provided bytes and subtype. Makes a copy of the
- * bytes passed in.
- *
- * @param subtype The subtype to use for this instance.
- * @param bytes The bytes to use for this instance.
- * @return The new BsonBinaryData instance
- */
- @Nonnull
- public static BsonBinaryData fromBytes(int subtype, @Nonnull byte[] bytes) {
- return new BsonBinaryData(subtype, ByteString.copyFrom(bytes));
- }
-
- /**
- * Returns the underlying data as a ByteString.
- *
- * @return The data as a ByteString.
- */
- @Nonnull
- public ByteString dataAsByteString() {
- return data;
- }
-
- /**
- * Returns a copy of the underlying data as a byte[] array.
- *
- * @return The data as a byte[] array.
- */
- @Nonnull
- public byte[] dataAsBytes() {
- return data.toByteArray();
- }
-
- /**
- * Returns the subtype of this binary data.
- *
- * @return The subtype of the binary data.
- */
- public int subtype() {
- return this.subtype;
- }
-
- /**
- * Returns true if this BsonBinaryData is equal to the provided object.
- *
- * @param obj The object to compare against.
- * @return Whether this BsonBinaryData is equal to the provided object.
- */
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- BsonBinaryData other = (BsonBinaryData) obj;
- return this.subtype == other.subtype && Objects.equals(this.data, other.data);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(this.subtype, this.data);
- }
-
- @Nonnull
- @Override
- public String toString() {
- return "BsonBinaryData{subtype=" + this.subtype + ", data=" + this.data.toString() + "}";
- }
-
- MapValue toProto() {
- return UserDataConverter.encodeBsonBinaryData(subtype, data);
- }
-}
diff --git a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentSnapshot.java b/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentSnapshot.java
index cef3581903a8..6b61b38bfc63 100644
--- a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentSnapshot.java
+++ b/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/DocumentSnapshot.java
@@ -482,18 +482,6 @@ public BsonTimestamp getBsonTimestamp(@Nonnull String field) {
return (BsonTimestamp) get(field);
}
- /**
- * Returns the value of the field as a BsonBinaryData.
- *
- * @param field The path to the field.
- * @throws RuntimeException if the value is not a BsonBinaryData.
- * @return The value of the field.
- */
- @Nullable
- public BsonBinaryData getBsonBinaryData(@Nonnull String field) {
- return (BsonBinaryData) get(field);
- }
-
/**
* Gets the reference to the document.
*
diff --git a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Order.java b/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Order.java
index db6f8dff3ec3..e4b46438091d 100644
--- a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Order.java
+++ b/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/Order.java
@@ -43,7 +43,6 @@ enum TypeOrder implements Comparable {
BSON_TIMESTAMP,
STRING,
BLOB,
- BSON_BINARY,
REF,
BSON_OBJECT_ID,
GEO_POINT,
@@ -100,7 +99,7 @@ static TypeOrder fromMapValue(MapValue mapValue) {
case BSON_TIMESTAMP:
return TypeOrder.BSON_TIMESTAMP;
case BSON_BINARY_DATA:
- return TypeOrder.BSON_BINARY;
+ return TypeOrder.BLOB;
case UNKNOWN:
case NONE:
default:
@@ -160,8 +159,7 @@ public int compare(@Nonnull Value left, @Nonnull Value right) {
return compareBsonObjectId(left, right);
case BSON_TIMESTAMP:
return compareBsonTimestamp(left, right);
- case BSON_BINARY:
- return compareBsonBinary(left, right);
+
default:
throw new IllegalArgumentException("Cannot compare " + leftType);
}
@@ -226,9 +224,43 @@ public static int compareUtf8Strings(String left, String right) {
}
private int compareBlobs(Value left, Value right) {
- ByteString leftBytes = left.getBytesValue();
- ByteString rightBytes = right.getBytesValue();
- return compareByteStrings(leftBytes, rightBytes);
+ int leftSubtype = getSubtype(left);
+ int rightSubtype = getSubtype(right);
+ if (leftSubtype != rightSubtype) {
+ return Integer.compare(leftSubtype, rightSubtype);
+ }
+ return compareByteStrings(getData(left), getData(right));
+ }
+
+ private static int getSubtype(Value value) {
+ if (value.hasBytesValue()) {
+ return 0;
+ }
+ if (value.hasMapValue() && UserDataConverter.isBsonBinaryData(value.getMapValue())) {
+ return value
+ .getMapValue()
+ .getFieldsMap()
+ .get(MapType.RESERVED_BSON_BINARY_KEY)
+ .getBytesValue()
+ .byteAt(0)
+ & 0xFF;
+ }
+ throw new IllegalArgumentException("Cannot get subtype for non-blob value: " + value);
+ }
+
+ private static ByteString getData(Value value) {
+ if (value.hasBytesValue()) {
+ return value.getBytesValue();
+ }
+ if (value.hasMapValue() && UserDataConverter.isBsonBinaryData(value.getMapValue())) {
+ return value
+ .getMapValue()
+ .getFieldsMap()
+ .get(MapType.RESERVED_BSON_BINARY_KEY)
+ .getBytesValue()
+ .substring(1);
+ }
+ throw new IllegalArgumentException("Cannot get data for non-blob value: " + value);
}
static int compareByteStrings(ByteString leftBytes, ByteString rightBytes) {
@@ -412,14 +444,6 @@ private int compareBsonTimestamp(Value left, Value right) {
return secondsDiff != 0 ? secondsDiff : Long.compare(lhs.increment, rhs.increment);
}
- private int compareBsonBinary(Value left, Value right) {
- ByteString lhs =
- left.getMapValue().getFieldsMap().get(MapType.RESERVED_BSON_BINARY_KEY).getBytesValue();
- ByteString rhs =
- right.getMapValue().getFieldsMap().get(MapType.RESERVED_BSON_BINARY_KEY).getBytesValue();
- return compareByteStrings(lhs, rhs);
- }
-
private boolean isNaN(Value value) {
if (value.hasDoubleValue() && Double.isNaN(value.getDoubleValue())) {
return true;
diff --git a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UserDataConverter.java b/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UserDataConverter.java
index 7126a955f75d..7e4d55cd4afb 100644
--- a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UserDataConverter.java
+++ b/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/UserDataConverter.java
@@ -173,12 +173,13 @@ static Value encodeValue(
return Value.newBuilder().setGeoPointValue(geopoint.toProto()).build();
} else if (sanitizedObject instanceof Blob) {
Blob blob = (Blob) sanitizedObject;
- return Value.newBuilder().setBytesValue(blob.toByteString()).build();
- } else if (sanitizedObject instanceof BsonBinaryData) {
- BsonBinaryData bson = (BsonBinaryData) sanitizedObject;
- return Value.newBuilder()
- .setMapValue(encodeBsonBinaryData(bson.subtype(), bson.dataAsByteString()))
- .build();
+ if (blob.subtype() != 0) {
+ return Value.newBuilder()
+ .setMapValue(encodeBsonBinaryData(blob.subtype(), blob.toByteString()))
+ .build();
+ } else {
+ return Value.newBuilder().setBytesValue(blob.toByteString()).build();
+ }
} else if (sanitizedObject instanceof Expression) {
return exprToValue((Expression) sanitizedObject);
} else if (sanitizedObject instanceof AggregateFunction) {
@@ -409,8 +410,8 @@ static BsonTimestamp decodeBsonTimestamp(MapValue mapValue) {
return new BsonTimestamp(seconds, increment);
}
- /** Decodes the given MapValue into a BsonBinaryData. Assumes the given map is a BSON binary. */
- static BsonBinaryData decodeBsonBinary(MapValue mapValue) {
+ /** Decodes the given MapValue into a Blob. Assumes the given map is a BSON binary. */
+ static Blob decodeBsonBinary(MapValue mapValue) {
ByteString bytes =
mapValue.getFieldsMap().get(MapType.RESERVED_BSON_BINARY_KEY).getBytesValue();
// Note: A byte is interpreted as a signed 8-bit value. Since values larger than 127 have a
@@ -420,7 +421,7 @@ static BsonBinaryData decodeBsonBinary(MapValue mapValue) {
// Since we want the `subtype` to be an unsigned byte, we need to perform 0-extension (rather
// than sign-extension) to convert it to an int.
int subtype = bytes.byteAt(0) & 0xFF;
- return BsonBinaryData.fromByteString(subtype, bytes.substring(1));
+ return Blob.createBsonBinary(subtype, bytes.substring(1));
}
/**
diff --git a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/encoding/CustomClassMapper.java b/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/encoding/CustomClassMapper.java
index ed01783e11b8..0232c26b22b8 100644
--- a/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/encoding/CustomClassMapper.java
+++ b/java-firestore/google-cloud-firestore/src/main/java/com/google/cloud/firestore/encoding/CustomClassMapper.java
@@ -19,7 +19,6 @@
import com.google.api.core.InternalApi;
import com.google.cloud.Timestamp;
import com.google.cloud.firestore.Blob;
-import com.google.cloud.firestore.BsonBinaryData;
import com.google.cloud.firestore.BsonObjectId;
import com.google.cloud.firestore.BsonTimestamp;
import com.google.cloud.firestore.Decimal128Value;
@@ -171,7 +170,6 @@ static Object serialize(T o, DeserializeContext.ErrorPath path) {
|| o instanceof Decimal128Value
|| o instanceof BsonTimestamp
|| o instanceof BsonObjectId
- || o instanceof BsonBinaryData
|| o instanceof GeoPoint
|| o instanceof Blob
|| o instanceof DocumentReference
@@ -346,8 +344,7 @@ private static T deserializeToClass(Object o, Class clazz, DeserializeCon
return (T) convertBsonObjectId(o, context.errorPath);
} else if (BsonTimestamp.class.isAssignableFrom(clazz)) {
return (T) convertBsonTimestamp(o, context.errorPath);
- } else if (BsonBinaryData.class.isAssignableFrom(clazz)) {
- return (T) convertBsonBinaryData(o, context.errorPath);
+
} else if (DocumentReference.class.isAssignableFrom(clazz)) {
return (T) convertDocumentReference(o, context.errorPath);
} else if (clazz.isArray()) {
@@ -686,16 +683,6 @@ private static BsonTimestamp convertBsonTimestamp(
}
}
- private static BsonBinaryData convertBsonBinaryData(
- Object o, DeserializeContext.ErrorPath errorPath) {
- if (o instanceof BsonBinaryData) {
- return (BsonBinaryData) o;
- } else {
- throw errorPath.deserializeError(
- "Failed to convert value of type " + o.getClass().getName() + " to BsonBinaryData");
- }
- }
-
private static DocumentReference convertDocumentReference(
Object o, DeserializeContext.ErrorPath errorPath) {
if (o instanceof DocumentReference) {
diff --git a/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/ExtendedTypesTest.java b/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/ExtendedTypesTest.java
index 26f08e5ba519..be161e135865 100644
--- a/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/ExtendedTypesTest.java
+++ b/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/ExtendedTypesTest.java
@@ -167,39 +167,71 @@ public void BsonTimestampValuesAndEquality() {
@Test
public void BsonBinaryDataValuesAndEquality() {
- BsonBinaryData b1 = BsonBinaryData.fromBytes(127, new byte[] {1, 2, 3});
- BsonBinaryData b2 = BsonBinaryData.fromBytes(127, new byte[] {1, 2, 3});
- BsonBinaryData b3 = BsonBinaryData.fromBytes(1, new byte[] {1, 2, 3});
- BsonBinaryData b4 = BsonBinaryData.fromBytes(127, new byte[] {1, 2, 4});
+ Blob b1 = Blob.createBsonBinary(127, new byte[] {1, 2, 3});
+ Blob b2 = Blob.createBsonBinary(127, new byte[] {1, 2, 3});
+ Blob b3 = Blob.createBsonBinary(1, new byte[] {1, 2, 3});
+ Blob b4 = Blob.createBsonBinary(127, new byte[] {1, 2, 4});
assertThat(b1.subtype()).isEqualTo(127);
- assertThat(b1.dataAsBytes()).isEqualTo(new byte[] {1, 2, 3});
+ assertThat(b1.toBytes()).isEqualTo(new byte[] {1, 2, 3});
assertThat(b1).isEqualTo(b2);
assertThat(b1).isNotEqualTo(b3);
assertThat(b1).isNotEqualTo(b4);
}
@Test
- public void BsonBinaryDataConvertsByteToIntAndIntToByteCorrectly() {
+ public void BlobEqualityWithSubtypes() {
byte[] data = new byte[] {1, 2, 3};
- BsonBinaryData b1 = BsonBinaryData.fromBytes(127, data); // 0x7F - MSB:0
- BsonBinaryData b2 = BsonBinaryData.fromBytes(128, data); // 0x80 - MSB:1
- BsonBinaryData b3 = BsonBinaryData.fromBytes(255, data); // 0xFF - MSB:1
+ Blob nativeBlob1 = Blob.fromBytes(data);
+ Blob nativeBlob2 = Blob.fromBytes(data);
+ Blob bsonBlobSubtype0 = Blob.createBsonBinary(data);
+ Blob bsonBlobSubtype1 = Blob.createBsonBinary(1, data);
+ Blob bsonBlobSubtype1_differentData = Blob.createBsonBinary(1, new byte[] {1, 2, 4});
+
+ // Native blobs are equal to each other
+ assertThat(nativeBlob1).isEqualTo(nativeBlob2);
+
+ // Native blob is equal to BSON blob with subtype 0
+ assertThat(nativeBlob1).isEqualTo(bsonBlobSubtype0);
+ assertThat(bsonBlobSubtype0).isEqualTo(nativeBlob1);
+
+ // Native blob is NOT equal to BSON blob with subtype 1
+ assertThat(nativeBlob1).isNotEqualTo(bsonBlobSubtype1);
- BsonBinaryData b4 = UserDataConverter.decodeBsonBinary(b1.toProto());
- BsonBinaryData b5 = UserDataConverter.decodeBsonBinary(b2.toProto());
- BsonBinaryData b6 = UserDataConverter.decodeBsonBinary(b3.toProto());
+ // BSON blobs with different subtypes are not equal
+ assertThat(bsonBlobSubtype0).isNotEqualTo(bsonBlobSubtype1);
+
+ // BSON blobs with same subtype but different data are not equal
+ assertThat(bsonBlobSubtype1).isNotEqualTo(bsonBlobSubtype1_differentData);
+ }
+
+ @Test
+ public void BsonBinaryDataConvertsByteToIntAndIntToByteCorrectly() {
+ byte[] data = new byte[] {1, 2, 3};
+ Blob b1 = Blob.createBsonBinary(127, data); // 0x7F - MSB:0
+ Blob b2 = Blob.createBsonBinary(128, data); // 0x80 - MSB:1
+ Blob b3 = Blob.createBsonBinary(255, data); // 0xFF - MSB:1
+
+ Blob b4 =
+ UserDataConverter.decodeBsonBinary(
+ UserDataConverter.encodeBsonBinaryData(b1.subtype(), b1.toByteString()));
+ Blob b5 =
+ UserDataConverter.decodeBsonBinary(
+ UserDataConverter.encodeBsonBinaryData(b2.subtype(), b2.toByteString()));
+ Blob b6 =
+ UserDataConverter.decodeBsonBinary(
+ UserDataConverter.encodeBsonBinaryData(b3.subtype(), b3.toByteString()));
assertThat(b4.subtype()).isEqualTo(127);
- assertThat(b4.dataAsBytes()).isEqualTo(data);
+ assertThat(b4.toBytes()).isEqualTo(data);
assertThat(b4).isEqualTo(b1);
assertThat(b5.subtype()).isEqualTo(128);
- assertThat(b5.dataAsBytes()).isEqualTo(data);
+ assertThat(b5.toBytes()).isEqualTo(data);
assertThat(b5).isEqualTo(b2);
assertThat(b6.subtype()).isEqualTo(255);
- assertThat(b6.dataAsBytes()).isEqualTo(data);
+ assertThat(b6.toBytes()).isEqualTo(data);
assertThat(b6).isEqualTo(b3);
}
@@ -207,14 +239,16 @@ public void BsonBinaryDataConvertsByteToIntAndIntToByteCorrectly() {
public void BsonBinaryDataConstructorsEncodeToTheSameValue() {
byte[] bytes = new byte[] {1, 2, 3};
ByteString byteString = ByteString.copyFromUtf8("\01\02\03");
- BsonBinaryData b1 = BsonBinaryData.fromByteString(127, byteString);
- BsonBinaryData b2 = BsonBinaryData.fromBytes(127, bytes);
- assertThat(b1.toProto()).isEqualTo(b2.toProto());
+ Blob b1 = Blob.createBsonBinary(127, byteString);
+ Blob b2 = Blob.createBsonBinary(127, bytes);
+ assertThat(UserDataConverter.encodeBsonBinaryData(b1.subtype(), b1.toByteString()))
+ .isEqualTo(UserDataConverter.encodeBsonBinaryData(b2.subtype(), b2.toByteString()));
assertThat(b1).isEqualTo(b2);
- BsonBinaryData b3 = BsonBinaryData.fromByteString(128, byteString);
- BsonBinaryData b4 = BsonBinaryData.fromBytes(128, bytes);
- assertThat(b3.toProto()).isEqualTo(b4.toProto());
+ Blob b3 = Blob.createBsonBinary(128, byteString);
+ Blob b4 = Blob.createBsonBinary(128, bytes);
+ assertThat(UserDataConverter.encodeBsonBinaryData(b3.subtype(), b3.toByteString()))
+ .isEqualTo(UserDataConverter.encodeBsonBinaryData(b4.subtype(), b4.toByteString()));
assertThat(b3).isEqualTo(b4);
}
@@ -496,7 +530,7 @@ public void canEncodeAndDecodeBsonTimestamp() {
@Test
public void canEncodeAndDecodeBsonBinaryData() {
- BsonBinaryData bsonBinaryData = BsonBinaryData.fromBytes(127, new byte[] {1, 2, 3});
+ Blob bsonBinaryData = Blob.createBsonBinary(127, new byte[] {1, 2, 3});
Value proto =
Value.newBuilder()
.setMapValue(
@@ -510,4 +544,13 @@ public void canEncodeAndDecodeBsonBinaryData() {
.build();
assertEncodesAndDecodesCorrectly(proto, bsonBinaryData);
}
+
+ @Test
+ public void canEncodeAndDecodeBsonBinaryDataSubtype0() {
+ Blob bsonBinaryData = Blob.createBsonBinary(0, new byte[] {1, 2, 3});
+ Value proto =
+ Value.newBuilder().setBytesValue(ByteString.copyFrom(new byte[] {1, 2, 3})).build();
+ // BSON binary subtype 0 matches standard native Blob
+ assertEncodesAndDecodesCorrectly(proto, bsonBinaryData);
+ }
}
diff --git a/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java b/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java
index b0b71b19ae58..515a6b23feba 100644
--- a/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java
+++ b/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/LocalFirestoreHelper.java
@@ -967,6 +967,7 @@ private static CommitRequest sortCommit(CommitRequest commit) {
return builder.build();
}
+
private static boolean supportsExtendedTypes() {
String edition = System.getProperty("FIRESTORE_EDITION");
if (edition == null) {
@@ -1002,7 +1003,7 @@ public static class AllSupportedTypes {
public Decimal128Value decimal128Value;
public BsonObjectId bsonObjectId;
public BsonTimestamp bsonTimestamp;
- public BsonBinaryData bsonBinaryData;
+ public Blob bsonBinaryData;
public AllSupportedTypes() {
if (supportsExtendedTypes()) {
@@ -1013,7 +1014,7 @@ public AllSupportedTypes() {
decimal128Value = new Decimal128Value("1.2e3");
bsonObjectId = new BsonObjectId("507f191e810c19729de860eb");
bsonTimestamp = new BsonTimestamp(100, 10);
- bsonBinaryData = BsonBinaryData.fromBytes(127, new byte[] {1, 2, 3});
+ bsonBinaryData = Blob.createBsonBinary(127, new byte[] {1, 2, 3});
}
}
@@ -1182,7 +1183,7 @@ public boolean equals(Object o) {
ALL_SUPPORTED_TYPES_MAP.put("bsonObjectId", new BsonObjectId("507f191e810c19729de860eb"));
ALL_SUPPORTED_TYPES_MAP.put("bsonTimestamp", new BsonTimestamp(100, 10));
ALL_SUPPORTED_TYPES_MAP.put(
- "bsonBinaryData", BsonBinaryData.fromBytes(127, new byte[] {1, 2, 3}));
+ "bsonBinaryData", Blob.createBsonBinary(127, new byte[] {1, 2, 3}));
} else {
ALL_SUPPORTED_TYPES_MAP.put("minKey", null);
ALL_SUPPORTED_TYPES_MAP.put("maxKey", null);
@@ -1327,8 +1328,7 @@ public boolean equals(Object o) {
.setMapValue(
MapValue.newBuilder()
.putFields(
- "__decimal128__",
- Value.newBuilder().setStringValue("1.2e3").build())
+ "__decimal128__", Value.newBuilder().setStringValue("1.2e3").build())
.build())
.build())
.put(
@@ -1338,9 +1338,7 @@ public boolean equals(Object o) {
MapValue.newBuilder()
.putFields(
"__oid__",
- Value.newBuilder()
- .setStringValue("507f191e810c19729de860eb")
- .build())
+ Value.newBuilder().setStringValue("507f191e810c19729de860eb").build())
.build())
.build())
.put(
diff --git a/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/OrderTest.java b/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/OrderTest.java
index 3fc9e5e210ee..23e5093923e9 100644
--- a/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/OrderTest.java
+++ b/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/OrderTest.java
@@ -123,11 +123,17 @@ public void verifyOrder() {
// blobs
groups.add(new Value[] {blobValue(new byte[] {})});
- groups.add(new Value[] {blobValue(new byte[] {0})});
+ groups.add(new Value[] {blobValue(new byte[] {0}), bsonBinaryData(0, new byte[] {0})});
groups.add(new Value[] {blobValue(new byte[] {0, 1, 2, 3, 4})});
groups.add(new Value[] {blobValue(new byte[] {0, 1, 2, 4, 3})});
groups.add(new Value[] {blobValue(new byte[] {127})});
+ // BSON Binary Data Subtype 1
+ groups.add(new Value[] {bsonBinaryData(1, new byte[] {})});
+ groups.add(new Value[] {bsonBinaryData(1, new byte[] {0}), bsonBinaryData(1, new byte[] {0})});
+ groups.add(new Value[] {bsonBinaryData(1, new byte[] {0, 1, 2, 3, 4})});
+ groups.add(new Value[] {bsonBinaryData(1, new byte[] {0, 1, 2, 4, 3})});
+
// BSON Binary Data
groups.add(new Value[] {bsonBinaryData(5, new byte[] {})});
groups.add(new Value[] {bsonBinaryData(5, new byte[] {0}), bsonBinaryData(5, new byte[] {0})});
@@ -264,7 +270,7 @@ private Value bsonTimestampValue(long seconds, long increment) {
private Value bsonBinaryData(int subtype, byte[] data) {
return Value.newBuilder()
- .setMapValue(BsonBinaryData.fromBytes(subtype, data).toProto())
+ .setMapValue(UserDataConverter.encodeBsonBinaryData(subtype, ByteString.copyFrom(data)))
.build();
}
diff --git a/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java b/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java
index 170859f5962e..3af75da42fe7 100644
--- a/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java
+++ b/java-firestore/google-cloud-firestore/src/test/java/com/google/cloud/firestore/it/ITPipelineTest.java
@@ -111,6 +111,7 @@
import static java.util.Collections.emptyList;
import static org.junit.Assert.assertThrows;
import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
import com.google.api.gax.rpc.ApiException;
import com.google.api.gax.rpc.StatusCode;
@@ -418,6 +419,33 @@ public void testAllDataTypes() throws Exception {
assertThat(data.get("array").toString()).isEqualTo(refArray.toString());
}
+ @Test
+ public void canFilterAndOrderBlobWithSubtypes() throws Exception {
+ assumeTrue(getFirestoreEdition() == FirestoreEdition.ENTERPRISE);
+ Map> data =
+ ImmutableMap.of(
+ "doc1", ImmutableMap.of("key", Blob.createBsonBinary(1, new byte[] {1, 2, 3})),
+ "doc2", ImmutableMap.of("key", Blob.createBsonBinary(1, new byte[] {1, 2, 4})),
+ "doc3", ImmutableMap.of("key", Blob.createBsonBinary(2, new byte[] {1, 2, 3})));
+ CollectionReference coll = testCollectionWithDocs(data);
+
+ List results =
+ firestore
+ .pipeline()
+ .createFrom(coll)
+ .where(
+ Expression.greaterThan(
+ field("key"), constant(Blob.createBsonBinary(1, new byte[] {1, 2, 3}))))
+ .sort(field("key").descending())
+ .execute()
+ .get()
+ .getResults();
+
+ List