Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
0b89f95
get tags
ibrandes Aug 14, 2025
8127a5e
set tags
ibrandes Aug 14, 2025
e3989c5
sas permissions for tag
ibrandes Aug 14, 2025
4c765d4
adding tag to datalake sas model tests
ibrandes Aug 14, 2025
2ef3d71
add only datalake files from 38db6fd3c6dc0a18d896a14c98de79a9099239a1
browndav-msft Feb 20, 2026
7c282bb
fix linting errors:remove unused imports, add return annotation setTa…
browndav-msft Feb 20, 2026
e8d6e59
fix sasPermissionsParseSupplier test
browndav-msft Feb 20, 2026
661ace4
recorded tests for DirectoryApiTests.getSetTags()
browndav-msft Feb 20, 2026
03afd46
split getSetTagsAC into getTagsAC and setTagsAC
browndav-msft Feb 20, 2026
a18b53f
record tests for getTagsAC and setTagsAC
browndav-msft Feb 21, 2026
95ddef5
change generatePathName() to dc.getDirectoryPath
browndav-msft Feb 21, 2026
aa462d4
create recordings for getSetTagsDirectorySas
browndav-msft Feb 21, 2026
ed23d3b
Record DirectoryApiTests#getSetTagsOAuth
browndav-msft Feb 23, 2026
7b0c8b9
Record DirectoryApiTests#getSetTagsLease
browndav-msft Feb 23, 2026
7a7b517
Record DirectoryApiTests#getTagsLeaseFailed
browndav-msft Feb 23, 2026
63e09fc
Record DirectoryApiTests#setTagsLeaseFailed
browndav-msft Feb 23, 2026
453a093
Record DirectoryApiTests#getSetTagsFileSystemSas
browndav-msft Feb 23, 2026
de14786
Record DirectoryApiTests#getSetTagsAccountSas
browndav-msft Feb 23, 2026
14c325c
Record DirectoryApiTests#getSetTagsDirectoryIdentitySas
browndav-msft Feb 23, 2026
b0b451a
Record DirectoryApiTests#getSetTagsFileSystemIdentitySas
browndav-msft Feb 23, 2026
54757b1
Record DirectoryApiTests#getTagsError
browndav-msft Feb 23, 2026
357bc84
Record DirectoryApiTests#setTagsError
browndav-msft Feb 23, 2026
f15d4ad
Record DirectoryApiTests#setTagsACFail
browndav-msft Feb 23, 2026
af7713f
Record DirectoryApiTests#getTagsACFail
browndav-msft Feb 23, 2026
95515ca
Add x-ms-blob-if-modified/unmodified-since to CustomMatcher headers i…
browndav-msft Feb 23, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sdk/storage/azure-storage-file-datalake/assets.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
"AssetsRepo": "Azure/azure-sdk-assets",
"AssetsRepoPrefixPath": "java",
"TagPrefix": "java/storage/azure-storage-file-datalake",
"Tag": "java/storage/azure-storage-file-datalake_4fbddc8ed8"
"Tag": "java/storage/azure-storage-file-datalake_f9d7e79018"
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import com.azure.core.util.logging.ClientLogger;
import com.azure.storage.blob.BlobContainerAsyncClient;
import com.azure.storage.blob.BlobUrlParts;
import com.azure.storage.blob.options.BlobGetTagsOptions;
import com.azure.storage.blob.options.BlobSetTagsOptions;
import com.azure.storage.blob.specialized.BlockBlobAsyncClient;
import com.azure.storage.blob.specialized.SpecializedBlobClientBuilder;
import com.azure.storage.common.StorageSharedKeyCredential;
Expand Down Expand Up @@ -62,8 +64,10 @@
import com.azure.storage.file.datalake.models.PathRemoveAccessControlEntry;
import com.azure.storage.file.datalake.models.PathSystemProperties;
import com.azure.storage.file.datalake.models.UserDelegationKey;
import com.azure.storage.file.datalake.options.DataLakeGetTagsOptions;
import com.azure.storage.file.datalake.options.DataLakePathCreateOptions;
import com.azure.storage.file.datalake.options.DataLakePathDeleteOptions;
import com.azure.storage.file.datalake.options.DataLakeSetTagsOptions;
import com.azure.storage.file.datalake.options.PathGetPropertiesOptions;
import com.azure.storage.file.datalake.options.PathGetSystemPropertiesOptions;
import com.azure.storage.file.datalake.options.PathRemoveAccessControlRecursiveOptions;
Expand Down Expand Up @@ -1950,4 +1954,65 @@ public String generateSas(DataLakeServiceSasSignatureValues dataLakeServiceSasSi
PathResourceType.DIRECTORY.equals(this.pathResourceType))
.generateSas(SasImplUtils.extractSharedKeyCredential(getHttpPipeline()), stringToSignHandler, context);
}

