spring-data-dynamodb icon indicating copy to clipboard operation
spring-data-dynamodb copied to clipboard

Second instance of DynamoDBMapperConfig being created

Open GynnRickerbyNZPost opened this issue 6 years ago • 14 comments

In updating to 5.1.0, on startup we're now getting:

Unsatisfied dependency expressed through constructor parameter 1; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dynamoDBMapper' defined in class path resource [{Propriety class details removed}]: Unsatisfied dependency expressed through method 'dynamoDBMapper' parameter 1; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig' available: expected single matching bean but found 2: dynamoDBMapperConfig,dynamoDB-DynamoDBMapperConfig

We're creating the DynamoDBMapperConfig as per https://github.com/derjust/spring-data-dynamodb/wiki/Alter-table-name-during-runtime. Looks like something else is also now creating a DynamoDBMapperConfig.

Should these be created now in a different fashion?

GynnRickerbyNZPost avatar Feb 05 '19 02:02 GynnRickerbyNZPost

@GynnRickerbyNZPost

I had the same problem and I found out that I was configuring another DynamoDBMapperConfig bean.

So I removed this extra bean and the error stopped, remaining only the dynamoDB-DynamoDBMapperConfig.

Best regards,

Tiago Peixoto.

tiagocpeixoto avatar Feb 07 '19 13:02 tiagocpeixoto

Yes, but I need to configure the DynamoDBMapperConfig to specify table name overrides.

The dynamoDB-DynamoDBMapperConfig one is being created internally (and seems didn't use to be in previous versions), and there's no obvious new documentation on how to turn it off.

GynnRickerbyNZPost avatar Feb 07 '19 20:02 GynnRickerbyNZPost

@GynnRickerbyNZPost

Have you tried to set dynamoDBMapperConfigRef property of @EnableDynamoDBRepositories to point to your custom config?

For exemple (in Kotlin):

@EnableDynamoDBRepositories(dynamoDBMapperConfigRef = "customDynamoDBMapperConfig")
class DynamoDbConfig() {

    @Bean("customDynamoDBMapperConfig")
    fun dynamoDBMapperConfig(): DynamoDBMapperConfig = DynamoDBMapperConfig.DEFAULT
}

tiagocpeixoto avatar Feb 10 '19 22:02 tiagocpeixoto

Yes. And works fine in 5.0.4.

@Configuration
@EnableDynamoDBRepositories(dynamoDBMapperConfigRef = "dynamoDBMapperConfig")
public class DynamoDBConfig {

  	@Bean("dynamoDBMapperConfig")
	public DynamoDBMapperConfig dynamoDBMapperConfig(final TableNameOverride tableNameOverrider) {

GynnRickerbyNZPost avatar Feb 10 '19 22:02 GynnRickerbyNZPost

A quick looking around the code, it looks like DynamoDBMapperConfigFactory was added in 5.1.0, as a FactoryBean which Spring Boot is picking up.

Unfortunately since I've got it working with 5.0.4 I don't have the spare time (project manager is happy with older version working) to go back and work out the appropriate config to override the FactoryBean to use my own settings.

GynnRickerbyNZPost avatar Feb 10 '19 23:02 GynnRickerbyNZPost

I ran into this same problem in Spring Boot, but didn't have to override the factory bean, I just removed the ConfigRef from the @EnabledDynamoDBRepositories annotation. If you have a DynamoDBMapperConfig bean the postProcessAfterInitialization method in the DynamoDBMapperConfigFactory will find it and use it.

Have you tried changing @EnableDynamoDBRepositories(dynamoDBMapperConfigRef = "dynamoDBMapperConfig") to just this @EnableDynamoDBRepositories If this is the correct intent, the documentation found here Alter table name during runtime may need to be updated.

emckissick avatar Feb 12 '19 18:02 emckissick

I created a PR. Hope it helps!

Feel free to give me feedback.

tiagocpeixoto avatar Feb 24 '19 02:02 tiagocpeixoto

I made a new fix related to this issue.

tiagocpeixoto avatar Mar 09 '19 23:03 tiagocpeixoto

Any ETA on this? We'd been waiting for 5.1 to go to Spring Boot 2.1, but now we'll need to wait for this fix as well.

efenderbosch avatar Mar 25 '19 18:03 efenderbosch

I figured out a couple ways to get around this until the next release.

First, when you are creating your @Bean instances of the config and mapper, tag them with @org.springframework.context.annotation.Primary

Second, and not as good, in my opinion, use @javax.inject.Named on other beans that get the above beans injected.

efenderbosch avatar Mar 29 '19 19:03 efenderbosch

Hi, just to make it clear: I tried this library v5.1 following step by step the tutorial and I've the exception reported above:

Parameter 1 of constructor in org.socialsignin.spring.data.dynamodb.repository.util.Entity2DynamoDBTableSynchronizer required a single bean, but 2 were found:
	- dynamoDBMapper: defined by method 'dynamoDBMapper' in class path resource [cloud/optix/server/config/DynamoDBConfig.class]
	- dynamoDB-DynamoDBMapper: defined in null

I do not have a multiple dynamoDBMapperConfig, I'm just using the basic configuration. Should I move back to the previous version? I'm using Spring Boot 2.1.4

Thanks

drenda avatar Apr 19 '19 07:04 drenda

@emckissick's suggestion worked for us. I'm not sure if there are any other possible pitfalls to using this approach, but simply removing the dynamoDBMapperConfigRef from the @ EnableDynamoDBRepositories annotation and including our own bean definition of the mapper config worked a treat.

Example:

@Configuration
@ConfigurationProperties("amazon.aws")
@Setter
@EnableDynamoDBRepositories(basePackages = "com.package.adapters.dynamodb")
public class PersistenceConfig {

    @NotBlank
    private String accessKey;

    @NotBlank
    private String secretKey;

    @Bean
    public AmazonDynamoDB amazonDynamoDB() {
        BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
        AWSStaticCredentialsProvider credentialsProvider = new AWSStaticCredentialsProvider(credentials);
        return AmazonDynamoDBClientBuilder
                .standard()
                .withCredentials(credentialsProvider)
                .build();
    }

    @Bean
    public DynamoDBMapperConfig dynamoDBMapperConfig() {
        return new DynamoDBMapperConfig.Builder()
                .withTableNameOverride(withTableNamePrefix("local."))
                .build();
    }
}

stevebakh avatar Apr 30 '19 08:04 stevebakh

Like others, I already had a @Bean DynamoDBMapperConfig defined.

For me a combination of removing dynamoDBMapperConfigRef from the @EnableDynamoDBRepositories annotation and also marking my existing DynamoDBMapperConfig bean definition as @Primary seemed to do the trick.

rratliff avatar Apr 30 '19 14:04 rratliff

The following does the trick for me. Primary annotation and the removal of dynamoDBMapperConfigRef

//Make sure there is no dynamoDBMapperConfigRef
@EnableDynamoDBRepositories(basePackageClasses = User.class) 

@Bean
@Primary
public DynamoDBMapper dynamoDBMapper(AmazonDynamoDB amazonDynamoDB, DynamoDBMapperConfig config) {
    return new DynamoDBMapper(amazonDynamoDB, config);
}

@Bean
@Primary
public DynamoDBMapperConfig dynamoDBMapperConfig() {
     return DynamoDBMapperConfig.DEFAULT;
}

sunmingtao avatar Dec 23 '20 23:12 sunmingtao