Simplified and simple usage of DynamoDB. Mapper assumes you've already defined reasonable marshaling of your class to and from JSON, and simply persists objects to DynamoDB tables as records with structure that reflects the objects' JSON representation.
This allows you to use libraries like FreeBuilder and AutoValue to get clean Java classes with immutable instances and minimal boilerplate, while still maintaining the simple DynamoDB persistence afforded by the DynamoDB object mapper.
Mapper supports the version attribute for optimistic locking:
@FreeBuilder
@JsonDeserialize(builder = SimpleFreeBuiltVersioned.Builder.class)
@DynamoDBTable(tableName = "simple_free_built_versioned")
interface SimpleFreeBuiltVersioned {
@DynamoDBHashKey(attributeName = "hashKey")
String getHashKey();
String getStringValue();
@DynamoDBVersionAttribute(attributeName = "version")
Optional<Integer> getVersion();
class Builder extends SimpleFreeBuiltVersioned_Builder {}
}
Note that the example above also uses Optional<T>
-- empty optionals are omitted from the JSON by Jackson, so they are
safely round-tripped to DynamoDB.
Mapper also supports specifying a range key:
@FreeBuilder
@JsonDeserialize(builder = HashAndRange.Builder.class)
@DynamoDBTable(tableName = "hash_and_range")
interface HashAndRange {
@DynamoDBHashKey(attributeName = "hashKey")
String getHashKey();
@DynamoDBRangeKey(attributeName = "rangeKey")
String getRangeKey();
class Builder extends HashAndRange_Builder {}
}
If the hash or range key needs to be autogenerated, you can use the @DynamoDBAutoGeneratedKey
annotation on a method
and Mapper will provide a UUID if a value is omitted; this only works for fields of type String
or Optional<String>
.
And in most cases vanilla Java objects will continue to work with Mapper, just like they do with the
SDK's built-in DynamoDBMapper
.
The API of mapper is simply the class JsonDynamoMapper
:
public <T> PutItemResult save(T item) throws MappingException {}
public <T> Optional<T> load(Class<T> clazz, String hashKey) throws MappingException {}
public <T> Optional<T> load(Class<T> clazz, String hashKey, String rangeKey) throws MappingException {}
public <T> ScanResultPage<T> scan(Class<T> clazz) throws MappingException {}
public <T> ScanResultPage<T> scan(Class<T> clazz, @NotNull DynamoDBScanExpression scanExpression) throws MappingException {}
public <T> T convert(Class<T> clazz, Map<String, AttributeValue> attributeValueMap) throws MappingException {}
public <T> Map<String, AttributeValue> convert(T item) throws MappingException {}
The basics of save
, load
and scan
are effectively the same as the built-in object mapper. More DynamoDB operations
can be implemented by using the simple convert
methods in conjunction with the
DynamoDB SDK's low-level API.