aws-sdk-java-v2 icon indicating copy to clipboard operation
aws-sdk-java-v2 copied to clipboard

The SDK v2 does not provide a Regions enum like v1 used to (was: Missing us-east-1 in BucketLocationConstraint)

Open pybeaudouin opened this issue 3 years ago • 7 comments

Describe the bug

We are using BucketLocationConstraint to bind application properties to a valid S3 Region.

Related : https://github.com/aws/aws-sdk-java-v2/issues/1324

Expected Behavior

The object s3Region is instantiated.

Current Behavior

java.lang.IllegalArgumentException: No enum constant software.amazon.awssdk.services.s3.model.BucketLocationConstraint.us-east-1

Reproduction Steps

demo.s3.region: "us-east-1"
@ConfigurationProperties("demo")
public class S3Properties {
    BucketLocationConstraint s3Region;
}

Possible Solution

Add the missing value(s) to service-2.json

Additional Information/Context

Note: this value is then passed to the S3Client builder like so :

S3Client.builder()
    .region(Region.of(s3Properties.getRegion().toString()))

We looked into using a Region enum directly, but we could not find an equivalent of the Regions enum from AWS SDK v1.

AWS Java SDK version used

2.17.246

JDK version used

17.0.4

Operating System and version

macOS Monterey 12.5

pybeaudouin avatar Aug 05 '22 21:08 pybeaudouin

The SDK v2 equivalent to v1 Regions enum is software.amazon.awssdk.regions.Region: https://sdk.amazonaws.com/java/api/latest/software/amazon/awssdk/regions/Region.html

Can you use Region instead of BucketLocationConstraint?

debora-ito avatar Aug 05 '22 22:08 debora-ito

Hello @debora-ito , I had found it but it is not an enum. Therefore it is possible to instantiate objects with invalid Region ids, like "this-does-not-exist".

pybeaudouin avatar Aug 05 '22 23:08 pybeaudouin

There is even a unit test using "first" as the region id : https://github.com/aws/aws-sdk-java-v2/blob/584ccb59e770177aeaa4c3b6bda4e24015b8ece9/core/regions/src/test/java/software/amazon/awssdk/regions/RegionTest.java#L49

pybeaudouin avatar Aug 05 '22 23:08 pybeaudouin

I found the following documentation piece in GetBucketLocationResponse :

Specifies the Region where the bucket resides. For a list of all the Amazon S3 supported location constraints by Region, see Regions and Endpoints. Buckets in Region us-east-1 have a LocationConstraint of null.

Is there an enum containing all regions or S3 bucket locations (including us-east-1), like the Regions enum of the SDK v1?

If not, we can keep using BucketLocationConstraint and make an exception for us-east-1.

pybeaudouin avatar Aug 06 '22 01:08 pybeaudouin

@pybeaudouin seems like you're using Spring Boot. You can bind to Region even if it is not an enum if you add custom converter bean annotated with @ConfigurationPropertiesBinding:

import software.amazon.awssdk.regions.Region;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConfigurationPropertiesBinding;
import org.springframework.core.convert.converter.Converter;
import org.springframework.stereotype.Component;

@ConfigurationProperties("s3")
record S3Properties(Region region) {}

@Component
@ConfigurationPropertiesBinding
class RegionConverter implements Converter<String, Region> {

    @Override public Region convert(String source) {
        return Region.of(source);
    }
}

maciejwalkowiak avatar Aug 06 '22 07:08 maciejwalkowiak

@maciejwalkowiak Thank you for your help.

This is not a Spring Boot issue. In fact, it is able to bind Strings to Regions without a converter.

The issue is that Region allows building objects with invalid region identifiers, such as "first".

Using the AWS SDK for Java v1, one can use the enum Regions and get type safety.

Using the AWS SDK for Java v2, I ended up building my own wrapper :

// Lombok imports
@Getter
@FieldDefaults(level = AccessLevel.PRIVATE)
public static class S3BucketRegion {
  String id;

  /** This constructor is used by Spring to bind properties. */
  public S3BucketRegion(String id) {
    if ("us-east-1".equals(id)) {
      this.id = id;
      return;
    }

    final var bucketLocation = BucketLocationConstraint.fromValue(id);
    if (bucketLocation != null && bucketLocation != UNKNOWN_TO_SDK_VERSION) {
      this.id = id;
      return;
    }

    throw new IllegalArgumentException("Unsupported AWS S3 region id : " + id);
  }
}

pybeaudouin avatar Aug 06 '22 19:08 pybeaudouin

As the name suggests, BucketLocationConstraint should not be used to represent regions. I have renamed the issue to highlight the problem.

I would be interested in learning about the decision behind dropping Regions. It could be "as designed" and not a "bug".

In any case, I am now using the solution I posted above.

pybeaudouin avatar Aug 06 '22 19:08 pybeaudouin

It's by design. Java SDK v1 Regions enum was hand-written, every time a new region was released we had to manually update the code. In Java SDK v2 the region list is now auto-generated, and the ability to provide a region via a String is for flexibility.

It looks like you have a workaround in place, so I'll go ahead and close this. Feel free to reach out if you have any other question.

debora-ito avatar Aug 26 '22 23:08 debora-ito

⚠️COMMENT VISIBILITY WARNING⚠️

Comments on closed issues are hard for our team to see. If you need more assistance, please open a new issue that references this one. If you wish to keep having a conversation with other community members under this issue feel free to do so.

github-actions[bot] avatar Aug 26 '22 23:08 github-actions[bot]