Skip to content

Conversation

@muhammad-othman
Copy link
Member

@muhammad-othman muhammad-othman commented Dec 5, 2025

Description

Generates RenameObject operation

AssemblyComparer AWSSDK.S3.New.dll: Error Amazon.S3.Model.RenameObjectRequest/MethodRemoved: Missing method System.DateTime get_SourceIfUnmodifiedSince() in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Message Amazon.S3.Model.RenameObjectRequest/MethodAdded: New method System.Nullable<System.DateTime> get_SourceIfUnmodifiedSince() in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Error Amazon.S3.Model.RenameObjectRequest/MethodRemoved: Missing method System.DateTime get_DestinationIfUnmodifiedSince() in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Message Amazon.S3.Model.RenameObjectRequest/MethodAdded: New method System.Nullable<System.DateTime> get_DestinationIfUnmodifiedSince() in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Error Amazon.S3.Model.RenameObjectRequest/MethodRemoved: Missing method System.Void set_SourceIfUnmodifiedSince(System.DateTime) in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Message Amazon.S3.Model.RenameObjectRequest/MethodAdded: New method System.Void set_SourceIfUnmodifiedSince(System.Nullable<System.DateTime>) in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Error Amazon.S3.Model.RenameObjectRequest/MethodRemoved: Missing method System.Void set_SourceIfModifiedSince(System.DateTime) in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Message Amazon.S3.Model.RenameObjectRequest/MethodAdded: New method System.Void set_SourceIfModifiedSince(System.Nullable<System.DateTime>) in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Error Amazon.S3.Model.RenameObjectRequest/MethodRemoved: Missing method System.Void set_DestinationIfUnmodifiedSince(System.DateTime) in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Message Amazon.S3.Model.RenameObjectRequest/MethodAdded: New method System.Void set_DestinationIfUnmodifiedSince(System.Nullable<System.DateTime>) in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Error Amazon.S3.Model.RenameObjectRequest/MethodRemoved: Missing method System.DateTime get_DestinationIfModifiedSince() in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Message Amazon.S3.Model.RenameObjectRequest/MethodAdded: New method System.Nullable<System.DateTime> get_DestinationIfModifiedSince() in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Error Amazon.S3.Model.RenameObjectRequest/MethodRemoved: Missing method System.Void set_DestinationIfModifiedSince(System.DateTime) in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Message Amazon.S3.Model.RenameObjectRequest/MethodAdded: New method System.Void set_DestinationIfModifiedSince(System.Nullable<System.DateTime>) in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Error Amazon.S3.Model.RenameObjectRequest/MethodRemoved: Missing method System.DateTime get_SourceIfModifiedSince() in Amazon.S3.Model.RenameObjectRequest
AssemblyComparer AWSSDK.S3.New.dll: Message Amazon.S3.Model.RenameObjectRequest/MethodAdded: New method System.Nullable<System.DateTime> get_SourceIfModifiedSince() in Amazon.S3.Model.RenameObjectRequest

The following properties was changed from DateTime to DateTime?:

  • SourceIfUnmodifiedSince
  • DestinationIfUnmodifiedSince
  • DestinationIfModifiedSince
  • SourceIfModifiedSince
    We agreed that this is acceptable and will call it out in the changelog.

Another breaking change is that the order of required parameters validation has changed, which will cause different exceptions messages to be thrown for the same parameters combinations, but the exceptions are the same.

Additionally request.UseQueryString = true; was removed, though it didn't affect the result URL since this operation uses the request headers and query string wasn't affected by this removal.

Motivation and Context

DOTNET-8422

Testing

  • DRY_RUN-967ff3a2-7405-463b-b78e-7ba84e29a500.
  • Ran the Fuzz tests.
  • Tested the operation locally before and after the change with various parameters' combinations.

Screenshots (if appropriate)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • My code follows the code style of this project
  • My change requires a change to the documentation
  • I have updated the documentation accordingly
  • I have read the README document
  • I have added tests to cover my changes
  • All new and existing tests passed

License

  • I confirm that this pull request can be released under the Apache 2 license

@muhammad-othman
Copy link
Member Author

Same breaking changes mentioned above

Breaking Changes Analysis for RenameObject Operation Migration (Commit b90e83b3)

