AWS Security ChangesHomeSearch

AWS amazondynamodb documentation change

Service: amazondynamodb · 2025-04-03 · Documentation low

File: amazondynamodb/latest/developerguide/ttl-expired-items.md

Summary

Enhanced TTL update example with conditional expressions, added validation, and improved error handling. Introduced constants for attribute names and expiration logic.

Security assessment

While the conditional check (attribute_exists) improves data integrity, this is a standard idempotency pattern rather than a security feature. No evidence of addressing vulnerabilities or documenting security controls.

Diff

diff --git a/amazondynamodb/latest/developerguide/ttl-expired-items.md b/amazondynamodb/latest/developerguide/ttl-expired-items.md
index f8c5bba87..403597d9d 100644
--- a//amazondynamodb/latest/developerguide/ttl-expired-items.md
+++ b//amazondynamodb/latest/developerguide/ttl-expired-items.md
@@ -39,2 +38,0 @@ Query Filtered Expression to gather TTL items in a DynamoDB table using AWS SDK
-    import software.amazon.awssdk.utils.ImmutableMap;
-    
@@ -44,16 +41,0 @@ Query Filtered Expression to gather TTL items in a DynamoDB table using AWS SDK
-            // Get current time in epoch second format (comparing against expiry attribute)
-            final long currentTime = System.currentTimeMillis() / 1000;
-    
-            // A string that contains conditions that DynamoDB applies after the Query operation, but before the data is returned to you.
-            final String keyConditionExpression = "#pk = :pk";
-    
-            // The condition that specifies the key values for items to be retrieved by the Query action.
-            final String filterExpression = "#ea > :ea";
-            final Map<String, String> expressionAttributeNames = ImmutableMap.of(
-                    "#pk", "primaryKey",
-                    "#ea", "expireAt");
-            final Map<String, AttributeValue> expressionAttributeValues = ImmutableMap.of(
-                    ":pk", AttributeValue.builder().s(primaryKey).build(),
-                    ":ea", AttributeValue.builder().s(String.valueOf(currentTime)).build()
-            );
-    
@@ -62,2 +44,2 @@ Query Filtered Expression to gather TTL items in a DynamoDB table using AWS SDK
-                    .keyConditionExpression(keyConditionExpression)
-                    .filterExpression(filterExpression)
+                    .keyConditionExpression(KEY_CONDITION_EXPRESSION)
+                    .filterExpression(FILTER_EXPRESSION)
@@ -67,3 +49,3 @@ Query Filtered Expression to gather TTL items in a DynamoDB table using AWS SDK
-            try (DynamoDbClient ddb = DynamoDbClient.builder()
-                    .region(region)
-                    .build()) {
+    
+            try (DynamoDbClient ddb = dynamoDbClient != null ? dynamoDbClient : 
+                    DynamoDbClient.builder().region(region).build()) {
@@ -71,6 +53,8 @@ Query Filtered Expression to gather TTL items in a DynamoDB table using AWS SDK
-                System.out.println(tableName + " Query operation with TTL successful. Request id is "
-                        + response.responseMetadata().requestId());
-                // Print the items that are not expired
-                for (Map<String, AttributeValue> item : response.items()) {
-                    System.out.println(item.toString());
-                }
+                System.out.println("Query successful. Found " + response.count() + " items that have not expired yet.");
+                
+                // Print each item
+                response.items().forEach(item -> {
+                    System.out.println("Item: " + item);
+                });
+                
+                return 0;
@@ -78,2 +62,2 @@ Query Filtered Expression to gather TTL items in a DynamoDB table using AWS SDK
-                System.err.format("Error: The Amazon DynamoDB table \"%s\" can't be found.\n", tableName);
-                System.exit(1);
+                System.err.format(TABLE_NOT_FOUND_ERROR, tableName);
+                throw e;
@@ -82 +66 @@ Query Filtered Expression to gather TTL items in a DynamoDB table using AWS SDK
-                System.exit(1);
+                throw e;
@@ -84 +67,0 @@ Query Filtered Expression to gather TTL items in a DynamoDB table using AWS SDK
-            System.exit(0);
@@ -224,0 +208,5 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
+    import java.util.Map;
+    import java.util.Optional;
+    
+    import com.amazon.samplelib.CodeSampleUtils;
+    
@@ -227,0 +216 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
+    import software.amazon.awssdk.services.dynamodb.model.ConditionalCheckFailedException;
@@ -232,4 +220,0 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
-    import software.amazon.awssdk.utils.ImmutableMap;
-    
-    import java.util.Map;
-    import java.util.Optional;
@@ -236,0 +222,4 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
+    /**
+     * Updates an item in a DynamoDB table with TTL attributes using a conditional expression.
+     * This class demonstrates how to conditionally update TTL expiration timestamps.
+     */
@@ -238,2 +227,2 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
-        public static void main(String[] args) {
-            final String usage = """
+    
+        private static final String USAGE = """
@@ -241 +230 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
-                        <tableName> <primaryKey> <sortKey> <newTtlAttribute> <region>
+                    <tableName> <primaryKey> <sortKey> <region>
@@ -246 +234,0 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
-                        newTtlAttribute - New attribute name (as part of the update command)
@@ -249,3 +237,41 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
-            // Optional "region" parameter - if args list length is NOT 3 or 4, short-circuit exit.
-            if (!(args.length == 4 || args.length == 5)) {
-                System.out.println(usage);
+        private static final int DAYS_TO_EXPIRE = 90;
+        private static final int SECONDS_PER_DAY = 24 * 60 * 60;
+        private static final String PRIMARY_KEY_ATTR = "primaryKey";
+        private static final String SORT_KEY_ATTR = "sortKey";
+        private static final String UPDATED_AT_ATTR = "updatedAt";
+        private static final String EXPIRE_AT_ATTR = "expireAt";
+        private static final String UPDATE_EXPRESSION = "SET " + UPDATED_AT_ATTR + "=:c, " + EXPIRE_AT_ATTR + "=:e";
+        private static final String CONDITION_EXPRESSION = "attribute_exists(" + PRIMARY_KEY_ATTR + ")";
+        private static final String SUCCESS_MESSAGE = "%s UpdateItem operation with TTL successful.";
+        private static final String CONDITION_FAILED_MESSAGE = "Condition check failed. Item does not exist.";
+        private static final String TABLE_NOT_FOUND_ERROR = "Error: The Amazon DynamoDB table \"%s\" can't be found.";
+    
+        private final DynamoDbClient dynamoDbClient;
+    
+        /**
+         * Constructs an UpdateTTLConditional with a default DynamoDB client.
+         */
+        public UpdateTTLConditional() {
+            this.dynamoDbClient = null;
+        }
+        
+        /**
+         * Constructs an UpdateTTLConditional with the specified DynamoDB client.
+         *
+         * @param dynamoDbClient The DynamoDB client to use
+         */
+        public UpdateTTLConditional(final DynamoDbClient dynamoDbClient) {
+            this.dynamoDbClient = dynamoDbClient;
+        }
+    
+        /**
+         * Main method to demonstrate conditionally updating an item with TTL.
+         *
+         * @param args Command line arguments
+         */
+        public static void main(final String[] args) {
+            try {
+                int result = new UpdateTTLConditional().processArgs(args);
+                System.exit(result);
+            } catch (Exception e) {
+                System.err.println(e.getMessage());
@@ -253,0 +280,15 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
+        }
+        
+        /**
+         * Process command line arguments and conditionally update an item with TTL.
+         *
+         * @param args Command line arguments
+         * @return 0 if successful, non-zero otherwise
+         * @throws ResourceNotFoundException If the table doesn't exist
+         * @throws DynamoDbException If an error occurs during the operation
+         * @throws IllegalArgumentException If arguments are invalid
+         */
+        public int processArgs(final String[] args) {
+            // Argument validation (remove or replace this line when reusing this code)
+            CodeSampleUtils.validateArgs(args, new int[]{3, 4}, USAGE);
+            
@@ -257,2 +298,3 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
-            final String newTtlAttribute = args[3];
-            Region region = Optional.ofNullable(args[4]).isEmpty() ? Region.US_EAST_1 : Region.of(args[4]);
+            final Region region = Optional.ofNullable(args.length > 3 ? args[3] : null)
+                    .map(Region::of)
+                    .orElse(Region.US_EAST_1);
@@ -263,12 +306,12 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
-            final long expireDate = currentTime + (90 * 24 * 60 * 60);
-            // An expression that defines one or more attributes to be updated, the action to be performed on them, and new values for them.
-            final String updateExpression = "SET newTtlAttribute = :val1";
-            // A condition that must be satisfied in order for a conditional update to succeed.
-            final String conditionExpression = "expireAt > :val2";
-    
-            final ImmutableMap<String, AttributeValue> keyMap =
-                    ImmutableMap.of("primaryKey", AttributeValue.fromS(primaryKey),
-                            "sortKey", AttributeValue.fromS(sortKey));
-            final Map<String, AttributeValue> expressionAttributeValues = ImmutableMap.of(
-                    ":val1", AttributeValue.builder().s(newTtlAttribute).build(),
-                    ":val2", AttributeValue.builder().s(String.valueOf(expireDate)).build()
+            final long expireDate = currentTime + (DAYS_TO_EXPIRE * SECONDS_PER_DAY);
+            
+            // Create the key map for the item to update
+            final Map<String, AttributeValue> keyMap = Map.of(
+                    PRIMARY_KEY_ATTR, AttributeValue.builder().s(primaryKey).build(),
+                    SORT_KEY_ATTR, AttributeValue.builder().s(sortKey).build()
+            );
+            
+            // Create the expression attribute values
+            final Map<String, AttributeValue> expressionAttributeValues = Map.of(
+                    ":c", AttributeValue.builder().n(String.valueOf(currentTime)).build(),
+                    ":e", AttributeValue.builder().n(String.valueOf(expireDate)).build()
@@ -280,2 +323,2 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
-                    .updateExpression(updateExpression)
-                    .conditionExpression(conditionExpression)
+                    .updateExpression(UPDATE_EXPRESSION)
+                    .conditionExpression(CONDITION_EXPRESSION)
@@ -284,3 +327,3 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
-            try (DynamoDbClient ddb = DynamoDbClient.builder()
-                    .region(region)
-                    .build()) {
+                    
+            try (DynamoDbClient ddb = dynamoDbClient != null ? dynamoDbClient : 
+                    DynamoDbClient.builder().region(region).build()) {
@@ -288,2 +331,5 @@ Update TTL on on an existing DynamoDB Item in a table, with a condition.
-                System.out.println(tableName + " UpdateItem operation with conditional TTL successful. Request id is "
-                        + response.responseMetadata().requestId());
+                System.out.println(String.format(SUCCESS_MESSAGE, tableName));
+                return 0;
+            } catch (ConditionalCheckFailedException e) {
+                System.err.println(CONDITION_FAILED_MESSAGE);