Dynamic Table Name in DynamoDB with Java DynamoMapper

In my current project we want AWS CloudFormation to determine the names of our DynamoDB tables by setting them as properties in a standard Java property file. Our service reads this property file on startup and thus get the tables names that we want to use. So far so good but it turns out that if we want to make use of the object mapper (DynamoMapper) that Amazon provides to allow us to annotate our entities we now run into a bit of a problem. The problem is that the Java object representing a DynamoDB entity needs a @DynamoDBTable annotation specifying the table name to use, for example @DynamoDBTable(tableName = "my_table_name"). The string "my_table_name" that we pass into the tableName attribute needs to be resolved at compile-time due to the nature of annotations in Java. Thus it seems like we need to know and specify the table name before we start our application and can read it from our property file.

Finding a work-around

Looking a bit closer at the DynamoMapper API and code I soon found a class called DynamoDBMapperConfig. This class allows us to specify a so called TableNameOverride that overrides the table name defined in the DynamoDBTable annotation in our Java entity class. At first I thought that a DynamoDBMapperConfig only could be applied globally on a single AmazonDynamoDB instance which wouldn’t work in our case since our service have several different tables. How ever it turns out that you can supply a DynamoDBMapperConfig as a second parameter to several methods in the DynamoMapper API. For example if you want to override the table name defined in the following class

when saving an instance of it to DynamoDB you could do like this:

This will ignore the table name defined by the @DynamoDBTable annotation in the MyEntity class and instead use the tableName that we read from our property file.

How about batch saving?

It was how ever a bit more problematic in our case since we wanted to use the batchSave method to save multiple entities at once to reduce costs and latency. In the AWS SDK version we used (1.5.4) there was no overloaded method of batchSave that took a DynamoDBMapperConfig as a second parameter. Looking into the source code of the DynamoMapper revealed that the batchSave method simply delegated to another method called batchWrite which took a DynamoDBMapperConfig as its third parameter. The second parameter of batchWrite specifies which entities to remove and the first parameter specifies which entities to save. So if in our case it turned out we could do like this:

That’s it!

This Post Has 11 Comments

  1. Thanks Johan! that was exactly what I was after.

  2. Great blog post! Precisely what I needed to know!

  3. I used another approach, I hope it’s helpful for others. First, create your own table name resolver:

    public static class MyTableNameResolver
    extends DynamoDBMapperConfig.DefaultTableNameResolver {
    @Override
    public String getTableName(Class clazz, DynamoDBMapperConfig config) {
    String base = super.getTableName(clazz, config);
    String suffix = System.getProperty(“dynamoDBTableSuffix”);
    return suffix == null ? base : base + suffix;
    }
    }

    And then instruct the mapper to use it:

    mapper = new DynamoDBMapper(client, new DynamoDBMapperConfig(new MyTableNameResolver()))

    Now all calls to mapper use this resolver by default and you don’t need to change anything in your code.

  4. Wow, EXACTLY what I was looking for, thank you so much!!

  5. Great article! Exactly what I was looking for! Thanks Johan!

  6. Thanks ! Saved my day :)

  7. Thanks a lot for the hint!

    My extension to that: using spring boot you can do sthg. like the following:

    @Value(“${amazon.dynamodb.tableName}”)
    private String tableName;

    @Bean
    @Autowired
    public DynamoDBMapper dynamoDbMapper(final AmazonDynamoDBClient amazonDynamoDbClient, final DynamoDBMapperConfig dynamoDBMapperConfig) {
    return new DynamoDBMapper(amazonDynamoDbClient, dynamoDBMapperConfig);
    }

    @Bean
    public DynamoDBMapperConfig dynamoDBMapperConfig() {
    return new DynamoDBMapperConfig(new TableNameOverride(this.tableName));
    }

    … and then you can use everything as before.

  8. Very helpful, I didn’t expect I could find this solution, thanks to you.

  9. Thanks a lot! Quite helpful blog.
    Just one thing ,as you have shown batchSave is an exception, is it the same case with batchLoad also ?

    Thanks

  10. This blog post really helped me. In writing test code for my DynamoDB Java code, I needed to use a temporary table. This was a headache since I had the table bound at compile time to the Java object. Your post put me on the path to the right answer.

    DynamoDBMapperConfig is “deprecated”, but I was able to find the current code which is shown below:

    DynamoDBMapper mapper = new DynamoDBMapper( client, new TableNameOverride( tableName ).config() );

Leave a Reply

Close Menu