4

I am using derjust/spring-data-dynamodb library to interact with DynamoDB. I have defined a class Product as follows:

@DynamoDBTable(tableName = "product")
public class Product {

    @Id
    @NotNull
    @DynamoDBHashKey
    private String productId;

    @DynamoDBIndexHashKey(globalSecondaryIndexName = "product-category-gsi")
    private String categoryId;

    private double amount;

    // more fields, getters and setters    
}

I want to use the same code across multiple environments - dev, staging, prod. So, the table names would be dev-product, staging-product and prod-product.

The environment is available as an application property. I have configured the table name using the steps mentioned here: https://github.com/derjust/spring-data-dynamodb/wiki/Alter-table-name-during-runtime

@Configuration
@EnableDynamoDBRepositories(basePackages = "com.example.entity",dynamoDBMapperConfigRef = "dynamoDBMapperConfig")
public class DynamoDBConfiguration {

    @Value("${aws.region}")
    private String awsRegion;

    @Value("${env.name}")
    private String envName;

    @Bean
    public AmazonDynamoDB amazonDynamoDB() {
        return AmazonDynamoDBClientBuilder.standard()
            .withRegion(awsRegion)
            .build();
    }

    @Bean
    public DynamoDBMapperConfig.TableNameOverride tableNameOverrider() {
        return DynamoDBMapperConfig.TableNameOverride.withTableNameReplacement(envName + "-product");
    }

    @Bean
    public DynamoDBMapperConfig dynamoDBMapperConfig() {
        DynamoDBMapperConfig.Builder builder = new DynamoDBMapperConfig.Builder();
        builder.setTableNameOverride(tableNameOverrider());
        return new DynamoDBMapperConfig(DynamoDBMapperConfig.DEFAULT, builder.build());
    }
}

But how can I override the global secondary index name ? Currently, I have hardcoded it to "product-category-gsi".

I want to be able to set it dynamically like I am setting the table name to dev-product-category-gsi, staging-product-category-gsi and prod-product-category-gsi.

OneMoreError
  • 7,518
  • 20
  • 73
  • 112
  • why to have prefix before gsi? because any ways gsi are not global concept and applicable only in context of one table. Which anyways you have prefixed. – best wishes Mar 28 '20 at 10:06
  • I ran into the same issue in past and couldn’t find a solution. However, as stated on previous comment there is no reason to have different GSI names as long as you have different table names. – Alberto Martin Mar 29 '20 at 16:44

2 Answers2

3

You can create a constant for globalSecondaryIndexName with environment name,

public class DynamoDBConstants {
    public static final String GLOBAL_SECONDARY_INDEXNAME = System.getProperty("env.name")+"product-category-gsi";
}

And use it as below,

@DynamoDBIndexHashKey(globalSecondaryIndexName = DynamoDBConstants.GLOBAL_SECONDARY_INDEXNAME)
private String categoryId;
Vikas
  • 6,868
  • 4
  • 27
  • 41
  • This is not working, I get this error: value for annotation attribute DynamoDBIndexHashKey.globalSecondaryIndexName must be a constant expression – Tarik Mar 06 '23 at 18:00
0

It's not really an answer to your question, but I still think it's worth mentioning, since it will solve your problem and will provide more stability to your application.

It's a good practice to have separated AWS accounts for different stages: dev, staging, production.

There are multiple reasons to do it:

  1. Fine grained access to the account (all devs have access to dev, but not to production)
  2. Separate billing (for example you may limit resources on dev accounts to limit your bills)
  3. Reuse of resource names (exactly your problem)
  4. Additional security on production (enable MFA)
  5. Each account has limits. Having multiple accounts keep these limits separated and also reduces the blast radius if these limits are reached.

Another solution: Given that you don't use ALL AWS regions, you can keep your stages in different regions. I cannot recommend it, but it's an option.

Tarlog
  • 10,024
  • 2
  • 43
  • 67