Files Analyzed: 10 out of 10 files

  • ✓ generator/ServiceClientGeneratorLib/ServiceModel.cs
  • ✓ generator/ServiceModels/s3/s3.customizations.json
  • ✓ sdk/src/Services/S3/Custom/Model/Internal/MarshallTransformations/RenameObjectRequestMarshaller.cs
  • ✓ sdk/src/Services/S3/Custom/Model/RenameObjectRequest.cs (DELETED)
  • ✓ sdk/src/Services/S3/Generated/Model/IdempotencyParameterMismatchException.cs (NEW)
  • ✓ sdk/src/Services/S3/Generated/Model/Internal/MarshallTransformations/IdempotencyParameterMismatchExceptionUnmarshaller.cs (NEW)
  • ✓ sdk/src/Services/S3/Generated/Model/Internal/MarshallTransformations/RenameObjectRequestMarshaller.cs (NEW)
  • ✓ sdk/src/Services/S3/Generated/Model/Internal/MarshallTransformations/RenameObjectResponseUnmarshaller.cs (NEW)
  • ✓ sdk/src/Services/S3/Generated/Model/RenameObjectRequest.cs (NEW)
  • ✓ sdk/src/Services/S3/Generated/Model/RenameObjectResponse.cs (MOVED)

CRITICAL BREAKING CHANGES FOUND

1. DateTime Property Type Changes - BREAKING CHANGE

File: sdk/src/Services/S3/Generated/Model/RenameObjectRequest.cs

Issue: Four DateTime properties changed from non-nullable DateTime to nullable DateTime?, fundamentally altering their behavior when not set.

Affected Properties:

  • DestinationIfModifiedSince
  • DestinationIfUnmodifiedSince
  • SourceIfModifiedSince
  • SourceIfUnmodifiedSince

OLD Behavior (Custom):

public DateTime DestinationIfModifiedSince
{
    get { return this.destinationIfModifiedSince.GetValueOrDefault(); }
    set { this.destinationIfModifiedSince = value; }
}
  • Returns default(DateTime) (DateTime.MinValue with Unspecified kind) when not set

NEW Behavior (Generated):

public DateTime? DestinationIfModifiedSince
{
    get { return this._destinationIfModifiedSince; }
    set { this._destinationIfModifiedSince = value; }
}
  • Returns null when not set

Impact:

  • Code accessing these properties without null checks will fail at compile time
  • Code checking if (request.DestinationIfModifiedSince != default(DateTime)) will break
  • Serialization/marshalling behavior changes from sending default DateTime to not sending the header at all

Same issue applies to:

  • DestinationIfUnmodifiedSince
  • SourceIfModifiedSince
  • SourceIfUnmodifiedSince

2. Validation Order Change - BREAKING CHANGE

File: sdk/src/Services/S3/Generated/Model/Internal/MarshallTransformations/RenameObjectRequestMarshaller.cs + Custom partial

Issue: The order in which required parameters are validated has changed, which will cause different exceptions to be thrown first.

OLD Validation Order (Custom):

// Line 88-91 in old marshaller
if (!renameObjectRequest.IsSetBucketName())
    throw new ArgumentException("BucketName is a required property...");
if (!renameObjectRequest.IsSetKey())
    throw new ArgumentException("Key is a required property...");
if (!renameObjectRequest.IsSetRenameSource())
    throw new ArgumentException("RenameSource is a required property...");

NEW Validation Order (Split):

// Custom PreMarshallCustomization (called FIRST):
if (!publicRequest.IsSetRenameSource())
    throw new ArgumentException("RenameSource is a required property...");

// Then Generated Marshall method:
if (string.IsNullOrEmpty(publicRequest.BucketName))
    throw new ArgumentException("BucketName is a required property...");
if (string.IsNullOrEmpty(publicRequest.Key))
    throw new ArgumentException("Key is a required property...");

Impact:

  • OLD: Missing BucketName → throws BucketName exception first
  • NEW: Missing BucketName → throws RenameSource exception first (if also missing)
  • Code relying on specific exception order for error handling will break
  • Unit tests checking exception order will fail

SUMMARY

Total Breaking Changes: 2 critical issues

  1. DateTime nullability change - Affects 4 properties, will cause compilation errors in existing code
  2. Validation order change - Alters exception throwing sequence, breaking error handling logic

