diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ConditionalOnRepositoryType.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ConditionalOnRepositoryType.java new file mode 100644 index 0000000000..dbe5adc88f --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/ConditionalOnRepositoryType.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +import org.springframework.context.annotation.Conditional; + +/** + * {@link Conditional} that only matches when a particular type of Spring Data repository + * has been enabled. + * + * @author Andy Wilkinson + * @since 2.0.0 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.TYPE, ElementType.METHOD }) +@Documented +@Conditional(OnRepositoryTypeCondition.class) +public @interface ConditionalOnRepositoryType { + + /** + * The name of the store that backs the repositories. + * @return the store + */ + String store(); + + /** + * The required repository type. + * @return the required repository type + */ + RepositoryType type(); + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/OnRepositoryTypeCondition.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/OnRepositoryTypeCondition.java new file mode 100644 index 0000000000..bddc49ad41 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/OnRepositoryTypeCondition.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data; + +import java.util.Locale; +import java.util.Map; + +import org.springframework.boot.autoconfigure.condition.ConditionMessage; +import org.springframework.boot.autoconfigure.condition.ConditionOutcome; +import org.springframework.boot.autoconfigure.condition.SpringBootCondition; +import org.springframework.context.annotation.ConditionContext; +import org.springframework.core.env.Environment; +import org.springframework.core.type.AnnotatedTypeMetadata; + +/** + * {@link SpringBootCondition} for controlling what type of Spring Data repositories are + * auto-configured. + * + * @author Andy Wilkinson + */ +class OnRepositoryTypeCondition extends SpringBootCondition { + + @Override + public ConditionOutcome getMatchOutcome(ConditionContext context, + AnnotatedTypeMetadata metadata) { + Map attributes = metadata.getAnnotationAttributes( + ConditionalOnRepositoryType.class.getName(), true); + RepositoryType configuredType = getTypeProperty(context.getEnvironment(), + (String) attributes.get("store")); + RepositoryType requiredType = (RepositoryType) attributes.get("type"); + ConditionMessage.Builder message = ConditionMessage + .forCondition(ConditionalOnRepositoryType.class); + if (configuredType == requiredType || configuredType == RepositoryType.AUTO) { + return ConditionOutcome.match(message.because("configured type of '" + + configuredType.name() + "' matched required type")); + } + return ConditionOutcome + .noMatch(message.because("configured type (" + configuredType.name() + + ") did not match required type (" + requiredType.name() + ")")); + } + + private RepositoryType getTypeProperty(Environment environment, String store) { + return RepositoryType.valueOf(environment + .getProperty(String.format("spring.data.%s.repositories.type", store), + "auto") + .toUpperCase(Locale.ENGLISH)); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/RepositoryType.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/RepositoryType.java new file mode 100644 index 0000000000..2c1ccaea9f --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/RepositoryType.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data; + +/** + * Type of Spring Data repositories to enable. + * + * @author Andy Wilkinson + * @since 2.0.0 + */ +public enum RepositoryType { + + /** + * Enables all repository types automatically based on their availability. + */ + AUTO, + + /** + * Enables imperative repositories. + */ + IMPERATIVE, + + /** + * Enables no repositories. + */ + NONE, + + /** + * Enables reactive repositories. + */ + REACTIVE; + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraReactiveRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraReactiveRepositoriesAutoConfiguration.java index d75d44a4c8..fb6c88628c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraReactiveRepositoriesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraReactiveRepositoriesAutoConfiguration.java @@ -20,7 +20,8 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType; +import org.springframework.boot.autoconfigure.data.RepositoryType; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.cassandra.ReactiveSession; @@ -39,7 +40,7 @@ import org.springframework.data.cassandra.repository.support.ReactiveCassandraRe */ @Configuration @ConditionalOnClass({ ReactiveSession.class, ReactiveCassandraRepository.class }) -@ConditionalOnProperty(prefix = "spring.data.cassandra.reactiverepositories", name = "enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnRepositoryType(store = "cassandra", type = RepositoryType.REACTIVE) @ConditionalOnMissingBean(ReactiveCassandraRepositoryFactoryBean.class) @Import(CassandraReactiveRepositoriesAutoConfigureRegistrar.class) @AutoConfigureAfter(CassandraReactiveDataAutoConfiguration.class) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraRepositoriesAutoConfiguration.java index 1b570472db..7dce53d1e4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraRepositoriesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraRepositoriesAutoConfiguration.java @@ -21,7 +21,8 @@ import com.datastax.driver.core.Session; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType; +import org.springframework.boot.autoconfigure.data.RepositoryType; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.cassandra.repository.CassandraRepository; @@ -38,7 +39,7 @@ import org.springframework.data.cassandra.repository.support.CassandraRepository */ @Configuration @ConditionalOnClass({ Session.class, CassandraRepository.class }) -@ConditionalOnProperty(prefix = "spring.data.cassandra.repositories", name = "enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnRepositoryType(store = "cassandra", type = RepositoryType.IMPERATIVE) @ConditionalOnMissingBean(CassandraRepositoryFactoryBean.class) @Import(CassandraRepositoriesAutoConfigureRegistrar.class) public class CassandraRepositoriesAutoConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesAutoConfiguration.java index 8b716de4f4..e907128852 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesAutoConfiguration.java @@ -24,7 +24,8 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 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.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType; +import org.springframework.boot.autoconfigure.data.RepositoryType; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.couchbase.repository.ReactiveCouchbaseRepository; @@ -40,7 +41,7 @@ import org.springframework.data.couchbase.repository.support.ReactiveCouchbaseRe */ @Configuration @ConditionalOnClass({ Bucket.class, ReactiveCouchbaseRepository.class, Flux.class }) -@ConditionalOnProperty(prefix = "spring.data.couchbase.reactiverepositories", name = "enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnRepositoryType(store = "couchbase", type = RepositoryType.REACTIVE) @ConditionalOnBean(ReactiveRepositoryOperationsMapping.class) @ConditionalOnMissingBean(ReactiveCouchbaseRepositoryFactoryBean.class) @Import(CouchbaseReactiveRepositoriesRegistrar.class) diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfiguration.java index a5d68cba26..451538a2be 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfiguration.java @@ -22,7 +22,8 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; 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.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType; +import org.springframework.boot.autoconfigure.data.RepositoryType; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.couchbase.repository.CouchbaseRepository; @@ -40,7 +41,7 @@ import org.springframework.data.couchbase.repository.support.CouchbaseRepository @Configuration @ConditionalOnClass({ Bucket.class, CouchbaseRepository.class }) @ConditionalOnBean(RepositoryOperationsMapping.class) -@ConditionalOnProperty(prefix = "spring.data.couchbase.repositories", name = "enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnRepositoryType(store = "couchbase", type = RepositoryType.IMPERATIVE) @ConditionalOnMissingBean(CouchbaseRepositoryFactoryBean.class) @Import(CouchbaseRepositoriesRegistrar.class) public class CouchbaseRepositoriesAutoConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveRepositoriesAutoConfiguration.java index 51206fa7a6..b96f471488 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveRepositoriesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveRepositoriesAutoConfiguration.java @@ -22,7 +22,8 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType; +import org.springframework.boot.autoconfigure.data.RepositoryType; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.mongodb.repository.ReactiveMongoRepository; @@ -51,7 +52,7 @@ import org.springframework.data.mongodb.repository.support.ReactiveMongoReposito @ConditionalOnClass({ MongoClient.class, ReactiveMongoRepository.class }) @ConditionalOnMissingBean({ ReactiveMongoRepositoryFactoryBean.class, ReactiveMongoRepositoryConfigurationExtension.class }) -@ConditionalOnProperty(prefix = "spring.data.mongodb.reactiverepositories", name = "enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnRepositoryType(store = "mongodb", type = RepositoryType.REACTIVE) @Import(MongoReactiveRepositoriesAutoConfigureRegistrar.class) @AutoConfigureAfter(MongoReactiveDataAutoConfiguration.class) public class MongoReactiveRepositoriesAutoConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoRepositoriesAutoConfiguration.java index acb9943d4d..3028dd03de 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoRepositoriesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoRepositoriesAutoConfiguration.java @@ -22,7 +22,8 @@ import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType; +import org.springframework.boot.autoconfigure.data.RepositoryType; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.mongodb.repository.MongoRepository; @@ -55,7 +56,7 @@ import org.springframework.data.mongodb.repository.support.MongoRepositoryFactor @ConditionalOnClass({ Mongo.class, MongoRepository.class }) @ConditionalOnMissingBean({ MongoRepositoryFactoryBean.class, MongoRepositoryConfigurationExtension.class }) -@ConditionalOnProperty(prefix = "spring.data.mongodb.repositories", name = "enabled", havingValue = "true", matchIfMissing = true) +@ConditionalOnRepositoryType(store = "mongodb", type = RepositoryType.IMPERATIVE) @Import(MongoRepositoriesAutoConfigureRegistrar.class) @AutoConfigureAfter(MongoDataAutoConfiguration.class) public class MongoRepositoriesAutoConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 1a47f32070..240783324a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -95,32 +95,40 @@ "defaultValue": "none" }, { - "name": "spring.data.cassandra.reactiverepositories.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable Cassandra reactive repositories.", - "defaultValue": true + "name": "spring.data.cassandra.repositories.type", + "type": "org.springframework.boot.autoconfigure.data.RepositoryType", + "description": "Type of Cassandra repositories to enable.", + "defaultValue": "auto" }, { "name": "spring.data.cassandra.repositories.enabled", "type": "java.lang.Boolean", "description": "Whether to enable Cassandra repositories.", - "defaultValue": true + "defaultValue": true, + "deprecation": { + "replacement": "spring.data.cassandra.repositories.type", + "level": "error" + } }, { "name": "spring.data.couchbase.consistency", "defaultValue": "read-your-own-writes" }, { - "name": "spring.data.couchbase.reactiverepositories.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable Couchbase reactive repositories.", - "defaultValue": true + "name": "spring.data.couchbase.repositories.type", + "type": "org.springframework.boot.autoconfigure.data.RepositoryType", + "description": "Type of Couchbase repositories to enable.", + "defaultValue": "auto" }, { "name": "spring.data.couchbase.repositories.enabled", "type": "java.lang.Boolean", "description": "Whether to enable Couchbase repositories.", - "defaultValue": true + "defaultValue": true, + "deprecation": { + "replacement": "spring.data.couchbase.repositories.type", + "level": "error" + } }, { "name": "spring.data.elasticsearch.repositories.enabled", @@ -141,16 +149,20 @@ "defaultValue": true }, { - "name": "spring.data.mongodb.reactiverepositories.enabled", - "type": "java.lang.Boolean", - "description": "Whether to enable Mongo reactive repositories.", - "defaultValue": true + "name": "spring.data.mongodb.repositories.type", + "type": "org.springframework.boot.autoconfigure.data.RepositoryType", + "description": "Type of Mongo repositories to enable.", + "defaultValue": "auto" }, { "name": "spring.data.mongodb.repositories.enabled", "type": "java.lang.Boolean", "description": "Whether to enable Mongo repositories.", - "defaultValue": true + "defaultValue": true, + "deprecation": { + "replacement": "spring.data.mongodb.repositories.type", + "level": "error" + } }, { "name": "spring.data.neo4j.open-in-view", diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ConditionalOnRepositoryTypeTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ConditionalOnRepositoryTypeTests.java new file mode 100644 index 0000000000..ac9ffaa3b9 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/ConditionalOnRepositoryTypeTests.java @@ -0,0 +1,131 @@ +/* + * Copyright 2012-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data; + +import org.junit.Test; + +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Configuration; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link ConditionalOnRepositoryType}. + * + * @author Andy Wilkinson + */ +public class ConditionalOnRepositoryTypeTests { + + private final ApplicationContextRunner runner = new ApplicationContextRunner(); + + @Test + public void imperativeRepositoryMatchesWithNoConfiguredType() { + this.runner.withUserConfiguration(ImperativeRepository.class) + .run((context) -> assertThat(context) + .hasSingleBean(ImperativeRepository.class)); + } + + @Test + public void reactiveRepositoryMatchesWithNoConfiguredType() { + this.runner.withUserConfiguration(ReactiveRepository.class).run( + (context) -> assertThat(context).hasSingleBean(ReactiveRepository.class)); + } + + @Test + public void imperativeRepositoryMatchesWithAutoConfiguredType() { + this.runner.withUserConfiguration(ImperativeRepository.class) + .withPropertyValues("spring.data.test.repositories.type:auto") + .run((context) -> assertThat(context) + .hasSingleBean(ImperativeRepository.class)); + } + + @Test + public void reactiveRepositoryMatchesWithAutoConfiguredType() { + this.runner.withUserConfiguration(ReactiveRepository.class) + .withPropertyValues("spring.data.test.repositories.type:auto") + .run((context) -> assertThat(context) + .hasSingleBean(ReactiveRepository.class)); + } + + @Test + public void imperativeRepositoryMatchesWithImperativeConfiguredType() { + this.runner.withUserConfiguration(ImperativeRepository.class) + .withPropertyValues("spring.data.test.repositories.type:imperative") + .run((context) -> assertThat(context) + .hasSingleBean(ImperativeRepository.class)); + } + + @Test + public void reactiveRepositoryMatchesWithReactiveConfiguredType() { + this.runner.withUserConfiguration(ReactiveRepository.class) + .withPropertyValues("spring.data.test.repositories.type:reactive") + .run((context) -> assertThat(context) + .hasSingleBean(ReactiveRepository.class)); + } + + @Test + public void imperativeRepositoryDoesNotMatchWithReactiveConfiguredType() { + this.runner.withUserConfiguration(ImperativeRepository.class) + .withPropertyValues("spring.data.test.repositories.type:reactive") + .run((context) -> assertThat(context) + .doesNotHaveBean(ImperativeRepository.class)); + } + + @Test + public void reactiveRepositoryDoesNotMatchWithImperativeConfiguredType() { + this.runner.withUserConfiguration(ReactiveRepository.class) + .withPropertyValues("spring.data.test.repositories.type:imperative") + .run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveRepository.class)); + } + + @Test + public void imperativeRepositoryDoesNotMatchWithNoneConfiguredType() { + this.runner.withUserConfiguration(ImperativeRepository.class) + .withPropertyValues("spring.data.test.repositories.type:none") + .run((context) -> assertThat(context) + .doesNotHaveBean(ImperativeRepository.class)); + } + + @Test + public void reactiveRepositoryDoesNotMatchWithNoneConfiguredType() { + this.runner.withUserConfiguration(ReactiveRepository.class) + .withPropertyValues("spring.data.test.repositories.type:none") + .run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveRepository.class)); + } + + @Test + public void failsFastWhenConfiguredTypeIsUnknown() { + this.runner.withUserConfiguration(ReactiveRepository.class) + .withPropertyValues("spring.data.test.repositories.type:abcde") + .run((context) -> assertThat(context).hasFailed()); + } + + @Configuration + @ConditionalOnRepositoryType(store = "test", type = RepositoryType.IMPERATIVE) + protected static class ImperativeRepository { + + } + + @Configuration + @ConditionalOnRepositoryType(store = "test", type = RepositoryType.REACTIVE) + protected static class ReactiveRepository { + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraReactiveRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraReactiveRepositoriesAutoConfigurationTests.java index c8d0100b38..6e87cb2514 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraReactiveRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraReactiveRepositoriesAutoConfigurationTests.java @@ -20,9 +20,9 @@ import java.util.Set; import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Session; -import org.junit.After; import org.junit.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; @@ -30,7 +30,8 @@ import org.springframework.boot.autoconfigure.data.alt.cassandra.ReactiveCityCas import org.springframework.boot.autoconfigure.data.cassandra.city.City; import org.springframework.boot.autoconfigure.data.cassandra.city.ReactiveCityRepository; import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan.Filter; @@ -50,62 +51,72 @@ import static org.mockito.Mockito.mock; * @author EddĂș MelĂ©ndez * @author Stephane Nicoll * @author Mark Paluch + * @author Andy Wilkinson */ public class CassandraReactiveRepositoriesAutoConfigurationTests { - private AnnotationConfigApplicationContext context; - - @After - public void close() { - if (this.context != null) { - this.context.close(); - } - } + private final ApplicationContextRunner runner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(CassandraAutoConfiguration.class, + CassandraRepositoriesAutoConfiguration.class, + CassandraDataAutoConfiguration.class, + CassandraReactiveDataAutoConfiguration.class, + CassandraReactiveRepositoriesAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class)); @Test public void testDefaultRepositoryConfiguration() { - load(TestConfiguration.class); - assertThat(this.context.getBean(ReactiveCityRepository.class)).isNotNull(); - assertThat(this.context.getBean(Cluster.class)).isNotNull(); - assertThat(getInitialEntitySet()).hasSize(1); + this.runner.withUserConfiguration(TestConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(ReactiveCityRepository.class); + assertThat(context).hasSingleBean(Cluster.class); + assertThat(getInitialEntitySet(context)).hasSize(1); + }); } @Test public void testNoRepositoryConfiguration() { - load(TestExcludeConfiguration.class, EmptyConfiguration.class); - assertThat(this.context.getBean(Cluster.class)).isNotNull(); - assertThat(getInitialEntitySet()).hasSize(1).containsOnly(City.class); + this.runner.withUserConfiguration(TestExcludeConfiguration.class, + EmptyConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(Cluster.class); + assertThat(getInitialEntitySet(context)).hasSize(1) + .containsOnly(City.class); + }); } @Test public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { - load(TestExcludeConfiguration.class, CustomizedConfiguration.class); - assertThat(this.context.getBean(ReactiveCityCassandraRepository.class)) - .isNotNull(); - assertThat(getInitialEntitySet()).hasSize(1).containsOnly(City.class); + this.runner.withUserConfiguration(TestExcludeConfiguration.class, + CustomizedConfiguration.class).run((context) -> { + assertThat(context) + .hasSingleBean(ReactiveCityCassandraRepository.class); + assertThat(getInitialEntitySet(context)).hasSize(1) + .containsOnly(City.class); + }); + } + + @Test + public void enablingImperativeRepositoriesDisablesReactiveRepositories() { + this.runner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.data.cassandra.repositories.type=imperative") + .run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveCityRepository.class)); + } + + @Test + public void enablingNoRepositoriesDisablesReactiveRepositories() { + this.runner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.data.cassandra.repositories.type=none") + .run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveCityRepository.class)); } @SuppressWarnings("unchecked") - private Set> getInitialEntitySet() { - CassandraMappingContext mappingContext = this.context + private Set> getInitialEntitySet(ApplicationContext context) { + CassandraMappingContext mappingContext = context .getBean(CassandraMappingContext.class); return (Set>) ReflectionTestUtils.getField(mappingContext, "initialEntitySet"); } - private void load(Class... configurations) { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - ctx.register(configurations); - ctx.register(CassandraAutoConfiguration.class, - CassandraRepositoriesAutoConfiguration.class, - CassandraDataAutoConfiguration.class, - CassandraReactiveDataAutoConfiguration.class, - CassandraReactiveRepositoriesAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - ctx.refresh(); - this.context = ctx; - } - @Configuration @TestAutoConfigurationPackage(City.class) static class TestConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraRepositoriesAutoConfigurationTests.java index 2a844267ad..b666656f43 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraRepositoriesAutoConfigurationTests.java @@ -20,10 +20,9 @@ import java.util.Set; import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Session; -import org.junit.After; -import org.junit.Before; import org.junit.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; @@ -31,7 +30,8 @@ import org.springframework.boot.autoconfigure.data.alt.cassandra.CityCassandraRe import org.springframework.boot.autoconfigure.data.cassandra.city.City; import org.springframework.boot.autoconfigure.data.cassandra.city.CityRepository; import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; @@ -52,57 +52,65 @@ import static org.mockito.Mockito.mock; */ public class CassandraRepositoriesAutoConfigurationTests { - private AnnotationConfigApplicationContext context; - - @Before - public void setUp() { - this.context = new AnnotationConfigApplicationContext(); - } - - @After - public void close() { - this.context.close(); - } + private final ApplicationContextRunner runner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(CassandraAutoConfiguration.class, + CassandraRepositoriesAutoConfiguration.class, + CassandraDataAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class)); @Test public void testDefaultRepositoryConfiguration() { - addConfigurations(TestConfiguration.class); - assertThat(this.context.getBean(CityRepository.class)).isNotNull(); - assertThat(this.context.getBean(Cluster.class)).isNotNull(); - assertThat(getInitialEntitySet()).hasSize(1); + this.runner.withUserConfiguration(TestConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(CityRepository.class); + assertThat(context).hasSingleBean(Cluster.class); + assertThat(getInitialEntitySet(context)).hasSize(1); + }); } @Test public void testNoRepositoryConfiguration() { - addConfigurations(TestExcludeConfiguration.class, EmptyConfiguration.class); - assertThat(this.context.getBean(Cluster.class)).isNotNull(); - assertThat(getInitialEntitySet()).hasSize(1).containsOnly(City.class); + this.runner.withUserConfiguration(TestExcludeConfiguration.class, + EmptyConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(Cluster.class); + assertThat(getInitialEntitySet(context)).hasSize(1) + .containsOnly(City.class); + }); } @Test public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { - addConfigurations(TestExcludeConfiguration.class, CustomizedConfiguration.class); - assertThat(this.context.getBean(CityCassandraRepository.class)).isNotNull(); - assertThat(getInitialEntitySet()).hasSize(1).containsOnly(City.class); + this.runner.withUserConfiguration(TestExcludeConfiguration.class, + CustomizedConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(CityCassandraRepository.class); + assertThat(getInitialEntitySet(context)).hasSize(1) + .containsOnly(City.class); + }); + } + + @Test + public void enablingReactiveRepositoriesDisablesImperativeRepositories() { + this.runner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.data.cassandra.repositories.type=reactive") + .run((context) -> assertThat(context) + .doesNotHaveBean(CityCassandraRepository.class)); + } + + @Test + public void enablingNoRepositoriesDisablesReactiveRepositories() { + this.runner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.data.cassandra.repositories.type=none") + .run((context) -> assertThat(context) + .doesNotHaveBean(CityCassandraRepository.class)); } @SuppressWarnings("unchecked") - private Set> getInitialEntitySet() { - CassandraMappingContext mappingContext = this.context + private Set> getInitialEntitySet(AssertableApplicationContext context) { + CassandraMappingContext mappingContext = context .getBean(CassandraMappingContext.class); return (Set>) ReflectionTestUtils.getField(mappingContext, "initialEntitySet"); } - private void addConfigurations(Class... configurations) { - this.context.register(configurations); - this.context.register(CassandraAutoConfiguration.class, - CassandraRepositoriesAutoConfiguration.class, - CassandraDataAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - this.context.refresh(); - } - @Configuration @TestAutoConfigurationPackage(City.class) static class TestConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveAndBlockingRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveAndImperativeRepositoriesAutoConfigurationTests.java similarity index 92% rename from spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveAndBlockingRepositoriesAutoConfigurationTests.java rename to spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveAndImperativeRepositoriesAutoConfigurationTests.java index 5ae970260f..b1d8867555 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveAndBlockingRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveAndImperativeRepositoriesAutoConfigurationTests.java @@ -45,7 +45,7 @@ import static org.assertj.core.api.Assertions.assertThat; * * @author Stephane Nicoll */ -public class CouchbaseReactiveAndBlockingRepositoriesAutoConfigurationTests { +public class CouchbaseReactiveAndImperativeRepositoriesAutoConfigurationTests { private AnnotationConfigApplicationContext context; @@ -55,12 +55,12 @@ public class CouchbaseReactiveAndBlockingRepositoriesAutoConfigurationTests { } @Test - public void shouldCreateInstancesForReactiveAndBlockingRepositories() + public void shouldCreateInstancesForReactiveAndImperativeRepositories() throws Exception { this.context = new AnnotationConfigApplicationContext(); TestPropertyValues.of("spring.datasource.initialization-mode:never") .applyTo(this.context); - this.context.register(BlockingAndReactiveConfiguration.class, + this.context.register(ImperativeAndReactiveConfiguration.class, BaseConfiguration.class); this.context.refresh(); assertThat(this.context.getBean(CityRepository.class)).isNotNull(); @@ -71,7 +71,7 @@ public class CouchbaseReactiveAndBlockingRepositoriesAutoConfigurationTests { @TestAutoConfigurationPackage(CouchbaseAutoConfigurationTests.class) @EnableCouchbaseRepositories(basePackageClasses = CityRepository.class) @EnableReactiveCouchbaseRepositories(basePackageClasses = ReactiveCityRepository.class) - protected static class BlockingAndReactiveConfiguration { + protected static class ImperativeAndReactiveConfiguration { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesAutoConfigurationTests.java index fe0a4e89ba..25614d51e4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesAutoConfigurationTests.java @@ -65,10 +65,15 @@ public class CouchbaseReactiveRepositoriesAutoConfigurationTests { } @Test - public void disableReactiveRepository() { + public void imperativeRepositories() { load(DefaultConfiguration.class, - "spring.data.couchbase.reactiverepositories.enabled=false", - "spring.data.couchbase.repositories.enabled=false"); + "spring.data.couchbase.repositories.type=imperative"); + assertThat(this.context.getBeansOfType(ReactiveCityRepository.class)).hasSize(0); + } + + @Test + public void disabledRepositories() { + load(DefaultConfiguration.class, "spring.data.couchbase.repositories.type=none"); assertThat(this.context.getBeansOfType(ReactiveCityRepository.class)).hasSize(0); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfigurationTests.java index 0d419baa4a..7745935d72 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfigurationTests.java @@ -63,9 +63,15 @@ public class CouchbaseRepositoriesAutoConfigurationTests { } @Test - public void disableRepository() { + public void reactiveRepositories() { load(DefaultConfiguration.class, - "spring.data.couchbase.repositories.enabled=false"); + "spring.data.couchbase.repositories.type=reactive"); + assertThat(this.context.getBeansOfType(CityRepository.class)).hasSize(0); + } + + @Test + public void disabledRepositories() { + load(DefaultConfiguration.class, "spring.data.couchbase.repositories.type=none"); assertThat(this.context.getBeansOfType(CityRepository.class)).hasSize(0); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MixedMongoRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MixedMongoRepositoriesAutoConfigurationTests.java index 3286fdb088..16105f7068 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MixedMongoRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MixedMongoRepositoriesAutoConfigurationTests.java @@ -106,7 +106,7 @@ public class MixedMongoRepositoriesAutoConfigurationTests { this.context = new AnnotationConfigApplicationContext(); TestPropertyValues .of("spring.datasource.initialization-mode:never", - "spring.data.mongodb.repositories.enabled:false") + "spring.data.mongodb.repositories.type:none") .applyTo(this.context); this.context.register(OverlapConfiguration.class, BaseConfiguration.class); this.context.refresh(); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveRepositoriesAutoConfigurationTests.java index 3a9037ec20..9020202b6a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoReactiveRepositoriesAutoConfigurationTests.java @@ -19,10 +19,9 @@ package org.springframework.boot.autoconfigure.data.mongo; import java.util.Set; import com.mongodb.reactivestreams.client.MongoClient; -import org.junit.After; import org.junit.Test; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.data.alt.mongo.CityMongoDbRepository; @@ -32,7 +31,7 @@ import org.springframework.boot.autoconfigure.data.mongo.city.City; import org.springframework.boot.autoconfigure.data.mongo.city.ReactiveCityRepository; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; import org.springframework.boot.autoconfigure.mongo.MongoReactiveAutoConfiguration; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; @@ -45,61 +44,67 @@ import static org.assertj.core.api.Assertions.assertThat; * Tests for {@link MongoReactiveRepositoriesAutoConfiguration}. * * @author Mark Paluch + * @author Andy Wilkinson */ public class MongoReactiveRepositoriesAutoConfigurationTests { - private AnnotationConfigApplicationContext context; - - @After - public void close() { - if (this.context != null) { - this.context.close(); - } - } + private final ApplicationContextRunner runner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class, + MongoReactiveAutoConfiguration.class, + MongoReactiveDataAutoConfiguration.class, + MongoReactiveRepositoriesAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class)); @Test public void testDefaultRepositoryConfiguration() throws Exception { - prepareApplicationContext(TestConfiguration.class); - assertThat(this.context.getBean(ReactiveCityRepository.class)).isNotNull(); - MongoClient client = this.context.getBean(MongoClient.class); - assertThat(client).isInstanceOf(MongoClient.class); - MongoMappingContext mappingContext = this.context - .getBean(MongoMappingContext.class); - @SuppressWarnings("unchecked") - Set> entities = (Set>) ReflectionTestUtils - .getField(mappingContext, "initialEntitySet"); - assertThat(entities).hasSize(1); + this.runner.withUserConfiguration(TestConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(ReactiveCityRepository.class); + MongoClient client = context.getBean(MongoClient.class); + assertThat(client).isInstanceOf(MongoClient.class); + MongoMappingContext mappingContext = context + .getBean(MongoMappingContext.class); + @SuppressWarnings("unchecked") + Set> entities = (Set>) ReflectionTestUtils + .getField(mappingContext, "initialEntitySet"); + assertThat(entities).hasSize(1); + }); } @Test public void testNoRepositoryConfiguration() throws Exception { - prepareApplicationContext(EmptyConfiguration.class); - MongoClient client = this.context.getBean(MongoClient.class); - assertThat(client).isInstanceOf(MongoClient.class); + this.runner.withUserConfiguration(EmptyConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(MongoClient.class)); } @Test public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { - prepareApplicationContext(CustomizedConfiguration.class); - assertThat(this.context.getBeansOfType(ReactiveCityMongoDbRepository.class)) - .isEmpty(); + this.runner.withUserConfiguration(CustomizedConfiguration.class) + .run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveCityMongoDbRepository.class)); } - @Test(expected = NoSuchBeanDefinitionException.class) + @Test public void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() { - prepareApplicationContext(SortOfInvalidCustomConfiguration.class); - this.context.getBean(ReactiveCityRepository.class); + this.runner.withUserConfiguration(SortOfInvalidCustomConfiguration.class) + .run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveCityRepository.class)); } - private void prepareApplicationContext(Class... configurationClasses) { - this.context = new AnnotationConfigApplicationContext(); - this.context.register(configurationClasses); - this.context.register(MongoAutoConfiguration.class, - MongoDataAutoConfiguration.class, MongoReactiveAutoConfiguration.class, - MongoReactiveDataAutoConfiguration.class, - MongoReactiveRepositoriesAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - this.context.refresh(); + @Test + public void enablingImperativeRepositoriesDisablesReactiveRepositories() { + this.runner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.data.mongodb.repositories.type=imperative") + .run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveCityRepository.class)); + } + + @Test + public void enablingNoRepositoriesDisablesReactiveRepositories() { + this.runner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.data.mongodb.repositories.type=none") + .run((context) -> assertThat(context) + .doesNotHaveBean(ReactiveCityRepository.class)); } @Configuration diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoRepositoriesAutoConfigurationTests.java index fd169b7d79..0449c69d4e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoRepositoriesAutoConfigurationTests.java @@ -20,10 +20,9 @@ import java.util.Set; import com.mongodb.Mongo; import com.mongodb.MongoClient; -import org.junit.After; import org.junit.Test; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.data.alt.mongo.CityMongoDbRepository; @@ -31,7 +30,7 @@ import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; import org.springframework.boot.autoconfigure.data.mongo.city.City; import org.springframework.boot.autoconfigure.data.mongo.city.CityRepository; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.repository.config.EnableMongoRepositories; @@ -47,58 +46,62 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class MongoRepositoriesAutoConfigurationTests { - private AnnotationConfigApplicationContext context; - - @After - public void close() { - this.context.close(); - } + private final ApplicationContextRunner runner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(MongoAutoConfiguration.class, + MongoDataAutoConfiguration.class, + MongoRepositoriesAutoConfiguration.class, + PropertyPlaceholderAutoConfiguration.class)); @Test public void testDefaultRepositoryConfiguration() throws Exception { - prepareApplicationContext(TestConfiguration.class); - - assertThat(this.context.getBean(CityRepository.class)).isNotNull(); - Mongo mongo = this.context.getBean(Mongo.class); - assertThat(mongo).isInstanceOf(MongoClient.class); - MongoMappingContext mappingContext = this.context - .getBean(MongoMappingContext.class); - @SuppressWarnings("unchecked") - Set> entities = (Set>) ReflectionTestUtils - .getField(mappingContext, "initialEntitySet"); - assertThat(entities).hasSize(1); + this.runner.withUserConfiguration(TestConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(CityRepository.class); + Mongo mongo = context.getBean(Mongo.class); + assertThat(mongo).isInstanceOf(MongoClient.class); + MongoMappingContext mappingContext = context + .getBean(MongoMappingContext.class); + @SuppressWarnings("unchecked") + Set> entities = (Set>) ReflectionTestUtils + .getField(mappingContext, "initialEntitySet"); + assertThat(entities).hasSize(1); + }); } @Test public void testNoRepositoryConfiguration() throws Exception { - prepareApplicationContext(EmptyConfiguration.class); - - Mongo mongo = this.context.getBean(Mongo.class); - assertThat(mongo).isInstanceOf(MongoClient.class); + this.runner.withUserConfiguration(EmptyConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(Mongo.class); + assertThat(context.getBean(Mongo.class)).isInstanceOf(MongoClient.class); + }); } @Test public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { - prepareApplicationContext(CustomizedConfiguration.class); - - assertThat(this.context.getBean(CityMongoDbRepository.class)).isNotNull(); + this.runner.withUserConfiguration(CustomizedConfiguration.class) + .run((context) -> assertThat(context) + .hasSingleBean(CityMongoDbRepository.class)); } - @Test(expected = NoSuchBeanDefinitionException.class) + @Test public void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() { - prepareApplicationContext(SortOfInvalidCustomConfiguration.class); - - this.context.getBean(CityRepository.class); + this.runner.withUserConfiguration(SortOfInvalidCustomConfiguration.class).run( + (context) -> assertThat(context).doesNotHaveBean(CityRepository.class)); } - private void prepareApplicationContext(Class... configurationClasses) { - this.context = new AnnotationConfigApplicationContext(); - this.context.register(configurationClasses); - this.context.register(MongoAutoConfiguration.class, - MongoDataAutoConfiguration.class, - MongoRepositoriesAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - this.context.refresh(); + @Test + public void enablingReactiveRepositoriesDisablesImperativeRepositories() { + this.runner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.data.mongodb.repositories.type=reactive") + .run((context) -> assertThat(context) + .doesNotHaveBean(CityRepository.class)); + } + + @Test + public void enablingNoRepositoriesDisablesReactiveRepositories() { + this.runner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.data.mongodb.repositories.type=none") + .run((context) -> assertThat(context) + .doesNotHaveBean(CityRepository.class)); } @Configuration diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc index 89a5610037..c1dbdb7e1d 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/appendix-application-properties.adoc @@ -576,10 +576,9 @@ content into your application. Rather, pick only the properties that you need. spring.data.cassandra.pool.idle-timeout=120 # Idle timeout before an idle connection is removed. If a duration suffix is not specified, seconds will be used. spring.data.cassandra.pool.max-queue-size=256 # Maximum number of requests that get queued if no connection is available. spring.data.cassandra.pool.pool-timeout=5000ms # Pool timeout when trying to acquire a connection from a host's pool. - spring.data.cassandra.reactiverepositories.enabled=true # Whether to enable Cassandra reactive repositories. spring.data.cassandra.read-timeout= # Socket option: read time out. spring.data.cassandra.reconnection-policy= # Reconnection policy class. - spring.data.cassandra.repositories.enabled= # Enable Cassandra repositories. + spring.data.cassandra.repositories.type=auto # Type of Cassandra repositories to enable. spring.data.cassandra.retry-policy= # Class name of the retry policy. spring.data.cassandra.serial-consistency-level= # Queries serial consistency level. spring.data.cassandra.schema-action=none # Schema action to take at startup. @@ -589,8 +588,7 @@ content into your application. Rather, pick only the properties that you need. # DATA COUCHBASE ({sc-spring-boot-autoconfigure}/data/couchbase/CouchbaseDataProperties.{sc-ext}[CouchbaseDataProperties]) spring.data.couchbase.auto-index=false # Automatically create views and indexes. spring.data.couchbase.consistency=read-your-own-writes # Consistency to apply by default on generated queries. - spring.data.couchbase.reactiverepositories.enabled=true # Enable Couchbase reactive repositories. - spring.data.couchbase.repositories.enabled=true # Enable Couchbase repositories. + spring.data.couchbase.repositories.type=auto # Type of Couchbase repositories to enable. # ELASTICSEARCH ({sc-spring-boot-autoconfigure}/data/elasticsearch/ElasticsearchProperties.{sc-ext}[ElasticsearchProperties]) spring.data.elasticsearch.cluster-name=elasticsearch # Elasticsearch cluster name. @@ -609,8 +607,7 @@ content into your application. Rather, pick only the properties that you need. spring.data.mongodb.host=localhost # Mongo server host. Cannot be set with URI. spring.data.mongodb.password= # Login password of the mongo server. Cannot be set with URI. spring.data.mongodb.port=27017 # Mongo server port. Cannot be set with URI. - spring.data.mongodb.reactiverepositories.enabled=true # Whether to enable Mongo reactive repositories. - spring.data.mongodb.repositories.enabled=true # Whether to enable Mongo repositories. + spring.data.mongodb.repositories.type=true # Type of Mongo repositories to enable. spring.data.mongodb.uri=mongodb://localhost/test # Mongo database URI. Cannot be set with host, port and credentials. spring.data.mongodb.username= # Login user of the mongo server. Cannot be set with URI. diff --git a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc index fe8b9c092d..26039db1d7 100644 --- a/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/main/asciidoc/howto.adoc @@ -1902,10 +1902,11 @@ repositories for you. The most explicit way to do that is to use the standard Sp `+@EnableJpaRepositories+` and `+@EnableMongoRepositories+` annotations and provide the location of your `Repository` interfaces. -There are also flags (`+spring.data.*.repositories.enabled+`) that you can use to switch the -auto-configured repositories on and off in external configuration. Doing so is useful, for -instance, in case you want to switch off the Mongo repositories and still use the -auto-configured `MongoTemplate`. +There are also flags (`+spring.data.*.repositories.enabled+` and +`+spring.data.*.repositories.type+`) that you can use to switch the auto-configured +repositories on and off in external configuration. Doing so is useful, for instance, in +case you want to switch off the Mongo repositories and still use the auto-configured +`MongoTemplate`. The same obstacle and the same features exist for other auto-configured Spring Data repository types (Elasticsearch, Solr, and others). To work with them, change the names of the annotations and flags