Reputation: 1211
I'm trying to put an item in a DynamoDB table. I'm basically swapping usage of update item with put item which has the exact same logic as below, but for put item, I am getting errors:
ValidationException: ExpressionAttributeNames can only be specified when using expressions
Below is the code:
// Puts/updates item into DynamoDB table
public boolean setSessionString(String sessionId, String clientDomain, Map<String, String> keyValueMap,
long ttl) {
// TTL since epoch calculation
long timeToLiveInSeconds = ttl == 0 ? DEFAULT_TTL : ttl;
long expirationTime = System.currentTimeMillis() / 1000L + timeToLiveInSeconds;
try {
// Construct putItemSpec
PutItemSpec putItemSpec = createPutItemSpec(
createPrimaryKey(sessionId, clientDomain), keyValueMap, expirationTime);
table.putItem(putItemSpec);
return true;
} catch (final Exception e) {
throw DependencyException.builder()
.withMessage("DynamoDB update/put item error: " + e.getMessage())
.withCause(e.getCause())
.build();
}
}
// Enumerate key-value pairs to escape DynamoDB reserved keyword
private PutItemSpec createPutItemSpec(PrimaryKey primaryKey, Map<String, String> keyValueMap, long expirationTime) {
Item item = new Item().withPrimaryKey(primaryKey);
PutItemSpec putItemSpec = new PutItemSpec();
List<String> keyList = new ArrayList<String>(keyValueMap.keySet());
NameMap nameMap = new NameMap();
ValueMap valueMap = new ValueMap();
// Enumerating key-value entries
for (int keyValueIndex = 0; keyValueIndex < keyList.size(); keyValueIndex++) {
String keyEnum = "#k" + keyValueIndex;
String valueEnum = ":v" + keyValueIndex;
String key = keyList.get(keyValueIndex);
nameMap.with(keyEnum, key);
valueMap.with(valueEnum, keyValueMap.get(key));
}
// Appending ttl attribute
String ttlAttributeEscape = "#" + RESERVED_TTL_ATTRIBUTE;
String ttlValueEscape = ":" + RESERVED_TTL_ATTRIBUTE;
nameMap.with(ttlAttributeEscape, RESERVED_TTL_ATTRIBUTE);
valueMap.withLong(ttlValueEscape, expirationTime);
return putItemSpec.withNameMap(nameMap)
.withValueMap(valueMap)
.withItem(item);
}
Any suggestions on what I might be missing? There could be a key difference between update and put item spec perhaps.
Upvotes: 1
Views: 1564
Reputation: 10744
You are not using the latest Amazon DynamoDB API to put an item into an Amazon DynamoDB table. The recommended way is to use the AWS SDK for Java V2 and the Enchanced Client. Using the Enhanced Client, you can simply create a Java POJO, use its methods to set the values, and then simply call the putItem method and pass the Java object. (You do not need to use LISTS, etc)
Docs here:
Mapping items in DynamoDB tables
Here is a Java V2 example:
package com.example.dynamodb;
// snippet-start:[dynamodb.java2.mapping.putitem.import]
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbSortKey;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbBean;
import software.amazon.awssdk.enhanced.dynamodb.mapper.annotations.DynamoDbPartitionKey;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
// snippet-end:[dynamodb.java2.mapping.putitem.import]
/*
* Prior to running this code example, create an Amazon DynamoDB table named Customer with these columns:
* - id - the id of the record that is the key
* - custName - the customer name
* - email - the email value
* - registrationDate - an instant value when the item was added to the table
*
* Also, ensure that you have setup your development environment, including your credentials.
*
* For information, see this documentation topic:
*
* https://docs.aws.amazon.com/sdk-for-java/latest/developer-guide/get-started.html
*/
public class EnhancedPutItem {
public static void main(String[] args) {
Region region = Region.US_EAST_1;
DynamoDbClient ddb = DynamoDbClient.builder()
.region(region)
.build();
DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.builder()
.dynamoDbClient(ddb)
.build();
putRecord(enhancedClient) ;
ddb.close();
}
// snippet-start:[dynamodb.java2.mapping.putitem.main]
// Puts an item into a DynamoDB table
public static void putRecord(DynamoDbEnhancedClient enhancedClient) {
try {
DynamoDbTable<Customer> custTable = enhancedClient.table("Customer", TableSchema.fromBean(Customer.class));
// Create an Instant
LocalDate localDate = LocalDate.parse("2020-04-07");
LocalDateTime localDateTime = localDate.atStartOfDay();
Instant instant = localDateTime.toInstant(ZoneOffset.UTC);
// Populate the Table
Customer custRecord = new Customer();
custRecord.setCustName("Susan red");
custRecord.setId("id140");
custRecord.setEmail("[email protected]");
custRecord.setRegistrationDate(instant) ;
// Put the customer data into a DynamoDB table
custTable.putItem(custRecord);
} catch (DynamoDbException e) {
System.err.println(e.getMessage());
System.exit(1);
}
System.out.println("done");
}
// snippet-end:[dynamodb.java2.mapping.putitem.main]
}
Here is the corresponding Customer Class;
package com.example.dynamodb;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbEnhancedClient;
import software.amazon.awssdk.enhanced.dynamodb.DynamoDbTable;
import software.amazon.awssdk.enhanced.dynamodb.TableSchema;
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.DynamoDbSortKey;
import software.amazon.awssdk.enhanced.dynamodb.model.BatchWriteItemEnhancedRequest;
import software.amazon.awssdk.enhanced.dynamodb.model.WriteBatch;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.DynamoDbException;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
/**
* This class is used by the Enhanced Client examples.
*/
@DynamoDbBean
public class Customer {
private String id;
private String name;
private String email;
private Instant regDate;
@DynamoDbPartitionKey
public String getId() {
return this.id;
};
public void setId(String id) {
this.id = id;
}
public String getCustName() {
return this.name;
}
public void setCustName(String name) {
this.name = name;
}
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
public Instant getRegistrationDate() {
return regDate;
}
public void setRegistrationDate(Instant registrationDate) {
this.regDate = registrationDate;
}
}
You can find additional Enhanced Client examples here.
In addition, here is an AWS tutorial you will find in the AWS SDK Github repo that shows use of this API within a dynamic web app developed by using Spring BOOT.
Creating the DynamoDB web application item tracker
There resources show you the way to use the latest Amazon DynamoDB API.
Upvotes: 2