From 56329e67d73ba18130b852868d6580d3d082405b Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Tue, 28 Aug 2018 15:24:31 +0200 Subject: [PATCH] Polish "Add support for com.mongodb.client.MongoClient" Closes gh-14176 --- .../mongo/MongoDataAutoConfiguration.java | 114 ++++-------------- .../MongoDataAutoConfigurationTests.java | 16 ++- .../mongo/MongoAutoConfigurationTests.java | 16 ++- .../main/asciidoc/spring-boot-features.adoc | 4 + 4 files changed, 49 insertions(+), 101 deletions(-) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java index 58cda155f0..cfbe4b1b7a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java @@ -16,9 +16,6 @@ package org.springframework.boot.autoconfigure.data.mongo; -import java.util.Arrays; -import java.util.List; - import com.mongodb.ClientSessionOptions; import com.mongodb.DB; import com.mongodb.MongoClient; @@ -32,7 +29,7 @@ import org.springframework.boot.autoconfigure.condition.AnyNestedCondition; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration.AnySyncMongoClientAvailable; +import org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration.AnyMongoClientAvailable; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; import org.springframework.boot.autoconfigure.mongo.MongoProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -43,6 +40,7 @@ import org.springframework.context.annotation.Import; import org.springframework.dao.DataAccessException; import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.data.mongodb.MongoDbFactory; +import org.springframework.data.mongodb.core.MongoDbFactorySupport; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory; import org.springframework.data.mongodb.core.SimpleMongoDbFactory; @@ -75,8 +73,9 @@ import org.springframework.util.StringUtils; * @since 1.1.0 */ @Configuration -@ConditionalOnClass({ MongoClient.class, MongoTemplate.class }) -@Conditional(AnySyncMongoClientAvailable.class) +@ConditionalOnClass({ MongoClient.class, com.mongodb.client.MongoClient.class, + MongoTemplate.class }) +@Conditional(AnyMongoClientAvailable.class) @EnableConfigurationProperties(MongoProperties.class) @Import(MongoDataConfiguration.class) @AutoConfigureAfter(MongoAutoConfiguration.class) @@ -84,22 +83,25 @@ public class MongoDataAutoConfiguration { private final MongoProperties properties; - private final MongoDbFactoryFactory dbFactoryFactory; - - public MongoDataAutoConfiguration(ObjectProvider mongoClientProvider, - ObjectProvider mongoClientClientProvider, - MongoProperties properties) { - + public MongoDataAutoConfiguration(MongoProperties properties) { this.properties = properties; - this.dbFactoryFactory = new MongoDbFactoryFactory(mongoClientProvider, - mongoClientClientProvider); } @Bean - @Conditional(AnySyncMongoClientAvailable.class) @ConditionalOnMissingBean(MongoDbFactory.class) - public MongoDbFactory mongoDbFactory() { - return this.dbFactoryFactory.getFor(this.properties.getMongoClientDatabase()); + public MongoDbFactorySupport mongoDbFactory(ObjectProvider mongo, + ObjectProvider mongoClient) { + MongoClient preferredClient = mongo.getIfAvailable(); + if (preferredClient != null) { + return new SimpleMongoDbFactory(preferredClient, + this.properties.getMongoClientDatabase()); + } + com.mongodb.client.MongoClient fallbackClient = mongoClient.getIfAvailable(); + if (fallbackClient != null) { + return new SimpleMongoClientDbFactory(fallbackClient, + this.properties.getMongoClientDatabase()); + } + throw new IllegalStateException("Expected to find at least one MongoDB client."); } @Bean @@ -183,89 +185,25 @@ public class MongoDataAutoConfiguration { } /** - * Check if either {@link com.mongodb.MongoClient} or - * {@link com.mongodb.client.MongoClient} is already defined in the - * {@link org.springframework.context.ApplicationContext}. - * - * @author Christoph Strobl - * @since 2.1 + * Check if either a {@link com.mongodb.MongoClient} or + * {@link com.mongodb.client.MongoClient} bean is available. */ - static class AnySyncMongoClientAvailable extends AnyNestedCondition { + static class AnyMongoClientAvailable extends AnyNestedCondition { - AnySyncMongoClientAvailable() { + AnyMongoClientAvailable() { super(ConfigurationPhase.REGISTER_BEAN); } - @ConditionalOnBean(com.mongodb.MongoClient.class) - static class MongoClientPreferred { + @ConditionalOnBean(MongoClient.class) + static class PreferredClientAvailable { } @ConditionalOnBean(com.mongodb.client.MongoClient.class) - static class MongoClientClientPreferred { + static class FallbackClientAvailable { } } - /** - * Encapsulation of {@link MongoDbFactory} creation depending on available beans - * {@link com.mongodb.MongoClient} or {@link com.mongodb.client.MongoClient} expressed - * via the given {@link ObjectProvider ObjectProviders}. Prefers the first available - * MongoDB client creating a suitable instance of {@link MongoDbFactory} for it. - * - * @author Christoph Strobl - * @since 2.1 - */ - static class MongoDbFactoryFactory { - - private final List> clientProviders; - - /** - * Create new instance of {@link MongoDbFactoryFactory}. - * @param clientProviders order matters here, as we choose the first available - * one. - */ - MongoDbFactoryFactory(ObjectProvider... clientProviders) { - this.clientProviders = Arrays.asList(clientProviders); - } - - /** - * Get the {@link MongoDbFactory} suitable for the first available MongoDB client. - * @param database the name of the default database to return on - * {@link MongoDbFactory#getDb()}. - * @return new instance of {@link MongoDbFactory} suitable for the first available - * MongoDB client. - */ - MongoDbFactory getFor(String database) { - - Object client = findAvailableClientProvider(); - - if (client instanceof MongoClient) { - return new SimpleMongoDbFactory(MongoClient.class.cast(client), database); - } - - if (client instanceof com.mongodb.client.MongoClient) { - return new SimpleMongoClientDbFactory( - com.mongodb.client.MongoClient.class.cast(client), database); - } - - return null; - } - - private Object findAvailableClientProvider() { - - for (ObjectProvider provider : this.clientProviders) { - Object client = provider.getIfAvailable(); - if (client != null) { - return client; - } - } - - throw new IllegalStateException( - "Expected to find at least one MongoDB client."); - } - - } - } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java index a9e6f0b5cf..432f99c3db 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java @@ -43,6 +43,7 @@ import org.springframework.data.mapping.model.PropertyNameFieldNamingStrategy; import org.springframework.data.mongodb.MongoDbFactory; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoClientDbFactory; +import org.springframework.data.mongodb.core.SimpleMongoDbFactory; import org.springframework.data.mongodb.core.convert.MongoCustomConversions; import org.springframework.data.mongodb.core.mapping.BasicMongoPersistentEntity; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; @@ -177,9 +178,16 @@ public class MongoDataAutoConfigurationTests { } @Test - public void createsMongoDbFactoryForMongoClientClientWhenBeanPresent() { + public void createsMongoDbFactoryForPreferredMongoClient() { + this.contextRunner.run((context) -> { + MongoDbFactory dbFactory = context.getBean(MongoDbFactory.class); + assertThat(dbFactory).isInstanceOf(SimpleMongoDbFactory.class); + }); + } - this.contextRunner.withUserConfiguration(WithMongoClientClientConfiguration.class) + @Test + public void createsMongoDbFactoryForFallbackMongoClient() { + this.contextRunner.withUserConfiguration(FallbackMongoClientConfiguration.class) .run((context) -> { MongoDbFactory dbFactory = context.getBean(MongoDbFactory.class); assertThat(dbFactory).isInstanceOf(SimpleMongoClientDbFactory.class); @@ -211,10 +219,10 @@ public class MongoDataAutoConfigurationTests { } @Configuration - static class WithMongoClientClientConfiguration { + static class FallbackMongoClientConfiguration { @Bean - com.mongodb.client.MongoClient mongoClient() { + com.mongodb.client.MongoClient fallbackMongoClient() { return MongoClients.create(); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java index c2eb05a29b..b86757f853 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java @@ -23,14 +23,12 @@ import com.mongodb.MongoClientOptions; import com.mongodb.client.MongoClients; import org.junit.Test; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; import static org.mockito.Mockito.mock; /** @@ -83,13 +81,13 @@ public class MongoAutoConfigurationTests { @Test public void doesNotCreateMongoClientWhenAlreadyDefined() { - this.contextRunner .withPropertyValues("spring.data.mongodb.uri:mongodb://localhost/test") - .withUserConfiguration(ConfigurationWithClientMongoClient.class) - .run((context) -> assertThatExceptionOfType( - NoSuchBeanDefinitionException.class) - .isThrownBy(() -> context.getBean(MongoClient.class))); + .withUserConfiguration(FallbackMongoClientConfig.class).run((context) -> { + assertThat(context).doesNotHaveBean(MongoClient.class); + assertThat(context) + .hasSingleBean(com.mongodb.client.MongoClient.class); + }); } @Configuration @@ -118,10 +116,10 @@ public class MongoAutoConfigurationTests { } - static class ConfigurationWithClientMongoClient { + static class FallbackMongoClientConfig { @Bean - com.mongodb.client.MongoClient mongoClient() { + com.mongodb.client.MongoClient fallbackMongoClient() { return MongoClients.create(); } diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc index 9b2cd91524..38bbfe6e58 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc @@ -4029,6 +4029,10 @@ example, you might declare the following settings in your `application.propertie spring.data.mongodb.port=27017 ---- +If you have defined your own `MongoClient`, it will be used to auto-configure a suitable +`MongoDbFactory`. Both `com.mongodb.MongoClient` and `com.mongodb.client.MongoClient` +are supported. + NOTE: If you use the Mongo 3.0 Java driver, `spring.data.mongodb.host` and `spring.data.mongodb.port` are not supported. In such cases, `spring.data.mongodb.uri` should be used to provide all of the configuration.