diff --git a/google-cloud-storage/clirr-ignored-differences.xml b/google-cloud-storage/clirr-ignored-differences.xml
index 9cb223aebc..7a61b49855 100644
--- a/google-cloud-storage/clirr-ignored-differences.xml
+++ b/google-cloud-storage/clirr-ignored-differences.xml
@@ -21,6 +21,12 @@
com.google.cloud.storage.BucketInfo$Builder setHierarchicalNamespace(com.google.cloud.storage.BucketInfo$HierarchicalNamespace)
+
+ 7013
+ com/google/cloud/storage/BlobInfo$Builder
+ com.google.cloud.storage.BlobInfo$Builder setContexts(com.google.cloud.storage.BlobInfo$ObjectContexts)
+
+
7013
com/google/cloud/storage/BlobInfo$Builder
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java
index 8a6c3d1b7f..03d9d3f1cb 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Blob.java
@@ -550,6 +550,12 @@ public Builder setRetention(Retention retention) {
return this;
}
+ @Override
+ public Builder setContexts(ObjectContexts contexts) {
+ infoBuilder.setContexts(contexts);
+ return this;
+ }
+
@Override
public Blob build() {
return new Blob(storage, infoBuilder);
@@ -739,6 +745,12 @@ Builder clearRetentionExpirationTime() {
infoBuilder.clearRetentionExpirationTime();
return this;
}
+
+ @Override
+ Builder clearContexts() {
+ infoBuilder.clearContexts();
+ return this;
+ }
}
Blob(Storage storage, BlobInfo.BuilderImpl infoBuilder) {
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java
index 67324b197b..c6c769e009 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/BlobInfo.java
@@ -31,6 +31,7 @@
import com.google.cloud.storage.UnifiedOpts.NamedField;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.BaseEncoding;
import java.io.Serializable;
@@ -112,6 +113,7 @@ public class BlobInfo implements Serializable {
private final Retention retention;
private final OffsetDateTime softDeleteTime;
private final OffsetDateTime hardDeleteTime;
+ private ObjectContexts contexts;
private final transient ImmutableSet modifiedFields;
/** This class is meant for internal use only. Users are discouraged from using this class. */
@@ -289,6 +291,167 @@ public static Mode[] values() {
}
}
+ public static final class ObjectContexts implements Serializable {
+
+ private static final long serialVersionUID = -5993852233545224424L;
+
+ private final ImmutableMap custom;
+
+ private ObjectContexts(Builder builder) {
+ this.custom = builder.custom;
+ }
+
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return new Builder().setCustom(this.custom);
+ }
+
+ /** Returns the map of user-defined object contexts. */
+ public Map getCustom() {
+ return custom;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(custom);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ final ObjectContexts other = (ObjectContexts) obj;
+ return Objects.equals(this.custom, other.custom);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this).add("custom", custom).toString();
+ }
+
+ public static final class Builder {
+
+ private ImmutableMap custom;
+
+ private Builder() {}
+
+ public Builder setCustom(Map custom) {
+ this.custom = custom == null ? ImmutableMap.of() : ImmutableMap.copyOf(custom);
+ return this;
+ }
+
+ public ObjectContexts build() {
+ return new ObjectContexts(this);
+ }
+ }
+ }
+
+ /** Represents the payload of a user-defined object context. */
+ public static final class ObjectCustomContextPayload implements Serializable {
+
+ private static final long serialVersionUID = 557621132294323214L;
+
+ private final String value;
+ private final OffsetDateTime createTime;
+ private final OffsetDateTime updateTime;
+
+ private ObjectCustomContextPayload(Builder builder) {
+ this.value = builder.value;
+ this.createTime = builder.createTime;
+ this.updateTime = builder.updateTime;
+ }
+
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ public Builder toBuilder() {
+ return new Builder()
+ .setValue(this.value)
+ .setCreateTime(this.createTime)
+ .setUpdateTime(this.updateTime);
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public OffsetDateTime getCreateTime() {
+ return createTime;
+ }
+
+ public OffsetDateTime getUpdateTime() {
+ return updateTime;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(value, createTime, updateTime);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ ObjectCustomContextPayload other = (ObjectCustomContextPayload) obj;
+ return Objects.equals(value, other.value)
+ && Objects.equals(createTime, other.createTime)
+ && Objects.equals(updateTime, other.updateTime);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("value", value)
+ .add("createTime", createTime)
+ .add("updateTime", updateTime)
+ .toString();
+ }
+
+ public static final class Builder {
+
+ private String value;
+ private OffsetDateTime createTime;
+ private OffsetDateTime updateTime;
+
+ private Builder() {}
+
+ public Builder(String value) {
+ setValue(value);
+ }
+
+ public Builder setValue(String value) {
+ this.value = value;
+ return this;
+ }
+
+ public Builder setCreateTime(OffsetDateTime createTime) {
+ this.createTime = createTime;
+ return this;
+ }
+
+ public Builder setUpdateTime(OffsetDateTime updateTime) {
+ this.updateTime = updateTime;
+ return this;
+ }
+
+ public ObjectCustomContextPayload build() {
+ return new ObjectCustomContextPayload(this);
+ }
+ }
+ }
+
/** Builder for {@code BlobInfo}. */
public abstract static class Builder {
@@ -543,6 +706,8 @@ Builder setRetentionExpirationTimeOffsetDateTime(OffsetDateTime retentionExpirat
public abstract Builder setRetention(Retention retention);
+ public abstract Builder setContexts(ObjectContexts contexts);
+
/** Creates a {@code BlobInfo} object. */
public abstract BlobInfo build();
@@ -607,6 +772,8 @@ Builder setRetentionExpirationTimeOffsetDateTime(OffsetDateTime retentionExpirat
abstract Builder clearTemporaryHold();
abstract Builder clearRetentionExpirationTime();
+
+ abstract Builder clearContexts();
}
static final class BuilderImpl extends Builder {
@@ -644,6 +811,7 @@ static final class BuilderImpl extends Builder {
private Retention retention;
private OffsetDateTime softDeleteTime;
private OffsetDateTime hardDeleteTime;
+ private ObjectContexts contexts;
private final ImmutableSet.Builder modifiedFields = ImmutableSet.builder();
BuilderImpl(BlobId blobId) {
@@ -684,6 +852,7 @@ static final class BuilderImpl extends Builder {
retention = blobInfo.retention;
softDeleteTime = blobInfo.softDeleteTime;
hardDeleteTime = blobInfo.hardDeleteTime;
+ contexts = blobInfo.contexts;
}
@Override
@@ -1095,6 +1264,13 @@ public Builder setRetention(Retention retention) {
return this;
}
+ @Override
+ public Builder setContexts(ObjectContexts contexts) {
+ modifiedFields.add(BlobField.OBJECT_CONTEXTS);
+ this.contexts = contexts;
+ return this;
+ }
+
@Override
public BlobInfo build() {
checkNotNull(blobId);
@@ -1285,6 +1461,12 @@ Builder clearRetentionExpirationTime() {
this.retentionExpirationTime = null;
return this;
}
+
+ @Override
+ Builder clearContexts() {
+ this.contexts = null;
+ return this;
+ }
}
BlobInfo(BuilderImpl builder) {
@@ -1321,6 +1503,7 @@ Builder clearRetentionExpirationTime() {
retention = builder.retention;
softDeleteTime = builder.softDeleteTime;
hardDeleteTime = builder.hardDeleteTime;
+ contexts = builder.contexts;
modifiedFields = builder.modifiedFields.build();
}
@@ -1731,6 +1914,10 @@ public Retention getRetention() {
return retention;
}
+ public ObjectContexts getContexts() {
+ return contexts;
+ }
+
/** Returns a builder for the current blob. */
public Builder toBuilder() {
return new BuilderImpl(this);
@@ -1745,6 +1932,7 @@ public String toString() {
.add("size", getSize())
.add("content-type", getContentType())
.add("metadata", getMetadata())
+ .add("contexts", getContexts())
.toString();
}
@@ -1783,7 +1971,8 @@ public int hashCode() {
retention,
retentionExpirationTime,
softDeleteTime,
- hardDeleteTime);
+ hardDeleteTime,
+ contexts);
}
@Override
@@ -1827,7 +2016,8 @@ public boolean equals(Object o) {
&& Objects.equals(retentionExpirationTime, blobInfo.retentionExpirationTime)
&& Objects.equals(retention, blobInfo.retention)
&& Objects.equals(softDeleteTime, blobInfo.softDeleteTime)
- && Objects.equals(hardDeleteTime, blobInfo.hardDeleteTime);
+ && Objects.equals(hardDeleteTime, blobInfo.hardDeleteTime)
+ && Objects.equals(contexts, blobInfo.contexts);
}
ImmutableSet getModifiedFields() {
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcConversions.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcConversions.java
index a8354e6b42..9310005961 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcConversions.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/GrpcConversions.java
@@ -44,6 +44,7 @@
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Maps;
import com.google.common.io.BaseEncoding;
import com.google.protobuf.ByteString;
import com.google.protobuf.ProtocolStringList;
@@ -59,6 +60,8 @@
import com.google.storage.v2.Object;
import com.google.storage.v2.ObjectAccessControl;
import com.google.storage.v2.ObjectChecksums;
+import com.google.storage.v2.ObjectContexts;
+import com.google.storage.v2.ObjectCustomContextPayload;
import com.google.storage.v2.Owner;
import com.google.type.Date;
import com.google.type.Expr;
@@ -132,6 +135,12 @@ final class GrpcConversions {
bs -> Base64.getEncoder().encodeToString(bs.toByteArray()),
s -> ByteString.copyFrom(Base64.getDecoder().decode(s.getBytes(StandardCharsets.UTF_8))));
+ private final Codec objectContextsCodec =
+ Codec.of(this::objectContextsEncode, this::objectContextsDecode);
+ private final Codec
+ customContextPayloadCodec =
+ Codec.of(this::objectCustomContextPayloadEncode, this::objectCustomContextPayloadDecode);
+
@VisibleForTesting
final Codec timestampCodec =
Codec.of(
@@ -1007,6 +1016,7 @@ private Object blobInfoEncode(BlobInfo from) {
}
ifNonNull(from.getMetadata(), this::removeNullValues, toBuilder::putAllMetadata);
ifNonNull(from.getAcl(), toImmutableListOf(objectAcl()::encode), toBuilder::addAllAcl);
+ ifNonNull(from.getContexts(), objectContextsCodec::encode, toBuilder::setContexts);
return toBuilder.build();
}
@@ -1086,6 +1096,9 @@ private BlobInfo blobInfoDecode(Object from) {
toBuilder.setEtag(from.getEtag());
}
ifNonNull(from.getAclList(), toImmutableListOf(objectAcl()::decode), toBuilder::setAcl);
+ if (from.hasContexts()) {
+ toBuilder.setContexts(objectContextsCodec.decode(from.getContexts()));
+ }
return toBuilder.build();
}
@@ -1248,6 +1261,50 @@ private IpFilter.VpcNetworkSource vpcNetworkSourceDecode(VpcNetworkSource from)
return to.build();
}
+ private ObjectContexts objectContextsEncode(BlobInfo.ObjectContexts from) {
+ if (from == null) {
+ return null;
+ }
+ ObjectContexts.Builder to = ObjectContexts.newBuilder();
+ if (from.getCustom() != null) {
+ to.putAllCustom(
+ Maps.transformValues(
+ Maps.filterValues(from.getCustom(), Objects::nonNull),
+ customContextPayloadCodec::encode));
+ }
+ return to.build();
+ }
+
+ private BlobInfo.ObjectContexts objectContextsDecode(ObjectContexts from) {
+ return BlobInfo.ObjectContexts.newBuilder()
+ .setCustom(Maps.transformValues(from.getCustomMap(), customContextPayloadCodec::decode))
+ .build();
+ }
+
+ private ObjectCustomContextPayload objectCustomContextPayloadEncode(
+ BlobInfo.ObjectCustomContextPayload from) {
+ ObjectCustomContextPayload.Builder to = ObjectCustomContextPayload.newBuilder();
+ ifNonNull(from.getValue(), to::setValue);
+ ifNonNull(from.getCreateTime(), timestampCodec::encode, to::setCreateTime);
+ ifNonNull(from.getUpdateTime(), timestampCodec::encode, to::setUpdateTime);
+ return to.build();
+ }
+
+ private BlobInfo.ObjectCustomContextPayload objectCustomContextPayloadDecode(
+ ObjectCustomContextPayload from) {
+ BlobInfo.ObjectCustomContextPayload.Builder to =
+ BlobInfo.ObjectCustomContextPayload.newBuilder();
+ to.setValue(from.getValue());
+
+ if (from.hasCreateTime()) {
+ to.setCreateTime(timestampCodec.decode(from.getCreateTime()));
+ }
+ if (from.hasUpdateTime()) {
+ to.setUpdateTime(timestampCodec.decode(from.getUpdateTime()));
+ }
+ return to.build();
+ }
+
/**
* Several properties are translating lists of one type to another. This convenience method allows
* specifying a mapping function and composing as part of an {@code #isNonNull} definition.
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/JsonConversions.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/JsonConversions.java
index 016e793a5d..2938a2ede1 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/JsonConversions.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/JsonConversions.java
@@ -42,8 +42,10 @@
import com.google.api.services.storage.model.Bucket.Website;
import com.google.api.services.storage.model.BucketAccessControl;
import com.google.api.services.storage.model.ObjectAccessControl;
+import com.google.api.services.storage.model.ObjectCustomContextPayload;
import com.google.api.services.storage.model.Policy.Bindings;
import com.google.api.services.storage.model.StorageObject;
+import com.google.api.services.storage.model.StorageObject.Contexts;
import com.google.api.services.storage.model.StorageObject.Owner;
import com.google.cloud.Binding;
import com.google.cloud.Policy;
@@ -86,6 +88,7 @@
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
@@ -252,6 +255,12 @@ final class JsonConversions {
}
return CustomerSuppliedEncryptionEnforcementConfig.of(mode);
});
+ private final Codec objectContextsCodec =
+ Codec.of(this::objectContextsEncode, this::objectContextsDecode);
+
+ private final Codec
+ objectCustomContextPayloadCodec =
+ Codec.of(this::objectCustomContextPayloadEncode, this::objectCustomContextPayloadDecode);
private JsonConversions() {}
@@ -391,6 +400,7 @@ private StorageObject blobInfoEncode(BlobInfo from) {
to.setEtag(from.getEtag());
to.setId(from.getGeneratedId());
to.setSelfLink(from.getSelfLink());
+ ifNonNull(from.getContexts(), objectContextsCodec::encode, to::setContexts);
return to;
}
@@ -437,6 +447,7 @@ private BlobInfo blobInfoDecode(StorageObject from) {
ifNonNull(from.getRetention(), this::retentionDecode, to::setRetention);
ifNonNull(from.getSoftDeleteTime(), dateTimeCodec::decode, to::setSoftDeleteTime);
ifNonNull(from.getHardDeleteTime(), dateTimeCodec::decode, to::setHardDeleteTime);
+ ifNonNull(from.getContexts(), objectContextsCodec::decode, to::setContexts);
return to.build();
}
@@ -1242,6 +1253,49 @@ private static void maybeDecodeRetentionPolicy(Bucket from, BucketInfo.Builder t
}
}
+ private Contexts objectContextsEncode(BlobInfo.ObjectContexts from) {
+ if (from == null) {
+ return null;
+ }
+ Contexts to = new Contexts();
+ ifNonNull(
+ from.getCustom(),
+ m -> new HashMap<>(Maps.transformValues(m, objectCustomContextPayloadCodec::encode)),
+ to::setCustom);
+ return to;
+ }
+
+ private BlobInfo.ObjectContexts objectContextsDecode(Contexts from) {
+ if (from == null) {
+ return null;
+ }
+ BlobInfo.ObjectContexts.Builder to = BlobInfo.ObjectContexts.newBuilder();
+ ifNonNull(
+ from.getCustom(),
+ m -> new HashMap<>(Maps.transformValues(m, objectCustomContextPayloadCodec::decode)),
+ to::setCustom);
+ return to.build();
+ }
+
+ private ObjectCustomContextPayload objectCustomContextPayloadEncode(
+ BlobInfo.ObjectCustomContextPayload from) {
+ ObjectCustomContextPayload to = new ObjectCustomContextPayload();
+ ifNonNull(from.getValue(), to::setValue);
+ ifNonNull(from.getCreateTime(), Utils.dateTimeCodec::encode, to::setCreateTime);
+ ifNonNull(from.getUpdateTime(), Utils.dateTimeCodec::encode, to::setUpdateTime);
+ return to;
+ }
+
+ private BlobInfo.ObjectCustomContextPayload objectCustomContextPayloadDecode(
+ ObjectCustomContextPayload from) {
+ BlobInfo.ObjectCustomContextPayload.Builder to =
+ BlobInfo.ObjectCustomContextPayload.newBuilder();
+ ifNonNull(from.getValue(), to::setValue);
+ ifNonNull(from.getCreateTime(), Utils.dateTimeCodec::decode, to::setCreateTime);
+ ifNonNull(from.getUpdateTime(), Utils.dateTimeCodec::decode, to::setUpdateTime);
+ return to.build();
+ }
+
private static Map replaceDataNullValuesWithNull(Map labels) {
boolean anyDataNull = labels.values().stream().anyMatch(Data::isNull);
if (anyDataNull) {
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
index 61597307fd..79e270875d 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/Storage.java
@@ -339,7 +339,11 @@ enum BlobField implements FieldSelector, NamedField {
@TransportCompatibility({Transport.HTTP, Transport.GRPC})
HARD_DELETE_TIME(
- "hardDeleteTime", "hard_delete_time", com.google.api.client.util.DateTime.class);
+ "hardDeleteTime", "hard_delete_time", com.google.api.client.util.DateTime.class),
+
+ @TransportCompatibility({Transport.HTTP, Transport.GRPC})
+ OBJECT_CONTEXTS(
+ "contexts", "contexts", com.google.api.services.storage.model.StorageObject.Contexts.class);
static final List REQUIRED_FIELDS = ImmutableList.of(BUCKET, NAME);
private static final Map JSON_FIELD_NAME_INDEX;
@@ -2743,6 +2747,16 @@ public static BlobListOption softDeleted(boolean softDeleted) {
return new BlobListOption(UnifiedOpts.softDeleted(softDeleted));
}
+ /**
+ * Returns an option to filter list results based on object attributes, such as object contexts.
+ *
+ * @param filter The filter string.
+ */
+ @TransportCompatibility({Transport.HTTP, Transport.GRPC})
+ public static BlobListOption filter(String filter) {
+ return new BlobListOption(UnifiedOpts.objectFilter(filter));
+ }
+
/**
* A set of extra headers to be set for all requests performed within the scope of the operation
* this option is passed to (a get, read, resumable upload etc).
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/UnifiedOpts.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/UnifiedOpts.java
index 5092f1e62d..c9cb5de1de 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/UnifiedOpts.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/UnifiedOpts.java
@@ -581,6 +581,10 @@ static Md5MatchExtractor md5MatchExtractor() {
return Md5MatchExtractor.INSTANCE;
}
+ static ObjectFilter objectFilter(String filter) {
+ return new ObjectFilter(filter);
+ }
+
static Headers extraHeaders(ImmutableMap extraHeaders) {
requireNonNull(extraHeaders, "extraHeaders must be non null");
String blockedHeaders =
@@ -2502,6 +2506,19 @@ private Object readResolve() {
}
}
+ static final class ObjectFilter extends RpcOptVal implements ObjectListOpt {
+ private static final long serialVersionUID = -892748218491324843L;
+
+ private ObjectFilter(String val) {
+ super(StorageRpc.Option.OBJECT_FILTER, val);
+ }
+
+ @Override
+ public Mapper listObjects() {
+ return b -> b.setFilter(val);
+ }
+ }
+
/**
* Internal only implementation of {@link ObjectTargetOpt} which is a No-op.
*
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java
index 6ea50f3772..ca11f96673 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/HttpStorageRpc.java
@@ -497,7 +497,8 @@ public Tuple> list(final String bucket, Map storageObjects =
diff --git a/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java b/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java
index 160a2ad433..5127fbf54b 100644
--- a/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java
+++ b/google-cloud-storage/src/main/java/com/google/cloud/storage/spi/v1/StorageRpc.java
@@ -80,6 +80,7 @@ enum Option {
INCLUDE_FOLDERS_AS_PREFIXES("includeFoldersAsPrefixes"),
INCLUDE_TRAILING_DELIMITER("includeTrailingDelimiter"),
X_UPLOAD_CONTENT_LENGTH("x-upload-content-length"),
+ OBJECT_FILTER("objectFilter"),
/**
* An {@link com.google.common.collect.ImmutableMap ImmutableMap<String, String>} of values
* which will be set as additional headers on the request.
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobInfoTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobInfoTest.java
index c563c9e81a..862709a5ae 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobInfoTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobInfoTest.java
@@ -28,9 +28,12 @@
import com.google.cloud.storage.Acl.Project;
import com.google.cloud.storage.Acl.User;
import com.google.cloud.storage.BlobInfo.CustomerEncryption;
+import com.google.cloud.storage.BlobInfo.ObjectContexts;
+import com.google.cloud.storage.BlobInfo.ObjectCustomContextPayload;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.math.BigInteger;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.junit.Test;
@@ -79,6 +82,12 @@ public class BlobInfoTest {
private static final Boolean EVENT_BASED_HOLD = true;
private static final Boolean TEMPORARY_HOLD = true;
private static final Long RETENTION_EXPIRATION_TIME = 10L;
+ private static final ObjectCustomContextPayload payload =
+ ObjectCustomContextPayload.newBuilder().setValue("contextValue").build();
+ private static final Map customContexts =
+ Collections.singletonMap("contextKey", payload);
+ private static final ObjectContexts OBJECT_CONTEXTS =
+ ObjectContexts.newBuilder().setCustom(customContexts).build();
private static final BlobInfo BLOB_INFO =
BlobInfo.newBuilder("b", "n", GENERATION)
@@ -110,6 +119,7 @@ public class BlobInfoTest {
.setEventBasedHold(EVENT_BASED_HOLD)
.setTemporaryHold(TEMPORARY_HOLD)
.setRetentionExpirationTime(RETENTION_EXPIRATION_TIME)
+ .setContexts(OBJECT_CONTEXTS)
.build();
private static final BlobInfo DIRECTORY_INFO =
BlobInfo.newBuilder("b", "n/").setSize(0L).setIsDirectory(true).build();
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobTest.java
index f312837b0a..d52e1b7d6c 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/BlobTest.java
@@ -36,6 +36,8 @@
import com.google.cloud.storage.Acl.User;
import com.google.cloud.storage.Blob.BlobSourceOption;
import com.google.cloud.storage.BlobInfo.BuilderImpl;
+import com.google.cloud.storage.BlobInfo.ObjectContexts;
+import com.google.cloud.storage.BlobInfo.ObjectCustomContextPayload;
import com.google.cloud.storage.Storage.CopyRequest;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -44,6 +46,7 @@
import java.net.URL;
import java.nio.file.Path;
import java.security.Key;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -92,6 +95,12 @@ public class BlobTest {
private static final Boolean EVENT_BASED_HOLD = true;
private static final Boolean TEMPORARY_HOLD = true;
private static final Long RETENTION_EXPIRATION_TIME = 10L;
+ private static final ObjectCustomContextPayload payload =
+ ObjectCustomContextPayload.newBuilder().setValue("contextValue").build();
+ private static final Map customContexts =
+ Collections.singletonMap("contextKey", payload);
+ private static final ObjectContexts OBJECT_CONTEXTS =
+ ObjectContexts.newBuilder().setCustom(customContexts).build();
private static final BlobInfo FULL_BLOB_INFO =
BlobInfo.newBuilder("b", "n", GENERATION)
.setAcl(ACLS)
@@ -122,6 +131,7 @@ public class BlobTest {
.setEventBasedHold(EVENT_BASED_HOLD)
.setTemporaryHold(TEMPORARY_HOLD)
.setRetentionExpirationTime(RETENTION_EXPIRATION_TIME)
+ .setContexts(OBJECT_CONTEXTS)
.build();
private static final BlobInfo BLOB_INFO =
BlobInfo.newBuilder("b", "n", 12345678L).setMetageneration(42L).build();
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITBlobReadMaskTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITBlobReadMaskTest.java
index bf8c48258e..5c76995a57 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITBlobReadMaskTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITBlobReadMaskTest.java
@@ -202,6 +202,7 @@ public ImmutableList> parameters() {
new Args<>(
BlobField.RETENTION,
LazyAssertion.skip("TODO: jesse fill in buganizer bug here")),
+ new Args<>(BlobField.OBJECT_CONTEXTS, LazyAssertion.equal()),
new Args<>(BlobField.SOFT_DELETE_TIME, LazyAssertion.equal()),
new Args<>(BlobField.HARD_DELETE_TIME, LazyAssertion.equal()));
List argsDefined =
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITOptionRegressionTest.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITOptionRegressionTest.java
index e30fc31250..28e88582f7 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITOptionRegressionTest.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/it/ITOptionRegressionTest.java
@@ -742,7 +742,8 @@ public void storage_BlobGetOption_fields_BlobField() {
"updated",
"retention",
"softDeleteTime",
- "hardDeleteTime");
+ "hardDeleteTime",
+ "contexts");
s.get(o.getBlobId(), BlobGetOption.fields(BlobField.values()));
requestAuditing.assertQueryParam("fields", expected, splitOnCommaToSet());
}
@@ -923,7 +924,8 @@ public void storage_BlobListOption_fields_BlobField() {
"items/updated",
"items/retention",
"items/softDeleteTime",
- "items/hardDeleteTime");
+ "items/hardDeleteTime",
+ "items/contexts");
s.list(b.getName(), BlobListOption.fields(BlobField.values()));
requestAuditing.assertQueryParam("fields", expected, splitOnCommaToSet());
}
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/jqwik/ObjectArbitraryProvider.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/jqwik/ObjectArbitraryProvider.java
index e8a5bb64b1..4b99a19da4 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/jqwik/ObjectArbitraryProvider.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/jqwik/ObjectArbitraryProvider.java
@@ -79,7 +79,8 @@ public Set> provideFor(TypeUsage targetType, SubtypeProvider subtyp
StorageArbitraries.objects().customMetadata(),
StorageArbitraries.owner().injectNull(0.1),
StorageArbitraries.objects().objectAccessControl().injectNull(0.5),
- StorageArbitraries.etag())
+ StorageArbitraries.etag(),
+ StorageArbitraries.objects().objectContexts())
.as(Tuple::of))
.as(
(t1, t2, t3, t4) -> {
@@ -111,6 +112,7 @@ public Set> provideFor(TypeUsage targetType, SubtypeProvider subtyp
ifNonNull(t3.get7(), b::setCustomerEncryption);
ifNonNull(t3.get8(), b::setCustomTime);
ifNonNull(t4.get4(), b::setEtag);
+ ifNonNull(t4.get5(), b::setContexts);
return b.build();
});
return Collections.singleton(objectArbitrary);
diff --git a/google-cloud-storage/src/test/java/com/google/cloud/storage/jqwik/StorageArbitraries.java b/google-cloud-storage/src/test/java/com/google/cloud/storage/jqwik/StorageArbitraries.java
index b9d5bd0a54..ffcb2fcac0 100644
--- a/google-cloud-storage/src/test/java/com/google/cloud/storage/jqwik/StorageArbitraries.java
+++ b/google-cloud-storage/src/test/java/com/google/cloud/storage/jqwik/StorageArbitraries.java
@@ -42,6 +42,8 @@
import com.google.storage.v2.CustomerEncryption;
import com.google.storage.v2.ObjectAccessControl;
import com.google.storage.v2.ObjectChecksums;
+import com.google.storage.v2.ObjectContexts;
+import com.google.storage.v2.ObjectCustomContextPayload;
import com.google.storage.v2.Owner;
import com.google.storage.v2.ProjectName;
import com.google.storage.v2.ProjectTeam;
@@ -709,6 +711,35 @@ public Arbitrary