Recommendations:

  1. Revert DateTime properties to non-nullable DateTime with GetValueOrDefault() pattern
  2. Restore original validation order by moving all validations to PreMarshallCustomization or adjusting the order

Files Requiring Fixes:

  • sdk/src/Services/S3/Generated/Model/RenameObjectRequest.cs (DateTime properties)
  • sdk/src/Services/S3/Generated/Model/Internal/MarshallTransformations/RenameObjectRequestMarshaller.cs (validation order)
  • sdk/src/Services/S3/Custom/Model/Internal/MarshallTransformations/RenameObjectRequestMarshaller.cs (validation order)

@muhammad-othman muhammad-othman marked this pull request as ready for review December 5, 2025 18:28
request.AddSubResource("renameObject");

if (renameObjectRequest.IsSetClientToken())
if (!publicRequest.IsSetRenameSource())
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe a question for @peterrsongg: In your PRs these usually were generated as well. Why do they have to be hand-written here?

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah i can answer that. this is because RenameSource is a required header, and currently we only validate that required querystring members and resource path members are set in the generator

Copy link
Member Author

Choose a reason for hiding this comment

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

We don't validate all the properties, just RequestUriMembers and RenameSource is added to the header so we don't validate it as part of the generated code.
https://github.com/aws/aws-sdk-net/blob/muhamoth/S3-generate-RenameObject-operation/generator/ServiceClientGeneratorLib/Generators/Marshallers/BaseMarshaller.tt#L135

@muhammad-othman muhammad-othman force-pushed the muhamoth/S3-generate-RenameObject-operation branch from 58116f5 to 3391b8c Compare December 5, 2025 20:28
[SuppressMessage("Microsoft.Globalization", "CA1303:Do not pass literals as localized parameters")]
public class RenameObjectRequestMarshaller : IMarshaller<IRequest, RenameObjectRequest>, IMarshaller<IRequest, AmazonWebServiceRequest>
/// </summary>
public partial class RenameObjectRequestMarshaller : IMarshaller<IRequest, RenameObjectRequest>, IMarshaller<IRequest, AmazonWebServiceRequest>
Copy link
Contributor

Choose a reason for hiding this comment

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

https://github.com/aws/aws-sdk-net/blob/main/sdk/src/Services/S3/Custom/Model/Internal/MarshallTransformations/RenameObjectRequestMarshaller.cs#L49-L51

THis is a minor difference and i don't know why anyone would do this but the original code also checked the actual request wasn't null. Can we add that to the preMarshallCustomization too?🫠

request.AddSubResource("renameObject");

if (renameObjectRequest.IsSetClientToken())
if (!publicRequest.IsSetRenameSource())
Copy link
Contributor

Choose a reason for hiding this comment

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

yeah i can answer that. this is because RenameSource is a required header, and currently we only validate that required querystring members and resource path members are set in the generator

request.HttpMethod = "PUT";
request.AddSubResource("renameObject");

if (publicRequest.IsSetClientToken())
Copy link
Contributor

Choose a reason for hiding this comment

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

Instead of doing this and then relying on preMarshallCustomization as well, can we instead just preserve the if else logic in PreMarshallCustomization and add a customization.json entry? that way the logic for the same member isn't split between two files

        "excludeFromMarshalling":[
            "ClientToken"
        ]

Then inside PreMarshallCustomization:

            if (renameObjectRequest.IsSetClientToken())
            {
                request.Headers.Add(HeaderKeys.XAmzClientTokenHeader, S3Transforms.ToStringValue(renameObjectRequest.ClientToken));
            }
            else
            {
                request.Headers.Add(HeaderKeys.XAmzClientTokenHeader, Guid.NewGuid().ToString());
            }

Copy link
Member Author

Choose a reason for hiding this comment

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

I think we should keep most of the logic in the generated version whenever possible, though I added a comment explaining it and why the other condition can be found

@muhammad-othman muhammad-othman force-pushed the muhamoth/S3-generate-RenameObject-operation branch from 3391b8c to 5a66ae6 Compare December 5, 2025 21:33
@muhammad-othman muhammad-othman merged commit 31f2b59 into muhamoth/phase-3-pr5-base Dec 8, 2025
1 check passed
@muhammad-othman muhammad-othman deleted the muhamoth/S3-generate-RenameObject-operation branch December 8, 2025 16:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants