spring-data-dynamodb
spring-data-dynamodb copied to clipboard
TableNameOverride Prefix not applying
Expected Behavior I am using the following relevant classes, built from multiple examples for running a local testing version of DynamoDB to get more familiar with the framework:
General configuration
@Configuration
@EnableDynamoDBRepositories(
dynamoDBMapperConfigRef = "dynamoDBMapperConfig",
basePackages = "my.model.package")
public class DynamoDBConfig {
private static final Logger log = LoggerFactory.getLogger(DynamoDBConfig.class);
@Value("${amazon.aws.accesskey}")
private String amazonAWSAccessKey;
@Value("${amazon.aws.secretkey}")
private String amazonAWSSecretKey;
@Value("${amazon.dynamodb.tableNameOverride}")
private String tablePrefix;
public AWSCredentialsProvider amazonAWSCredentialsProvider() {
return new AWSStaticCredentialsProvider(amazonAWSCredentials());
}
@Bean
public AWSCredentials amazonAWSCredentials() {
return new BasicAWSCredentials(amazonAWSAccessKey, amazonAWSSecretKey);
}
@Bean
public DynamoDBMapperConfig dynamoDBMapperConfig() {
// Create empty DynamoDBMapperConfig builder
DynamoDBMapperConfig.Builder builder = DynamoDBMapperConfig.builder();
builder.setTableNameOverride(DynamoDBMapperConfig.TableNameOverride.withTableNamePrefix(tablePrefix));
return new DynamoDBMapperConfig(DynamoDBMapperConfig.DEFAULT, builder.build());
}
@Bean
public DynamoDBMapper dynamoDBMapper(AmazonDynamoDB amazonDynamoDB, DynamoDBMapperConfig config) {
return new DynamoDBMapper(amazonDynamoDB, config);
}
@Bean
public AmazonDynamoDB amazonDynamoDB() {
return AmazonDynamoDBClientBuilder.standard()
.withCredentials(amazonAWSCredentialsProvider())
.withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration("http://localhost:8000", "eu-central-1")
)
.build();
}
@Bean
public DynamoDBMappingContext dynamoDBMappingContext() {
return new DynamoDBMappingContext();
}
`
Class that is run after successful application start to setup database "schema"
@Service
public class DBSetupRunner {
final Logger log = LoggerFactory.getLogger(DBSetupRunner.class);
@Value("${amazon.dynamodb.tableNameOverride}")
private String tablePrefix;
@EventListener(ApplicationReadyEvent.class)
public void main() throws Exception {
AmazonDynamoDB dynamodb = null;
System.setProperty("sqlite4java.library.path", "native-libs");
// Create an in-memory and in-process instance of DynamoDB Local that runs over HTTP
final String[] localArgs = { "-inMemory" };
DynamoDBProxyServer server = null;
server = ServerRunner.createServerFromCommandLineArgs(localArgs);
server.start();
dynamodb = AmazonDynamoDBClientBuilder.standard().withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration("http://localhost:8000", "eu-central-1"))
.build();
setupDBSchema(dynamodb);
}
public void setupDBSchema(AmazonDynamoDB dynamodb){
CreateTableResult res = createTable(dynamodb, tablePrefix + "Example", "Id");
listTables(dynamodb.listTables(), "DynamoDB Local over HTTP");
}
private static void listTables(ListTablesResult result, String method) {
System.out.println("found " + Integer.toString(result.getTableNames().size()) + " tables with " + method);
for(String table : result.getTableNames()) {
System.out.println(table);
}
}
private static CreateTableResult createTable(AmazonDynamoDB ddb, String tableName, String hashKeyName) {
List<AttributeDefinition> attributeDefinitions = new ArrayList<AttributeDefinition>();
attributeDefinitions.add(new AttributeDefinition(hashKeyName, ScalarAttributeType.S));
List<KeySchemaElement> ks = new ArrayList<KeySchemaElement>();
ks.add(new KeySchemaElement(hashKeyName, KeyType.HASH));
ProvisionedThroughput provisionedthroughput = new ProvisionedThroughput(1000L, 1000L);
CreateTableRequest request =
new CreateTableRequest()
.withTableName(tableName)
.withAttributeDefinitions(attributeDefinitions)
.withKeySchema(ks)
.withProvisionedThroughput(provisionedthroughput);
return ddb.createTable(request);
}
}
I then access the tables using basic SpringData-based RestController and Repository classes after setting amazon.dynamodb.tableNameOverride=dev_ .
in my properties file.
I expected the mapping to access "dev_Example" due to the override instead of "Example", which is stated in the model class via @DynamoDBTable(tableName = "Example")
.
Actual Behavior When I now try to GET any information from the Example table, I get this error:
com.amazonaws.services.dynamodbv2.model.ResourceNotFoundException: Cannot do operations on a non-existent table (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ResourceNotFoundException; Request ID: b600800b-0e21-4793-8220-78febf0aead0)
because the application still tries to access "Example" instead of "dev_Example" which was created in the runner.
Steps to Reproduce the Problem
- Start up application with mentioned configuration
- call any REST endpoint accessing data from the "Example"-table.
Specifications
- Spring Data DynamoDB Version:
<dependency>
<groupId>com.github.derjust</groupId>
<artifactId>spring-data-dynamodb</artifactId>
<version>5.0.2</version>
</dependency>
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>DynamoDBLocal</artifactId>
<version>[1.11,2.0)</version>
</dependency>
- Spring Data Version: 2.0.3.RELEASE
- AWS SDK Version:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-dynamodb</artifactId>
<version>1.11.351</version>
</dependency>
- Java Version: 10.0.1 - Java HotSpot(TM) 64-Bit Server VM 10.0.1+10
- Platform Details: Running from IntelliJ IDEA Spring plugin for Maven.
I tried multiple different versions, some including the stuff that is referenced in the wiki, but the prefix is never applied to my queries once my application start up.
Might help some people but after reviewing #59
I've found that it still works (in 5.03) using XML config.
Created a demo repo that might help people here:
https://github.com/clos-consultancy/SpringDynamoDB
Hello.
I've been checking this today, with the same approach that you have. The only thing I changed is the name of the property on application.properties
file and the way to instantiate the DynamoDBMapperConfig
object.
I've used amazon.dynamodb.tableNamePrefix
instead of amazon.dynamodb.tableNameOverride
. It seems that this last one redefines the table name. I'm not sure anyways on that.
I made up the name of the property amazon.dynamodb.tableNamePrefix
. Don't know if exists haha.
On the configuration class, I have.
@Configuration
@EnableDynamoDBRepositories(
dynamoDBMapperConfigRef = "dynamoDBMapperConfig",
basePackages = "package.of.repo")
public class DynamoDBConfig {
private static final String SEPARATOR = "-";
@Value("${amazon.dynamodb.tableNamePrefix}")
private String tablePrefix;
@Bean
public AmazonDynamoDB amazonDynamoDB() {
return AmazonDynamoDBClientBuilder
.standard()
.withRegion(Regions.fromName(Environment.getRegion()))
.build();
}
@Bean
public DynamoDBMapperConfig dynamoDBMapperConfig() {
DynamoDBMapperConfig.Builder builder = DynamoDBMapperConfig.builder();
builder.setTableNameOverride(DynamoDBMapperConfig.TableNameOverride.withTableNamePrefix(getFormattedPrefix()));
return builder.build();
}
@Bean
public DynamoDBMapper dynamoDBMapper(AmazonDynamoDB amazonDynamoDB, DynamoDBMapperConfig config) {
return new DynamoDBMapper(amazonDynamoDB, config);
}
private String getFormattedPrefix(){
return tablePrefix + SEPARATOR;
}
}
Maybe this could help you too.
Any luck?
Hey.
I've been using the approach I wrote a year ago. For me it works pretty good. I have several lambdas on a project with that.
https://github.com/uvsy-aws-backend/java-dynamo-client/blob/e03cc850d5495de991f51bb5475114015b656eb3/src/main/java/com/universy/dynamo/mappercreators/DynamoDBAccess.java#L19
That's the main lib from which I configure the mapper. Not using SpringData now, but is the same idea.
I would like to know why I got downvoted haha
I am using DynamoDB spring data addon, and I wanted to add a table name prefix depending on environment (dev/prod). Unfortunately, I assume, it will never be possible for older version of the client.
Do you want to share some code? We can give it a try!
I stopped using derjust's library because of this issue. And it is not as hard as I thought to re-implement those methods. Thanks for your advice, @GonzaloSaad!
public class YourDynamoRepository implements CrudRepository<YourDynamoEntity, Long> {
private final DynamoDBMapper mapper; // bean injected by spring
// One of the repository methods
@Override public <S extends YourDynamoEntity> S save(S s) {
mapper.save(s);
return s;
}
}
Alright. Good to hear that worked! Anyways, I believe with that workaround you can keep using it!