diff --git a/sdk/storage/azure-storage-blob/assets.json b/sdk/storage/azure-storage-blob/assets.json index 8cad139f33ff..7f5e5b611d0c 100644 --- a/sdk/storage/azure-storage-blob/assets.json +++ b/sdk/storage/azure-storage-blob/assets.json @@ -2,5 +2,5 @@ "AssetsRepo": "Azure/azure-sdk-assets", "AssetsRepoPrefixPath": "java", "TagPrefix": "java/storage/azure-storage-blob", - "Tag": "java/storage/azure-storage-blob_47f4243e59" + "Tag": "java/storage/azure-storage-blob_1da9542ee2" } diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/models/BlobsDownloadHeaders.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/models/BlobsDownloadHeaders.java index 1d409a5a4cdd..7dd424fe666c 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/models/BlobsDownloadHeaders.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/implementation/models/BlobsDownloadHeaders.java @@ -295,6 +295,30 @@ public final class BlobsDownloadHeaders { @Generated private Long xMsStructuredContentLength; + /* + * The x-ms-access-tier property. + */ + @Generated + private String xMsAccessTier; + + /* + * The x-ms-access-tier-inferred property. + */ + @Generated + private Boolean xMsAccessTierInferred; + + /* + * The x-ms-access-tier-change-time property. + */ + @Generated + private DateTimeRfc1123 xMsAccessTierChangeTime; + + /* + * The x-ms-smart-access-tier property. + */ + @Generated + private String xMsSmartAccessTier; + /* * The x-ms-content-crc64 property. */ @@ -367,6 +391,16 @@ public final class BlobsDownloadHeaders { private static final HttpHeaderName X_MS_STRUCTURED_CONTENT_LENGTH = HttpHeaderName.fromString("x-ms-structured-content-length"); + private static final HttpHeaderName X_MS_ACCESS_TIER = HttpHeaderName.fromString("x-ms-access-tier"); + + private static final HttpHeaderName X_MS_ACCESS_TIER_INFERRED + = HttpHeaderName.fromString("x-ms-access-tier-inferred"); + + private static final HttpHeaderName X_MS_ACCESS_TIER_CHANGE_TIME + = HttpHeaderName.fromString("x-ms-access-tier-change-time"); + + private static final HttpHeaderName X_MS_SMART_ACCESS_TIER = HttpHeaderName.fromString("x-ms-smart-access-tier"); + private static final HttpHeaderName X_MS_CONTENT_CRC64 = HttpHeaderName.fromString("x-ms-content-crc64"); // HttpHeaders containing the raw property values. @@ -529,6 +563,20 @@ public BlobsDownloadHeaders(HttpHeaders rawHeaders) { } else { this.xMsStructuredContentLength = null; } + this.xMsAccessTier = rawHeaders.getValue(X_MS_ACCESS_TIER); + String xMsAccessTierInferred = rawHeaders.getValue(X_MS_ACCESS_TIER_INFERRED); + if (xMsAccessTierInferred != null) { + this.xMsAccessTierInferred = Boolean.parseBoolean(xMsAccessTierInferred); + } else { + this.xMsAccessTierInferred = null; + } + String xMsAccessTierChangeTime = rawHeaders.getValue(X_MS_ACCESS_TIER_CHANGE_TIME); + if (xMsAccessTierChangeTime != null) { + this.xMsAccessTierChangeTime = new DateTimeRfc1123(xMsAccessTierChangeTime); + } else { + this.xMsAccessTierChangeTime = null; + } + this.xMsSmartAccessTier = rawHeaders.getValue(X_MS_SMART_ACCESS_TIER); String xMsContentCrc64 = rawHeaders.getValue(X_MS_CONTENT_CRC64); if (xMsContentCrc64 != null) { this.xMsContentCrc64 = Base64.getDecoder().decode(xMsContentCrc64); @@ -1584,6 +1632,101 @@ public BlobsDownloadHeaders setXMsStructuredContentLength(Long xMsStructuredCont return this; } + /** + * Get the xMsAccessTier property: The x-ms-access-tier property. + * + * @return the xMsAccessTier value. + */ + @Generated + public String getXMsAccessTier() { + return this.xMsAccessTier; + } + + /** + * Set the xMsAccessTier property: The x-ms-access-tier property. + * + * @param xMsAccessTier the xMsAccessTier value to set. + * @return the BlobsDownloadHeaders object itself. + */ + @Generated + public BlobsDownloadHeaders setXMsAccessTier(String xMsAccessTier) { + this.xMsAccessTier = xMsAccessTier; + return this; + } + + /** + * Get the xMsAccessTierInferred property: The x-ms-access-tier-inferred property. + * + * @return the xMsAccessTierInferred value. + */ + @Generated + public Boolean isXMsAccessTierInferred() { + return this.xMsAccessTierInferred; + } + + /** + * Set the xMsAccessTierInferred property: The x-ms-access-tier-inferred property. + * + * @param xMsAccessTierInferred the xMsAccessTierInferred value to set. + * @return the BlobsDownloadHeaders object itself. + */ + @Generated + public BlobsDownloadHeaders setXMsAccessTierInferred(Boolean xMsAccessTierInferred) { + this.xMsAccessTierInferred = xMsAccessTierInferred; + return this; + } + + /** + * Get the xMsAccessTierChangeTime property: The x-ms-access-tier-change-time property. + * + * @return the xMsAccessTierChangeTime value. + */ + @Generated + public OffsetDateTime getXMsAccessTierChangeTime() { + if (this.xMsAccessTierChangeTime == null) { + return null; + } + return this.xMsAccessTierChangeTime.getDateTime(); + } + + /** + * Set the xMsAccessTierChangeTime property: The x-ms-access-tier-change-time property. + * + * @param xMsAccessTierChangeTime the xMsAccessTierChangeTime value to set. + * @return the BlobsDownloadHeaders object itself. + */ + @Generated + public BlobsDownloadHeaders setXMsAccessTierChangeTime(OffsetDateTime xMsAccessTierChangeTime) { + if (xMsAccessTierChangeTime == null) { + this.xMsAccessTierChangeTime = null; + } else { + this.xMsAccessTierChangeTime = new DateTimeRfc1123(xMsAccessTierChangeTime); + } + return this; + } + + /** + * Get the xMsSmartAccessTier property: The x-ms-smart-access-tier property. + * + * @return the xMsSmartAccessTier value. + */ + @Generated + public String getXMsSmartAccessTier() { + return this.xMsSmartAccessTier; + } + + /** + * Set the xMsSmartAccessTier property: The x-ms-smart-access-tier property. + * + * @param xMsSmartAccessTier the xMsSmartAccessTier value to set. + * @return the BlobsDownloadHeaders object itself. + */ + @Generated + public BlobsDownloadHeaders setXMsSmartAccessTier(String xMsSmartAccessTier) { + this.xMsSmartAccessTier = xMsSmartAccessTier; + return this; + } + /** * Get the xMsContentCrc64 property: The x-ms-content-crc64 property. * diff --git a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/BlobDownloadHeaders.java b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/BlobDownloadHeaders.java index dfd93a535fc6..6a372f5b2c74 100644 --- a/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/BlobDownloadHeaders.java +++ b/sdk/storage/azure-storage-blob/src/main/java/com/azure/storage/blob/models/BlobDownloadHeaders.java @@ -825,6 +825,97 @@ public BlobDownloadHeaders setEncryptionScope(String encryptionScope) { return this; } + /** + * Gets the access tier of the blob. + * + * @return the access tier of the blob. This is only set for Page blobs on a premium storage account or for Block + * blobs on blob storage or general purpose V2 account. + */ + public AccessTier getAccessTier() { + String accessTier = internalHeaders.getXMsAccessTier(); + return accessTier == null ? null : AccessTier.fromString(accessTier); + } + + /** + * Sets the access tier of the blob. + * + * @param accessTier the access tier of the blob. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders setAccessTier(AccessTier accessTier) { + internalHeaders.setXMsAccessTier(accessTier == null ? null : accessTier.toString()); + return this; + } + + /** + * Gets the status of the tier being inferred for the blob. + * + * @return the status of the tier being inferred for the blob. This is only set for Page blobs on a premium storage + * account or for Block blobs on blob storage or general purpose V2 account. + */ + public Boolean isAccessTierInferred() { + return Boolean.TRUE.equals(internalHeaders.isXMsAccessTierInferred()); + } + + /** + * Sets the status of the tier being inferred for the blob. + * + * @param accessTierInferred the status of the tier being inferred for the blob. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders setAccessTierInferred(Boolean accessTierInferred) { + internalHeaders.setXMsAccessTierInferred(accessTierInferred); + return this; + } + + /** + * Gets the time when the access tier for the blob was last changed. + * + * @return the time when the access tier for the blob was last changed. + */ + public OffsetDateTime getAccessTierChangeTime() { + return internalHeaders.getXMsAccessTierChangeTime(); + } + + /** + * Sets the time when the access tier for the blob was last changed. + * + * @param accessTierChangeTime the time when the access tier for the blob was last changed. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders setAccessTierChangeTime(OffsetDateTime accessTierChangeTime) { + internalHeaders.setXMsAccessTierChangeTime(accessTierChangeTime); + return this; + } + + /** + * Gets the underlying access tier of the blob when its access tier is {@link AccessTier#SMART}. + *

+ * This value is only populated when {@link #getAccessTier()} returns {@link AccessTier#SMART}. In that case, it + * represents the concrete access tier (for example {@link AccessTier#HOT} or {@link AccessTier#COOL}) that the + * service has selected for the blob. For all other access tiers, this property is {@code null} and should be + * ignored. + * + * @return the underlying access tier chosen by the service when the blob's access tier is {@link AccessTier#SMART}, + * or {@code null} if the blob is not using the smart access tier. + */ + public AccessTier getSmartAccessTier() { + String smartAccessTier = internalHeaders.getXMsSmartAccessTier(); + return smartAccessTier == null ? null : AccessTier.fromString(smartAccessTier); + } + + /** + * Sets the underlying access tier of the blob when its access tier is {@link AccessTier#SMART}. + * + * @param smartAccessTier the underlying access tier chosen by the service when the blob's access tier is + * {@link AccessTier#SMART}. + * @return the BlobDownloadHeaders object itself. + */ + public BlobDownloadHeaders setSmartAccessTier(AccessTier smartAccessTier) { + internalHeaders.setXMsSmartAccessTier(smartAccessTier == null ? null : smartAccessTier.toString()); + return this; + } + /** * Get the blobContentMD5 property: If the blob has a MD5 hash, and if request contains range header (Range or * x-ms-range), this response header is returned with the value of the whole blob's MD5 value. This value may or may diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobApiTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobApiTests.java index 50a9eb63ef21..71c474ba295c 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobApiTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobApiTests.java @@ -543,6 +543,36 @@ public void downloadAllNullBinaryData() { // headers.getLastAccessedTime() /* TODO (gapra): re-enable when last access time enabled. */ } + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-10-06") + @Test + public void downloadSmartAccessTierHeaders() { + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + bc.setAccessTier(AccessTier.SMART); + + BlobDownloadResponse response = bc.downloadStreamWithResponse(stream, null, null, null, false, null, null); + ByteBuffer body = ByteBuffer.wrap(stream.toByteArray()); + + assertEquals(DATA.getDefaultData(), body); + assertSmartAccessTierHeaders(response.getDeserializedHeaders()); + } + + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-10-06") + @Test + public void downloadContentSmartAccessTierHeaders() { + bc.setAccessTier(AccessTier.SMART); + BlobDownloadContentResponse response = bc.downloadContentWithResponse(null, null, null, null); + + TestUtils.assertArraysEqual(DATA.getDefaultBytes(), response.getValue().toBytes()); + assertSmartAccessTierHeaders(response.getDeserializedHeaders()); + } + + private static void assertSmartAccessTierHeaders(BlobDownloadHeaders headers) { + assertEquals(AccessTier.SMART, headers.getAccessTier()); + assertNotNull(headers.getSmartAccessTier()); + assertFalse(headers.isAccessTierInferred()); + assertNotEquals(OffsetDateTime.now(), headers.getAccessTierChangeTime()); + } + @Test public void downloadEmptyFile() { AppendBlobClient bc = cc.getBlobClient("emptyAppendBlob").getAppendBlobClient(); diff --git a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobAsyncApiTests.java b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobAsyncApiTests.java index 049e4254e92a..ea01df338d18 100644 --- a/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobAsyncApiTests.java +++ b/sdk/storage/azure-storage-blob/src/test/java/com/azure/storage/blob/BlobAsyncApiTests.java @@ -382,6 +382,33 @@ public void downloadAllNullBinaryData() { .verifyComplete(); } + @RequiredServiceVersion(clazz = BlobServiceVersion.class, min = "2026-10-06") + @Test + public void downloadSmartAccessTierHeaders() { + Mono response = bc.setAccessTier(AccessTier.SMART) + .then(bc.downloadStreamWithResponse(null, null, null, false)) + .flatMap(r -> { + assertSmartAccessTierHeaders(r.getDeserializedHeaders()); + return FluxUtil.collectBytesInByteBufferStream(r.getValue()); + }) + .flatMap(r -> { + TestUtils.assertArraysEqual(DATA.getDefaultBytes(), r); + return bc.downloadContentWithResponse(null, null); + }); + + StepVerifier.create(response).assertNext(r -> { + assertSmartAccessTierHeaders(r.getDeserializedHeaders()); + TestUtils.assertArraysEqual(DATA.getDefaultBytes(), r.getValue().toBytes()); + }).verifyComplete(); + } + + private static void assertSmartAccessTierHeaders(BlobDownloadHeaders headers) { + assertEquals(AccessTier.SMART, headers.getAccessTier()); + assertNotNull(headers.getSmartAccessTier()); + assertFalse(headers.isAccessTierInferred()); + assertNotEquals(OffsetDateTime.now(), headers.getAccessTierChangeTime()); + } + @Test public void downloadEmptyFile() { AppendBlobAsyncClient bc = ccAsync.getBlobAsyncClient("emptyAppendBlob").getAppendBlobAsyncClient(); diff --git a/sdk/storage/azure-storage-blob/swagger/README.md b/sdk/storage/azure-storage-blob/swagger/README.md index 292d2f7c231d..98afe0c616dc 100644 --- a/sdk/storage/azure-storage-blob/swagger/README.md +++ b/sdk/storage/azure-storage-blob/swagger/README.md @@ -16,7 +16,7 @@ autorest ### Code generation settings ``` yaml use: '@autorest/java@4.1.63' -input-file: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/15d7f54a5389d5906ffb4e56bb2f38fe5525c0d3/specification/storage/data-plane/Microsoft.BlobStorage/stable/2026-06-06/blob.json +input-file: https://raw.githubusercontent.com/seanmcc-msft/azure-rest-api-specs/eb29a830edf5db50758e7d044160c7f18077f7f7/specification/storage/data-plane/Microsoft.BlobStorage/stable/2026-10-06/blob.json java: true output-folder: ../ namespace: com.azure.storage.blob