AWS Developer Tools Blog

Introducing enhanced DynamoDB client in the AWS SDK for Java v2

We are pleased to announce the release of the enhanced DynamoDB client as a new module of the AWS SDK for Java 2.0. This enhanced DynamoDB module provides a more idiomatic code authoring experience. You can now integrate applications with Amazon DynamoDB using an adaptive API that allows you to execute database operations directly with the data classes your application already works with.

Our customers frequently tell us that they miss the ‘DynamoDB mapper’ in the Java v1 SDK. Thus, we’ve redesigned original library based on all the lessons we have learned and target common problems people try to solve using such a library. For example, here is a simple example to illustrate the utility of the enhanced client using a fictional ‘Customer’ data object class:-

@DynamoDbBean
public class Customer {
    @DynamoDbPartitionKey
    public String getId() { ... };
    public void setId(String id) { ... };
    
    public String getName() { ... };
    public void setName(String name) { ... };
    
    public Instant getRegistrationDate() { ... };
    public void setRegistrationDate(Instant registrationDate) { ... };
    
    private static final DynamoDbEnhancedClient DDB_ENHANCED_CLIENT = 
        DynamoDbEnhancedClient.create();
    private static final DynamoDbTable<Customer> CUSTOMER_TABLE =
        DDB_ENHANCED_CLIENT.table("customers_table", 
                                  TableSchema.fromBean(Customer.class));
    
    // Retrieve a single customer record from the database
    public static Customer load(Customer customer) {
        return CUSTOMER_TABLE.getItem(customer);
    }
    
    // Store this customer record in the database
    public void save() {
        CUSTOMER_TABLE.putItem(this);
    }
}

In the above example, you can see how the adaptive properties of the enhanced client reduce verbosity in code. In this example, note how once initialized, the mapped table resource provides an interface that accepts and returns the modeled objects you are storing in your table and can perform all the same DynamoDB operations that you would on the base client. All of the type checking, input validation and returned value validation is done under the hood with the enhanced client allowing you to focus on ‘what’ you are trying to do rather than ‘how’. Thus, the enhanced client significantly lowers the bar of entry for developers. You can write Java applications that use DynamoDB and experiment with its functionality easily.

Key advantages with the enhanced DynamoDB client

Client operations demystified

Sometimes, working with higher-level APIs can make some of the operations a bit too abstracted and and it is not always clear they might behave in certain situations. An example of this in the original DynamoDB mapper client is all the different ‘save behaviors’. While this is well-documented, sometimes the mapper would unexpectedly make a PutItem call when you may have reasonably been expecting it to make an UpdateItem call, which is not a pleasant experience. In the enhanced client the operations do exactly what they say — ‘getItem’ performs a GetItem, ‘putItem’ performs a PutItem etc., there are no additional calls made, only transformations on the inputs and outputs of the operations you choose to perform. This makes developers be cognizant of what operations to use when, and better predict behaviors of these operations in different situations.

True asynchronous support

The DynamoDB Enhanced client is able to perform operations asynchronously by leveraging the underlying asynchronous APIs provided by the AWS SDK for Java 2.0. Instead of returning results directly, the asynchronous enhanced client operations will return CompletableFuture objects for the results. In the case of ‘iterable’ results, the asynchronous version of the enhanced client will return a Publisher that your application can subscribe to and process results as an asynchronous stream.

Faster cold-start time than the v1 DynamoDBMapper

Finally, we know that many customers are taking advantage of serverless architecture hosted in the cloud and running parts of their services in AWS Lambda. One of the original motivations of our 2.0 release was to make an SDK that could cold-start initialize faster than the v1 SDK which is critical for latency sensitive Lambda functions. By extension we took this motivation with us when implementing the enhanced client and made every effort to keep it simple, fast and efficient. One example of this is that if you choose to, instead of scanning a bean class for annotations, you can simply declare all the attributes using static lambda functions for the getters and setters and reduce the start-up cost even more over the standard bean instantiation.

