2

I have the following Spring Boot @Configuration class:

@Configuration
@EnableReactiveMongoRepositories
class MongoConfiguration : AbstractReactiveMongoConfiguration()
{
    override fun reactiveMongoClient() = MongoClients.create()

    override fun getDatabaseName() = "mydb"

    override fun customConversions(): MongoCustomConversions =
            MongoCustomConversions(listOf(ZonedDateTimeReadConverter(), ZonedDateTimeWriteConverter()))
}

The application fails to start, and logs this message:

The bean 'reactiveMongoTemplate', defined in class path resource [org/springframework/boot/autoconfigure/data/mongo/MongoReactiveDataAutoConfiguration.class], could not be registered. A bean with that name has already been defined in class path resource [com/mypackage/MongoConfiguration.class] and overriding is disabled.

This puzzles me, as the reactiveMongoTemplate ben method in MongoReactiveDataAutoConfiguration is configured with @ConditionalOnMissingBean.

herman
  • 11,740
  • 5
  • 47
  • 58

2 Answers2

2

The problem is in AbstractReactiveMongoConfiguration that you have sub-classed. The signature of its reactiveMongoTemplate @Bean method states that it returns ReactiveMongoOperations. Until the bean has been created, that's all the type information that is available and there is no way for the bean factory to know that the bean is actually a ReactiveMongoTemplate instance. As a result, the @ConditionaOnMissingBean that's looking for a ReactiveMongoTemplate bean doesn't find one so an attempt to define both beans is made. This should be fixed in Spring Data MongoDB so that AbstractReactiveMongoConfiguration provides as much type information as possible for its beans. I've opened DATAMONGO-2355.

You can avoid the problem by making more use of Spring Boot's auto-configuration. Rather than sub-classing AbstractReactiveMongoConfiguration you can:

  1. Use the configuration property spring.data.mongodb.database=mydb to set the database.
  2. Use the auto-configured MongoClient bean rather than defining your own.
  3. Define your own MongoCustomConversions bean that will then be used in favour of one that Boot would otherwise auto-configure.
herman
  • 11,740
  • 5
  • 47
  • 58
Andy Wilkinson
  • 108,729
  • 24
  • 257
  • 242
  • I guess they could also just specify the ‘ReactiveMongoOperations‘ either in the ‘ConditionalOnMissingBean‘ annotation or as the return type for the method in ‘MongoReactiveDataAutoConfiguration‘. – herman Sep 02 '19 at 20:07
  • See my answer for a different fix. I agree though that using more of the auto-configuration is better, and that the root cause must be fixed in Spring Data MongoDb itself. – herman Sep 03 '19 at 08:35
  • BTW it turns out I don't even need the custom conversions. One should use `Instant` in the data model as the original timezone is lost anyway when converted `java.util.Date` and stored in MongoDb in UTC :) – herman Sep 03 '19 at 10:50
0

As Andy's answer correctly points out, there is a mismatch between the return type of AbstractReactiveMongoConfiguration#reactiveMongoTemplate and the autoconfigured bean: the first one is ReactiveMongoOperations while the second one is ReactiveMongoTemplate. And as this happens to be the only type info available to the bean factory, the @ConditionalOnMissingBean has no effect.

So the problem goes away if I simply override AbstractReactiveMongoConfiguration#reactiveMongoTemplate to narrow the return type like this:

override fun reactiveMongoTemplate(): ReactiveMongoTemplate = 
        super.reactiveMongoTemplate() as ReactiveMongoTemplate

This is a hack though: the autoconfiguration should back out when any ReactiveMongoOperations bean is configured (for example, a stub).

So contrary to what Andy says, I believe the problem is not in AbstractReactiveMongoConfiguration but in MongoReactiveDataAutoConfiguration where the reactiveMongoTemplate bean method should be annotated with @ConditionalOnMissingBean(ReactiveMongoOperations.class).

This was probably forgotten because normally the actual bean will be a ReactiveMongoTemplate. But why have the ReactiveMongoOperations interface at all if it's not supported properly?

herman
  • 11,740
  • 5
  • 47
  • 58