DynamoDB and Spring Boot

8 Jul 2019 java spring aws dynamodb

At work we were recently looking into setting up somethings in DynamoDB with Spring Boot for the first time as a team. We hit up Google and ended up on this page, https://www.baeldung.com/spring-data-dynamodb. Within a couple of seconds of reading there were a couple issues with this article that made we want to write this post. Now I know there are going to be issues with this post as well but I’m covering the big ones that were in that post.

Issue #1: AWS properties in application.properties

In step 4 of the article it has you set-up the configuration for you application. Inside the application file it has you define amazon.aws.accesskey and amazon.aws.secretkey inside the application.properties. There are many security issues that arise from doing it this way, but my biggest complaint is that it doesn’t use the Amazon specification of DefaultAWSCredentialsProviderChain.

The DefaultAWSCredentialsProviderChain is the recommended, though not required, way of utilizing the AWS SDK. More documentation can be found here, https://docs.aws.amazon.com/sdk-for-java/v1/developer-guide/credentials.html. This would allow us to move our application from development to production while utilizing local keys in development and EC2 AMI Roles in production.

Issue #2: Not utilizing the SDK builders

Again in step 4 we have the following @Bean definition

@Bean
public AmazonDynamoDB amazonDynamoDB() {
    AmazonDynamoDB amazonDynamoDB 
      = new AmazonDynamoDBClient(amazonAWSCredentials());
     
    if (!StringUtils.isEmpty(amazonDynamoDBEndpoint)) {
        amazonDynamoDB.setEndpoint(amazonDynamoDBEndpoint);
    }
     
    return amazonDynamoDB;
}

This creates a com.amazonaws.services.dynamodbv2.AmazonDynamoDBClient object directly, which is @Deprecated in favour of the com.amazonaws.services.dynamodbv2.AmazonDynamoDBClientBuilder. The builder gives a cleaner, more concise and non-deprecated version of creating your com.amazonaws.services.dynamodbv2.AmazonDynamoDB.

Issue #3: Using field-based injection

Sticking with a theme of step 4, the values in the DynamoDBConfig are configured using field-based injection. I’ve covered why field-based injection should be avoided in a previous post Spring Dependecy Injection. We can quickly fix this by utilizing contructor-based injection.

@Configuration
@EnableDynamoDBRepositories
  (basePackages = "com.baeldung.spring.data.dynamodb.repositories")
public class DynamoDBConfig {
    private final String amazonDynamoDBEndpoint;
    private final String amazonAWSAccessKey;
    private final String amazonAWSSecretKey;

    public DynamoDBConfig(@Value("${amazon.dynamodb.endpoint}") String amazonDynamoDBEndpoint, @Value("${amazon.aws.accesskey}") String amazonAWSAccessKey, @Value("${amazon.aws.secretkey}") String amazonAWSSecretKey) {
        this.amazonDynamoDBEndpoint = amazonDynamoDBEndpoint;
        this.amazonAWSAccessKey = amazonAWSAccessKey;
        this.amazonAWSSecretKey = amazonAWSSecretKey;
    }
 
    @Bean
    public AmazonDynamoDB amazonDynamoDB() {
        AmazonDynamoDB amazonDynamoDB 
          = new AmazonDynamoDBClient(amazonAWSCredentials());
         
        if (!StringUtils.isEmpty(amazonDynamoDBEndpoint)) {
            amazonDynamoDB.setEndpoint(amazonDynamoDBEndpoint);
        }
         
        return amazonDynamoDB;
    }
 
    @Bean
    public AWSCredentials amazonAWSCredentials() {
        return new BasicAWSCredentials(
          amazonAWSAccessKey, amazonAWSSecretKey);
    }
}

Those are the issues that I have with the article. I know that no article is perfect and that it’s up to the reader to properly implement the solutions provided because, sadly, we live in world of “this article/post told me to do it this way” so I’m going to take that as gospel.

Conclusion

One thing I would have like to see from the article would be to have it utilize more Springy things to do the configuration. In the article they’re checking for !StringUtils.isEmpty(amazonDynamoDBEndpoint) to see if the endpoint should be configured. Instead of using the StringUtils we could use beans to configure the endpoind, if needed.

@Bean
@ConditionalOnProperty("dynamodb.url")
public AwsClientBuilder.EndpointConfiguration endpointConfiguration(@Value("${dynamodb.url}") String dynamodbUrl,
                                                                    @Value("${dynamodb.region:us-east-1}") String dynamodbRegion) {
    return new AwsClientBuilder.EndpointConfiguration(dynamodbUrl, dynamodbRegion);
}

@Bean
public AmazonDynamoDB amazonDynamoDB(@Autowired(required = false) AwsClientBuilder.EndpointConfiguration endpointConfiguration) {
    return AmazonDynamoDBClientBuilder.standard().withEndpointConfiguration(endpointConfiguration).build();
}

This allows us to use Spring beans to configure the builder without having to do logic checks on where the property exists or not.