In the following sections we will walk through a few basic functions in the enhanced DynamoDB library and how to use them.

A Simple walk-through of basic functions in the enhanced DynamoDB Client in Java SDK v2

Here’s a quick guide presented as a series of steps to use some of the more basic functions of the DynamoDb Enhanced Client. For a complete description of all the features the library has to offer please refer to the usage guide of the library.

Step 1 : Add a dependency for the enhanced client

The first step to getting going with the DynamoDB Enhanced Client for Java is to include a dependency for it in your project. The example here will show you how to do it in Maven, but there are more instructions in the developer guide for using other dependency management frameworks.

<dependency>
  <groupId>software.amazon.awssdk</groupId>
  <artifactId>dynamodb-enhanced</artifactId>
  <version>2.12.0</version>
</dependency>

Note: we recommend always using the most recently released version of the SDK. Instructions to get the most recently released version can be found here.

Step 2 : Add the necessary DynamoDB bean annotations to your data object

The easiest way to use the enhanced client is with a Java data class that follows the ‘bean standard’. This means the class should have a default public constructor and standard-named getters and setters for each property of the class. The absolute minimum level of annotations required is a class level annotation to designate the class as a ‘DynamoDB bean’ and an annotation on the getter or setter for the primary partition key of the record. Using the fictional Customer class from before it would look something like this :-

@DynamoDbBean
public class Customer {
    @DynamoDbPartitionKey
    public String getId() { ... };
    public void setId(String id) { ... };
    
    public String getName() { ... };
    public void setName(String name) { ... };
    
    public Instant getRegistrationDate() { ... };
    public void setRegistrationDate(Instant registrationDate) { ... };
}

Step 3 : Instantiate the enhanced client

You can instantiate the enhanced client easily using default settings and a default credential provider chain:

DynamoDbEnhancedClient enhancedClient = DynamoDbEnhancedClient.create();

If you wish to configure settings, or use an underlying DynamoDbClient you have already constructed, we recommend using the builder instead:

DynamoDbEnhancedClient enhancedClient = 
    DynamoDbEnhancedClient.builder()
                          .dynamoDbClient(dynamoDbClient)
                          .build();

Step 4 : Create a DynamoDbTable resource

The next step will create an inline ‘TableSchema’ object representing the model and structure of your record, bind it to a real table name and from that create a ‘DynamoDbTable’ resource that can be used to execute table level operations:

DynamoDbTable<Customer> customerTable =
    enhancedClient.table("customers_table", TableSchema.fromBean(Customer.class));

To break this down a bit: we are constructing a TableSchema by telling it to scan our bean class which will build a list of attributes based on the getters and setters of the class and use the annotations you added earlier to identify which of those attributes are keys. We are then putting that schema together with an actual table name to create a ‘mapped table resource’ which is typed to the object it maps to; in this case Customer.

Step 5 : Perform DynamoDB operations on the table

Now the setup work is over, you can reap the benefits by performing any table level operation you like on your mapped table resource :

customerTable.getItem(customerToGet);
customerTable.putItem(newCustomer);
customerTable.deleteItem(customerToDelete);
customerTable.scan();
// etc.

Conclusion

In this blog post we showed you how to set-up and begin using the DynamoDB enhanced client for the AWS SDK for Java 2.0. We also showed how this new library can save you time and effort by writing code that maps data stored in your table to objects in your application. The enhanced client is open-source and resides in the same repository as the AWS SDK for Java 2.0.

Try this feature and stay on the loop on GitHub. We want to add other improvements to the DynamoDB enhanced client, like a ‘document API’ for reading and writing records from the database without having to defining a schema or structure for those records. We are also thinking about launching other enhanced clients in the future, such as the S3 enhanced client that can assist with orchestrating more complex S3 operations such as multi-part uploads and downloads. Give this new library a try and share your feedback on GitHub issues page or upvote feature ideas.