/**
* Gets the tags associated with the underlying path.
*
* @return The path's tags.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<Map<String, String>> getTags() {
return this.getTagsWithResponse(new DataLakeGetTagsOptions()).map(Response::getValue);
}

/**
* Gets the tags associated with the underlying path.
*
* @param options {@link DataLakeGetTagsOptions}
* @return The path's tags.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<Response<Map<String, String>>> getTagsWithResponse(DataLakeGetTagsOptions options) {
options = (options == null) ? new DataLakeGetTagsOptions() : options;
DataLakeRequestConditions requestConditions = (options.getRequestConditions() == null)
? new DataLakeRequestConditions()
: options.getRequestConditions();
BlobGetTagsOptions blobGetTagsOptions
= new BlobGetTagsOptions().setRequestConditions(Transforms.toBlobRequestConditions(requestConditions));

return this.blockBlobAsyncClient.getTagsWithResponse(blobGetTagsOptions)
.onErrorMap(DataLakeImplUtils::transformBlobStorageException);
}

/**
* Sets user defined tags. The specified tags in this method will replace existing tags. If old values
* must be preserved, they must be downloaded and included in the call to this method.
*
* @param tags Tags to associate with the path.
* @return A reactive response signalling completion.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<Void> setTags(Map<String, String> tags) {
return this.setTagsWithResponse(new DataLakeSetTagsOptions(tags)).map(Response::getValue);
Copy link

Copilot AI Feb 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setTags returns Mono<Void> but maps Response::getValue, which will be null for Response<Void>. Reactor doesn't allow emitting null, so this will likely fail with an NPE when subscribed. Use the same pattern as other void-returning APIs in this client (e.g., setMetadata): convert the Mono<Response<Void>> to a completion-only Mono<Void> (such as flatMap(FluxUtil::toMono) or then()).

Suggested change
return this.setTagsWithResponse(new DataLakeSetTagsOptions(tags)).map(Response::getValue);
return this.setTagsWithResponse(new DataLakeSetTagsOptions(tags))
.flatMap(FluxUtil::toMono);

Copilot uses AI. Check for mistakes.
}

/**
* Sets user defined tags. The specified tags in this method will replace existing tags. If old values
* must be preserved, they must be downloaded and included in the call to this method.
*
* @param options {@link DataLakeSetTagsOptions}
* @return A response containing status code and HTTP headers.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Mono<Response<Void>> setTagsWithResponse(DataLakeSetTagsOptions options) {
StorageImplUtils.assertNotNull("options", options);
DataLakeRequestConditions requestConditions = (options.getRequestConditions() == null)
? new DataLakeRequestConditions()
: options.getRequestConditions();
BlobSetTagsOptions blobSetTagsOptions = new BlobSetTagsOptions(options.getTags())
.setRequestConditions(Transforms.toBlobRequestConditions(requestConditions));

return this.blockBlobAsyncClient.setTagsWithResponse(blobSetTagsOptions)
.onErrorMap(DataLakeImplUtils::transformBlobStorageException);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
import com.azure.core.util.DateTimeRfc1123;
import com.azure.core.util.logging.ClientLogger;
import com.azure.storage.blob.models.BlobProperties;
import com.azure.storage.blob.options.BlobGetTagsOptions;
import com.azure.storage.blob.options.BlobSetTagsOptions;
import com.azure.storage.blob.specialized.BlockBlobClient;
import com.azure.storage.common.StorageSharedKeyCredential;
import com.azure.storage.common.Utility;
Expand Down Expand Up @@ -56,8 +58,10 @@
import com.azure.storage.file.datalake.models.PathRemoveAccessControlEntry;
import com.azure.storage.file.datalake.models.PathSystemProperties;
import com.azure.storage.file.datalake.models.UserDelegationKey;
import com.azure.storage.file.datalake.options.DataLakeGetTagsOptions;
import com.azure.storage.file.datalake.options.DataLakePathCreateOptions;
import com.azure.storage.file.datalake.options.DataLakePathDeleteOptions;
import com.azure.storage.file.datalake.options.DataLakeSetTagsOptions;
import com.azure.storage.file.datalake.options.PathGetPropertiesOptions;
import com.azure.storage.file.datalake.options.PathGetSystemPropertiesOptions;
import com.azure.storage.file.datalake.options.PathRemoveAccessControlRecursiveOptions;
Expand Down Expand Up @@ -1835,4 +1839,69 @@ public String generateSas(DataLakeServiceSasSignatureValues dataLakeServiceSasSi
PathResourceType.DIRECTORY.equals(this.pathResourceType))
.generateSas(SasImplUtils.extractSharedKeyCredential(getHttpPipeline()), stringToSignHandler, context);
}

/**
* Gets the tags associated with the underlying path.
*
* @return The path's tags.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Map<String, String> getTags() {
return this.getTagsWithResponse(new DataLakeGetTagsOptions(), null, Context.NONE).getValue();
}

/**
* Gets the tags associated with the underlying path.
*
* @param options {@link DataLakeGetTagsOptions}
* @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised.
* @param context Additional context that is passed through the Http pipeline during the service call.
* @return The path's tags.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Response<Map<String, String>> getTagsWithResponse(DataLakeGetTagsOptions options, Duration timeout,
Context context) {
options = (options == null) ? new DataLakeGetTagsOptions() : options;
DataLakeRequestConditions requestConditions = (options.getRequestConditions() == null)
? new DataLakeRequestConditions()
: options.getRequestConditions();
BlobGetTagsOptions blobGetTagsOptions
= new BlobGetTagsOptions().setRequestConditions(Transforms.toBlobRequestConditions(requestConditions));

return DataLakeImplUtils.returnOrConvertException(
() -> blockBlobClient.getTagsWithResponse(blobGetTagsOptions, timeout, context), LOGGER);
}

/**
* Sets user defined tags. The specified tags in this method will replace existing tags. If old values
* must be preserved, they must be downloaded and included in the call to this method.
*
* @param tags Tags to associate with the path.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public void setTags(Map<String, String> tags) {
this.setTagsWithResponse(new DataLakeSetTagsOptions(tags), null, Context.NONE);
}

/**
* Sets user defined tags. The specified tags in this method will replace existing tags. If old values
* must be preserved, they must be downloaded and included in the call to this method.
*
* @param options {@link DataLakeSetTagsOptions}
* @param timeout An optional timeout value beyond which a {@link RuntimeException} will be raised.
* @param context Additional context that is passed through the Http pipeline during the service call.
* @return A response containing status code and HTTP headers.
*/
@ServiceMethod(returns = ReturnType.SINGLE)
public Response<Void> setTagsWithResponse(DataLakeSetTagsOptions options, Duration timeout, Context context) {
StorageImplUtils.assertNotNull("options", options);
DataLakeRequestConditions requestConditions = (options.getRequestConditions() == null)
? new DataLakeRequestConditions()
: options.getRequestConditions();
BlobSetTagsOptions blobSetTagsOptions = new BlobSetTagsOptions(options.getTags())
.setRequestConditions(Transforms.toBlobRequestConditions(requestConditions));

return DataLakeImplUtils.returnOrConvertException(
() -> blockBlobClient.setTagsWithResponse(blobSetTagsOptions, timeout, context), LOGGER);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.storage.file.datalake.options;

import com.azure.core.annotation.Fluent;
import com.azure.storage.file.datalake.models.DataLakeRequestConditions;

/**
* Extended options that may be passed when getting tags for a path.
*/
@Fluent
public class DataLakeGetTagsOptions {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can make this final; from the wise words of the azure sdk api view bot, "Consider making all classes final by default - only make non-final if subclassing is supported."

private DataLakeRequestConditions requestConditions;

/**
* Creates a new instance of {@link DataLakeGetTagsOptions}.
*/
public DataLakeGetTagsOptions() {
}

/**
* Gets the {@link DataLakeRequestConditions}.
*
* @return {@link DataLakeRequestConditions}
*/
public DataLakeRequestConditions getRequestConditions() {
return requestConditions;
}

/**
* Sets the {@link DataLakeRequestConditions}.
*
* @param requestConditions {@link DataLakeRequestConditions}
* @return The updated options.
*/
public DataLakeGetTagsOptions setRequestConditions(DataLakeRequestConditions requestConditions) {
this.requestConditions = requestConditions;
return this;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.azure.storage.file.datalake.options;

import com.azure.core.annotation.Fluent;
import com.azure.storage.common.implementation.StorageImplUtils;
import com.azure.storage.file.datalake.models.DataLakeRequestConditions;

import java.util.Collections;
import java.util.Map;

/**
* Extended options that may be passed when setting tags for a path.
*/
@Fluent
public class DataLakeSetTagsOptions {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also can be final.

private final Map<String, String> tags;
private DataLakeRequestConditions requestConditions;

/**
* Creates a new instance of {@link DataLakeSetTagsOptions}.
*
* @param tags Tags to associate with the path.
* @throws NullPointerException If {@code tags} is null.
*/
public DataLakeSetTagsOptions(Map<String, String> tags) {
StorageImplUtils.assertNotNull("tags", tags);
this.tags = Collections.unmodifiableMap(tags);
}

/**
* Gets the tags to associate with the path.
*
* @return The tags to associate with the path.
*/
public Map<String, String> getTags() {
return tags;
}

/**
* Gets the {@link DataLakeRequestConditions}.
*
* @return {@link DataLakeRequestConditions}
*/
public DataLakeRequestConditions getRequestConditions() {
return requestConditions;
}

/**
* Sets the {@link DataLakeRequestConditions}.
*
* @param requestConditions {@link DataLakeRequestConditions}
* @return The updated options.
*/
public DataLakeSetTagsOptions setRequestConditions(DataLakeRequestConditions requestConditions) {
this.requestConditions = requestConditions;
return this;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public final class FileSystemSasPermission {
private boolean executePermission;
private boolean manageOwnershipPermission;
private boolean manageAccessControlPermission;
private boolean tagsPermission;

/**
* Initializes an {@code FileSystemSasPermission} object with all fields set to false.
Expand All @@ -38,7 +39,7 @@ public FileSystemSasPermission() {
* @param permissionString A {@code String} which represents the {@code FileSystemSasPermission}.
* @return A {@code FileSystemSasPermission} generated from the given {@code String}.
* @throws IllegalArgumentException If {@code permissionString} contains a character other than r, a, c, w, d, l, m, e,
* o, or p.
* o, t, or p.
*/
public static FileSystemSasPermission parse(String permissionString) {
FileSystemSasPermission permissions = new FileSystemSasPermission();
Expand Down Expand Up @@ -86,6 +87,10 @@ public static FileSystemSasPermission parse(String permissionString) {
permissions.manageAccessControlPermission = true;
break;

case 't':
permissions.tagsPermission = true;
break;

default:
throw new IllegalArgumentException(String.format(Locale.ROOT,
Constants.ENUM_COULD_NOT_BE_PARSED_INVALID_VALUE, "Permissions", permissionString, c));
Expand Down Expand Up @@ -294,6 +299,26 @@ public FileSystemSasPermission setManageAccessControlPermission(boolean hasManag
return this;
}

/**
* Gets the tags permission status.
*
* @return the tags permission status.
*/
public boolean hasTagsPermission() {
return tagsPermission;
}

/**
* Sets the tags permission status.
*
* @param tagsPermission Permission status to set
* @return the updated FileSystemSasPermission object.
*/
public FileSystemSasPermission setTagsPermission(boolean tagsPermission) {
this.tagsPermission = tagsPermission;
return this;
}

/**
* Converts the given permissions to a {@code String}. Using this method will guarantee the permissions are in an
* order accepted by the service.
Expand Down Expand Up @@ -346,6 +371,10 @@ public String toString() {
builder.append('p');
}

if (this.tagsPermission) {
builder.append('t');
}

return builder.toString();
}
}
Loading
Loading