diff --git a/src/cart/pom.xml b/src/cart/pom.xml
index eda2f0ab1..b746d2d9c 100644
--- a/src/cart/pom.xml
+++ b/src/cart/pom.xml
@@ -25,6 +25,18 @@
1.5.5.Final
+
+
+
+ software.amazon.awssdk
+ bom
+ 2.21.45
+ pom
+ import
+
+
+
+
org.springframework.boot
@@ -69,15 +81,17 @@
spring-boot-starter-data-mongodb
- com.amazonaws
- aws-java-sdk-dynamodb
- 1.12.603
-
+ software.amazon.awssdk
+ dynamodb
+
- com.amazonaws
- aws-java-sdk-sts
- 1.12.578
+ software.amazon.awssdk
+ dynamodb-enhanced
+
+ software.amazon.awssdk
+ sts
+
org.projectlombok
lombok
diff --git a/src/cart/src/main/java/com/amazon/sample/carts/configuration/DynamoDBConfiguration.java b/src/cart/src/main/java/com/amazon/sample/carts/configuration/DynamoDBConfiguration.java
index e7cdf3109..22afb3867 100644
--- a/src/cart/src/main/java/com/amazon/sample/carts/configuration/DynamoDBConfiguration.java
+++ b/src/cart/src/main/java/com/amazon/sample/carts/configuration/DynamoDBConfiguration.java
@@ -18,54 +18,46 @@
package com.amazon.sample.carts.configuration;
-import com.amazonaws.client.builder.AwsClientBuilder;
-import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
-import com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder;
-import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
-import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig;
-import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTypeConverterFactory;
+import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
+import software.amazon.awssdk.services.dynamodb.DynamoDbClientBuilder;
+
import com.amazon.sample.carts.services.DynamoDBCartService;
+
+import java.net.URI;
+
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.util.StringUtils;
+
import com.amazon.sample.carts.services.CartService;
@Configuration
@Profile("dynamodb")
public class DynamoDBConfiguration {
- @Bean
- public AmazonDynamoDB amazonDynamoDB(DynamoDBProperties properties) {
+ @Bean DynamoDbClient dynamoDbClient(DynamoDBProperties properties) {
+ DynamoDbClientBuilder builder = DynamoDbClient.builder();
+
if (!StringUtils.isEmpty(properties.getEndpoint())) {
- return AmazonDynamoDBClientBuilder.standard().withEndpointConfiguration(
- new AwsClientBuilder.EndpointConfiguration(properties.getEndpoint(), "us-west-2")
- ).build();
+ builder.region(Region.US_WEST_2);
+ builder.endpointOverride(URI.create(properties.getEndpoint()));
}
- return AmazonDynamoDBClientBuilder.standard().build();
- }
-
- @Bean
- public DynamoDBMapperConfig dynamoDBMapperConfig(DynamoDBProperties properties) {
- // Create empty DynamoDBMapperConfig builder
- DynamoDBMapperConfig.Builder builder = new DynamoDBMapperConfig.Builder();
- // Inject missing defaults from the deprecated method
- builder.withTypeConverterFactory(DynamoDBTypeConverterFactory.standard());
- builder.withTableNameResolver((aClass, dynamoDBMapperConfig) -> {
- return properties.getTableName();
- });
-
return builder.build();
}
@Bean
- public DynamoDBMapper dynamoDBMapper(AmazonDynamoDB amazonDynamoDB, DynamoDBMapperConfig config) {
- return new DynamoDBMapper(amazonDynamoDB, config);
+ public DynamoDbEnhancedClient dynamoDbEnhancedClient(DynamoDbClient dynamoDbClient) {
+ return DynamoDbEnhancedClient.builder()
+ .dynamoDbClient(dynamoDbClient)
+ .build();
}
@Bean
- public CartService dynamoCartService(DynamoDBMapper mapper, AmazonDynamoDB amazonDynamoDB, DynamoDBProperties properties) {
- return new DynamoDBCartService(mapper, amazonDynamoDB, properties.isCreateTable());
+ public CartService dynamoCartService(DynamoDbClient dynamoDbClient, DynamoDbEnhancedClient dynamoDbEnhancedClient, DynamoDBProperties properties) {
+ return new DynamoDBCartService(dynamoDbClient, dynamoDbEnhancedClient, properties.isCreateTable());
}
}
diff --git a/src/cart/src/main/java/com/amazon/sample/carts/configuration/DynamoDBProperties.java b/src/cart/src/main/java/com/amazon/sample/carts/configuration/DynamoDBProperties.java
index 80f90bac6..6b77efdd4 100644
--- a/src/cart/src/main/java/com/amazon/sample/carts/configuration/DynamoDBProperties.java
+++ b/src/cart/src/main/java/com/amazon/sample/carts/configuration/DynamoDBProperties.java
@@ -19,7 +19,6 @@
package com.amazon.sample.carts.configuration;
import lombok.Data;
-import lombok.Getter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
diff --git a/src/cart/src/main/java/com/amazon/sample/carts/repositories/dynamo/entities/DynamoItemEntity.java b/src/cart/src/main/java/com/amazon/sample/carts/repositories/dynamo/entities/DynamoItemEntity.java
index dce73bbfd..af892fd90 100644
--- a/src/cart/src/main/java/com/amazon/sample/carts/repositories/dynamo/entities/DynamoItemEntity.java
+++ b/src/cart/src/main/java/com/amazon/sample/carts/repositories/dynamo/entities/DynamoItemEntity.java
@@ -18,13 +18,13 @@
package com.amazon.sample.carts.repositories.dynamo.entities;
-import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBAttribute;
-import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBHashKey;
-import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBIndexHashKey;
-import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
+import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
+import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
+import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSecondaryPartitionKey;
+
import com.amazon.sample.carts.repositories.ItemEntity;
-@DynamoDBTable(tableName="Items")
+@DynamoDbBean()
public class DynamoItemEntity implements ItemEntity {
private String id;
@@ -48,28 +48,24 @@ public DynamoItemEntity() {
}
- @DynamoDBHashKey
+ @DynamoDbPartitionKey
public String getId() {
return id;
}
- @DynamoDBAttribute
- @DynamoDBIndexHashKey(globalSecondaryIndexName = "idx_global_customerId")
+ @DynamoDbSecondaryPartitionKey(indexNames = {"idx_global_customerId"})
public String getCustomerId() {
return customerId;
}
- @DynamoDBAttribute
public String getItemId() {
return itemId;
}
- @DynamoDBAttribute
public int getQuantity() {
return quantity;
}
- @DynamoDBAttribute
public int getUnitPrice() {
return unitPrice;
}
diff --git a/src/cart/src/main/java/com/amazon/sample/carts/services/DynamoDBCartService.java b/src/cart/src/main/java/com/amazon/sample/carts/services/DynamoDBCartService.java
index ec87f99c0..5ed9a1f22 100644
--- a/src/cart/src/main/java/com/amazon/sample/carts/services/DynamoDBCartService.java
+++ b/src/cart/src/main/java/com/amazon/sample/carts/services/DynamoDBCartService.java
@@ -18,66 +18,70 @@
package com.amazon.sample.carts.services;
-import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
-import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
-import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBQueryExpression;
-import com.amazonaws.services.dynamodbv2.datamodeling.PaginatedQueryList;
-import com.amazonaws.services.dynamodbv2.model.CreateTableRequest;
-import com.amazonaws.services.dynamodbv2.model.DeleteTableRequest;
-import com.amazonaws.services.dynamodbv2.model.Projection;
-import com.amazonaws.services.dynamodbv2.model.ProvisionedThroughput;
import com.amazon.sample.carts.repositories.CartEntity;
import com.amazon.sample.carts.repositories.ItemEntity;
import com.amazon.sample.carts.repositories.dynamo.entities.DynamoItemEntity;
import lombok.extern.slf4j.Slf4j;
-
+import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
+import software.amazon.awssdk.enhanced.dynamodb.DynamoDbIndex;
+import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
+import software.amazon.awssdk.enhanced.dynamodb.Key;
+import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
+import software.amazon.awssdk.enhanced.dynamodb.model.Page;
+import software.amazon.awssdk.enhanced.dynamodb.model.QueryConditional;
+import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
+import software.amazon.awssdk.services.dynamodb.model.DeleteTableRequest;
+import software.amazon.awssdk.services.dynamodb.model.ProjectionType;
+import software.amazon.awssdk.services.dynamodb.model.ResourceNotFoundException;
import jakarta.annotation.PostConstruct;
import java.util.ArrayList;
+import java.util.Iterator;
import java.util.List;
import java.util.Optional;
@Slf4j
public class DynamoDBCartService implements CartService {
- private final DynamoDBMapper mapper;
- private final AmazonDynamoDB dynamoDB;
+ private final DynamoDbClient dynamoDBClient;
private final boolean createTable;
+ private final DynamoDbTable table;
+
+ static final TableSchema CART_TABLE_SCHEMA = TableSchema.fromClass(DynamoItemEntity.class);
- public DynamoDBCartService(DynamoDBMapper mapper, AmazonDynamoDB dynamoDB, boolean createTable) {
- this.mapper = mapper;
- this.dynamoDB = dynamoDB;
+ public DynamoDBCartService(DynamoDbClient dynamoDBClient,DynamoDbEnhancedClient dynamoDbEnhancedClient, boolean createTable) {
+ this.dynamoDBClient = dynamoDBClient;
this.createTable = createTable;
+
+ this.table = dynamoDbEnhancedClient.table("Items", CART_TABLE_SCHEMA);
}
@PostConstruct
public void init() {
if(createTable) {
- DeleteTableRequest deleteTableRequest = mapper.generateDeleteTableRequest(DynamoItemEntity.class);
-
try {
- dynamoDB.describeTable(deleteTableRequest.getTableName());
-
- log.warn("Dynamo table found, deleting to recreate....");
- dynamoDB.deleteTable(deleteTableRequest);
+ dynamoDBClient.deleteTable(
+ DeleteTableRequest.builder().tableName("Items").build()
+ );
}
- catch (com.amazonaws.services.dynamodbv2.model.ResourceNotFoundException rnfe) {
- log.warn("Dynamo "+deleteTableRequest.getTableName()+" table not found");
+ catch (ResourceNotFoundException rnfe) {
+ log.warn("Dynamo table not found");
}
- ProvisionedThroughput pt = new ProvisionedThroughput(1L, 1L);
-
- CreateTableRequest tableRequest = mapper
- .generateCreateTableRequest(DynamoItemEntity.class);
- tableRequest.setProvisionedThroughput(pt);
- tableRequest.getGlobalSecondaryIndexes().get(0).setProvisionedThroughput(pt);
- tableRequest.getGlobalSecondaryIndexes().get(0).setProjection(new Projection().withProjectionType("ALL"));
- dynamoDB.createTable(tableRequest);
-
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
+ this.table.createTable(builder -> builder
+ .globalSecondaryIndices(builder3 -> builder3
+ .indexName("idx_global_customerId")
+
+ .projection(builder2 -> builder2
+ .projectionType(ProjectionType.ALL))
+ .provisionedThroughput(builder4 -> builder4
+ .writeCapacityUnits(1L)
+ .readCapacityUnits(1L)))
+ .provisionedThroughput(b -> b
+ .readCapacityUnits(1L)
+ .writeCapacityUnits(1L)
+ .build()));
+
+ this.dynamoDBClient.waiter().waitUntilTableExists(b -> b.tableName("Items"));
}
}
@@ -102,7 +106,9 @@ public List extends ItemEntity> getItems() {
public void delete(String customerId) {
List items = items(customerId);
- mapper.batchDelete(items);
+ items.forEach(item -> {
+ this.table.deleteItem(item);
+ });
}
@Override
@@ -114,7 +120,7 @@ public CartEntity merge(String sessionId, String customerId) {
public ItemEntity add(String customerId, String itemId, int quantity, int unitPrice) {
String hashKey = hashKey(customerId, itemId);
- DynamoItemEntity item = this.mapper.load(DynamoItemEntity.class, hashKey);
+ DynamoItemEntity item = this.table.getItem(Key.builder().partitionValue(hashKey(customerId, itemId)).build());
if(item != null) {
item.setQuantity(item.getQuantity() + quantity);
@@ -123,34 +129,34 @@ public ItemEntity add(String customerId, String itemId, int quantity, int unitPr
item = new DynamoItemEntity(hashKey, customerId, itemId, 1, unitPrice);
}
- this.mapper.save(item);
+ this.table.putItem(item);
return item;
}
@Override
public List items(String customerId) {
- final DynamoItemEntity gsiKeyObj = new DynamoItemEntity();
- gsiKeyObj.setCustomerId(customerId);
- final DynamoDBQueryExpression queryExpression =
- new DynamoDBQueryExpression<>();
- queryExpression.setHashKeyValues(gsiKeyObj);
- queryExpression.setIndexName("idx_global_customerId");
- queryExpression.setConsistentRead(false); // cannot use consistent read on GSI
- final PaginatedQueryList results =
- mapper.query(DynamoItemEntity.class, queryExpression);
-
- return new ArrayList<>(results);
+ DynamoDbIndex index = this.table.index("idx_global_customerId");
+ QueryConditional q = QueryConditional.keyEqualTo(Key.builder().partitionValue(customerId).build());
+ Iterator> result = index.query(q).iterator();
+ List users = new ArrayList<>();
+
+ while (result.hasNext()) {
+ Page userPage = result.next();
+ users.addAll(userPage.items());
+ }
+
+ return users;
}
@Override
public Optional item(String customerId, String itemId) {
- return Optional.of(mapper.load(DynamoItemEntity.class, hashKey(customerId, itemId)));
+ return Optional.of(this.table.getItem(Key.builder().partitionValue(hashKey(customerId, itemId)).build()));
}
@Override
public void deleteItem(String customerId, String itemId) {
- item(customerId, itemId).ifPresentOrElse(this.mapper::delete,
+ item(customerId, itemId).ifPresentOrElse(this.table::deleteItem,
()
-> log.warn("Item missing for delete {} -- {}", customerId, itemId));
}
@@ -162,7 +168,7 @@ public Optional update(String customerId, String itemId, int q
item.setQuantity(quantity);
item.setUnitPrice(unitPrice);
- this.mapper.save(item);
+ this.table.updateItem(item);
return item;
}
diff --git a/src/cart/src/test/java/com/amazon/sample/carts/services/DynamoDBCartServiceTests.java b/src/cart/src/test/java/com/amazon/sample/carts/services/DynamoDBCartServiceTests.java
index 6bb27e3e2..3cb2622dd 100644
--- a/src/cart/src/test/java/com/amazon/sample/carts/services/DynamoDBCartServiceTests.java
+++ b/src/cart/src/test/java/com/amazon/sample/carts/services/DynamoDBCartServiceTests.java
@@ -18,8 +18,9 @@
package com.amazon.sample.carts.services;
-import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
-import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapper;
+import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
+import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
+
import com.amazon.sample.carts.configuration.DynamoDBConfiguration;
import com.amazon.sample.carts.configuration.DynamoDBProperties;
import org.junit.jupiter.api.Tag;
@@ -54,7 +55,7 @@ public class DynamoDBCartServiceTests extends AbstractServiceTests {
private DynamoDBCartService service;
@Autowired
- private AmazonDynamoDB dynamodb;
+ private DynamoDbClient dynamoDbClient;
@Container
public static GenericContainer dynamodbContainer =
@@ -72,10 +73,10 @@ public CartService getService() {
static class TestConfiguration {
@Autowired
- private AmazonDynamoDB amazonDynamoDB;
+ private DynamoDbClient dynamoDbClient;
@Autowired
- private DynamoDBMapper mapper;
+ private DynamoDbEnhancedClient dynamoDbEnhancedClient;
}
public static class Initializer implements