From 1dbfcf8b5701c588a1d74476852756ece7465fb2 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 10 Dec 2021 14:28:20 +0000 Subject: [PATCH] Reinstate support for Spring Data Couchbase Closes gh-28976 --- .../build.gradle | 2 +- .../spring-boot-actuator/build.gradle | 4 +- .../spring-boot-autoconfigure/build.gradle | 2 +- .../cache/CacheAutoConfiguration.java | 7 +- .../cache/CacheConfigurations.java | 1 + .../boot/autoconfigure/cache/CacheType.java | 7 +- .../cache/CouchbaseCacheConfiguration.java | 71 ++++++++++ ...ouchbaseCacheManagerBuilderCustomizer.java | 39 ++++++ .../CouchbaseClientFactoryConfiguration.java | 45 ++++++ ...seClientFactoryDependentConfiguration.java | 52 +++++++ .../CouchbaseDataAutoConfiguration.java | 63 +++++++++ .../couchbase/CouchbaseDataConfiguration.java | 83 +++++++++++ .../couchbase/CouchbaseDataProperties.java | 97 +++++++++++++ ...ouchbaseReactiveDataAutoConfiguration.java | 42 ++++++ .../CouchbaseReactiveDataConfiguration.java | 52 +++++++ ...ReactiveRepositoriesAutoConfiguration.java | 51 +++++++ ...ouchbaseReactiveRepositoriesRegistrar.java | 55 ++++++++ ...ouchbaseRepositoriesAutoConfiguration.java | 49 +++++++ .../CouchbaseRepositoriesRegistrar.java | 55 ++++++++ .../data/couchbase/package-info.java | 20 +++ .../boot/autoconfigure/domain/EntityScan.java | 6 +- .../main/resources/META-INF/spring.factories | 4 + .../AbstractCacheAutoConfigurationTests.java | 10 +- .../cache/CacheAutoConfigurationTests.java | 85 +++++++++++- .../couchbase/CityCouchbaseRepository.java | 24 ++++ .../ReactiveCityCouchbaseRepository.java | 24 ++++ .../CouchbaseDataAutoConfigurationTests.java | 130 ++++++++++++++++++ .../CouchbaseDataPropertiesTests.java | 37 +++++ .../couchbase/CouchbaseMockConfiguration.java | 38 +++++ ...iveRepositoriesAutoConfigurationTests.java | 85 ++++++++++++ ...aseReactiveDataAutoConfigurationTests.java | 114 +++++++++++++++ ...iveRepositoriesAutoConfigurationTests.java | 108 +++++++++++++++ ...aseRepositoriesAutoConfigurationTests.java | 96 +++++++++++++ .../data/couchbase/city/City.java | 32 +++++ .../data/couchbase/city/CityRepository.java | 23 ++++ .../city/ReactiveCityRepository.java | 29 ++++ .../spring-boot-dependencies/build.gradle | 2 + .../spring-boot-docs/build.gradle | 2 + .../docs/asciidoc/anchor-rewrite.properties | 4 + .../src/docs/asciidoc/attributes.adoc | 2 + .../src/docs/asciidoc/data/nosql.adoc | 44 +++++- .../src/docs/asciidoc/io/caching.adoc | 26 ++++ .../repositories/CouchbaseProperties.java | 21 +++ .../nosql/couchbase/repositories/MyBean.java | 37 +++++ .../couchbase/repositories/MyConverter.java | 28 ++++ .../MyCouchbaseConfiguration.java | 34 +++++ .../MyCouchbaseCacheManagerConfiguration.java | 41 ++++++ .../build.gradle | 12 ++ .../build.gradle | 10 ++ .../spring-boot-smoke-test-cache/build.gradle | 3 + .../build.gradle | 12 ++ .../couchbase/SampleCouchbaseApplication.java | 51 +++++++ .../java/smoketest/data/couchbase/User.java | 65 +++++++++ .../data/couchbase/UserRepository.java | 23 ++++ .../src/main/resources/application.properties | 8 ++ .../SampleCouchbaseApplicationTests.java | 59 ++++++++ 56 files changed, 2113 insertions(+), 13 deletions(-) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CouchbaseCacheConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CouchbaseCacheManagerBuilderCustomizer.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseClientFactoryConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseClientFactoryDependentConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataProperties.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveDataAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveDataConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesRegistrar.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesRegistrar.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/package-info.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/couchbase/CityCouchbaseRepository.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/couchbase/ReactiveCityCouchbaseRepository.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataPropertiesTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseMockConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveAndImperativeRepositoriesAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveDataAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/City.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/CityRepository.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/ReactiveCityRepository.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/CouchbaseProperties.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyBean.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyConverter.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyCouchbaseConfiguration.java create mode 100644 spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/caching/provider/couchbase/MyCouchbaseCacheManagerConfiguration.java create mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase-reactive/build.gradle create mode 100644 spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase/build.gradle create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/build.gradle create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/SampleCouchbaseApplication.java create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/User.java create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/UserRepository.java create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/resources/application.properties create mode 100644 spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/test/java/smoketest/data/couchbase/SampleCouchbaseApplicationTests.java diff --git a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle index 33e1749c2d..92df6ee4cb 100644 --- a/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-actuator-autoconfigure/build.gradle @@ -36,7 +36,6 @@ dependencies { implementation("com.fasterxml.jackson.datatype:jackson-datatype-jsr310") optional("ch.qos.logback:logback-classic") - optional("com.couchbase.client:java-client") optional("com.datastax.oss:java-driver-core") { exclude group: "org.slf4j", module: "jcl-over-slf4j" } @@ -120,6 +119,7 @@ dependencies { optional("org.springframework.data:spring-data-cassandra") { exclude group: "org.slf4j", module: "jcl-over-slf4j" } + optional("org.springframework.data:spring-data-couchbase") optional("org.springframework.data:spring-data-jpa") optional("org.springframework.data:spring-data-ldap") optional("org.springframework.data:spring-data-mongodb") diff --git a/spring-boot-project/spring-boot-actuator/build.gradle b/spring-boot-project/spring-boot-actuator/build.gradle index a9064cd715..acc766b934 100644 --- a/spring-boot-project/spring-boot-actuator/build.gradle +++ b/spring-boot-project/spring-boot-actuator/build.gradle @@ -11,7 +11,6 @@ description = "Spring Boot Actuator" dependencies { api(project(":spring-boot-project:spring-boot")) - optional("com.couchbase.client:java-client") optional("com.datastax.oss:java-driver-core") { exclude group: "org.slf4j", module: "jcl-over-slf4j" } @@ -70,7 +69,8 @@ dependencies { optional("org.springframework.data:spring-data-cassandra") { exclude group: "org.slf4j", module: "jcl-over-slf4j" } - optional("org.springframework.data:spring-data-elasticsearch") { + optional("org.springframework.data:spring-data-couchbase") + optional("org.springframework.data:spring-data-elasticsearch") { exclude(group: "commons-logging", module: "commons-logging") } optional("org.springframework.data:spring-data-ldap") diff --git a/spring-boot-project/spring-boot-autoconfigure/build.gradle b/spring-boot-project/spring-boot-autoconfigure/build.gradle index 2c722baac3..4b30d89cd3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-autoconfigure/build.gradle @@ -12,7 +12,6 @@ description = "Spring Boot AutoConfigure" dependencies { api(project(":spring-boot-project:spring-boot")) - optional("com.couchbase.client:java-client") optional("com.fasterxml.jackson.core:jackson-databind") optional("com.fasterxml.jackson.dataformat:jackson-dataformat-cbor") optional("com.fasterxml.jackson.dataformat:jackson-dataformat-xml") @@ -117,6 +116,7 @@ dependencies { optional("org.springframework:spring-webflux") optional("org.springframework:spring-webmvc") optional("org.springframework.batch:spring-batch-core") + optional("org.springframework.data:spring-data-couchbase") optional("org.springframework.data:spring-data-envers") { exclude group: "javax.activation", module: "javax.activation-api" exclude group: "javax.persistence", module: "javax.persistence-api" diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java index ecf3794fe5..36093f449c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2020 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. @@ -27,6 +27,7 @@ import org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration.Cache 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.couchbase.CouchbaseDataAutoConfiguration; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.autoconfigure.hazelcast.HazelcastAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryDependsOnPostProcessor; @@ -60,8 +61,8 @@ import org.springframework.util.Assert; @ConditionalOnBean(CacheAspectSupport.class) @ConditionalOnMissingBean(value = CacheManager.class, name = "cacheResolver") @EnableConfigurationProperties(CacheProperties.class) -@AutoConfigureAfter({ HazelcastAutoConfiguration.class, HibernateJpaAutoConfiguration.class, - RedisAutoConfiguration.class }) +@AutoConfigureAfter({ CouchbaseDataAutoConfiguration.class, HazelcastAutoConfiguration.class, + HibernateJpaAutoConfiguration.class, RedisAutoConfiguration.class }) @Import({ CacheConfigurationImportSelector.class, CacheManagerEntityManagerFactoryDependsOnPostProcessor.class }) public class CacheAutoConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheConfigurations.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheConfigurations.java index 88cae7ab7e..779b4879ba 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheConfigurations.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheConfigurations.java @@ -38,6 +38,7 @@ final class CacheConfigurations { mappings.put(CacheType.GENERIC, GenericCacheConfiguration.class.getName()); mappings.put(CacheType.HAZELCAST, HazelcastCacheConfiguration.class.getName()); mappings.put(CacheType.JCACHE, JCacheCacheConfiguration.class.getName()); + mappings.put(CacheType.COUCHBASE, CouchbaseCacheConfiguration.class.getName()); mappings.put(CacheType.REDIS, RedisCacheConfiguration.class.getName()); mappings.put(CacheType.CAFFEINE, CaffeineCacheConfiguration.class.getName()); mappings.put(CacheType.SIMPLE, SimpleCacheConfiguration.class.getName()); diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheType.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheType.java index 2f4dac8f35..6b4f899cdf 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheType.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CacheType.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2019 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. @@ -41,6 +41,11 @@ public enum CacheType { */ HAZELCAST, + /** + * Couchbase backed caching. + */ + COUCHBASE, + /** * Redis backed caching. */ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CouchbaseCacheConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CouchbaseCacheConfiguration.java new file mode 100644 index 0000000000..a4ba5952d7 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CouchbaseCacheConfiguration.java @@ -0,0 +1,71 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.cache; + +import java.util.LinkedHashSet; +import java.util.List; + +import com.couchbase.client.java.Cluster; + +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.cache.CacheProperties.Couchbase; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.cache.CacheManager; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Conditional; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.CouchbaseClientFactory; +import org.springframework.data.couchbase.cache.CouchbaseCacheManager; +import org.springframework.data.couchbase.cache.CouchbaseCacheManager.CouchbaseCacheManagerBuilder; +import org.springframework.util.ObjectUtils; + +/** + * Couchbase cache configuration. + * + * @author Stephane Nicoll + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({ Cluster.class, CouchbaseClientFactory.class, CouchbaseCacheManager.class }) +@ConditionalOnMissingBean(CacheManager.class) +@ConditionalOnSingleCandidate(CouchbaseClientFactory.class) +@Conditional(CacheCondition.class) +class CouchbaseCacheConfiguration { + + @Bean + CouchbaseCacheManager cacheManager(CacheProperties cacheProperties, CacheManagerCustomizers customizers, + ObjectProvider couchbaseCacheManagerBuilderCustomizers, + CouchbaseClientFactory clientFactory) { + List cacheNames = cacheProperties.getCacheNames(); + CouchbaseCacheManagerBuilder builder = CouchbaseCacheManager.builder(clientFactory); + Couchbase couchbase = cacheProperties.getCouchbase(); + org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration config = org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration + .defaultCacheConfig(); + if (couchbase.getExpiration() != null) { + config = config.entryExpiry(couchbase.getExpiration()); + } + builder.cacheDefaults(config); + if (!ObjectUtils.isEmpty(cacheNames)) { + builder.initialCacheNames(new LinkedHashSet<>(cacheNames)); + } + couchbaseCacheManagerBuilderCustomizers.orderedStream().forEach((customizer) -> customizer.customize(builder)); + CouchbaseCacheManager cacheManager = builder.build(); + return customizers.customize(cacheManager); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CouchbaseCacheManagerBuilderCustomizer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CouchbaseCacheManagerBuilderCustomizer.java new file mode 100644 index 0000000000..af2d248390 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache/CouchbaseCacheManagerBuilderCustomizer.java @@ -0,0 +1,39 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.cache; + +import org.springframework.data.couchbase.cache.CouchbaseCacheManager; +import org.springframework.data.couchbase.cache.CouchbaseCacheManager.CouchbaseCacheManagerBuilder; + +/** + * Callback interface that can be implemented by beans wishing to customize the + * {@link CouchbaseCacheManagerBuilder} before it is used to build the auto-configured + * {@link CouchbaseCacheManager}. + * + * @author Stephane Nicoll + * @since 2.3.3 + */ +@FunctionalInterface +public interface CouchbaseCacheManagerBuilderCustomizer { + + /** + * Customize the {@link CouchbaseCacheManagerBuilder}. + * @param builder the builder to customize + */ + void customize(CouchbaseCacheManagerBuilder builder); + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseClientFactoryConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseClientFactoryConfiguration.java new file mode 100644 index 0000000000..f6b7aceb8b --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseClientFactoryConfiguration.java @@ -0,0 +1,45 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.couchbase; + +import com.couchbase.client.java.Cluster; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.CouchbaseClientFactory; +import org.springframework.data.couchbase.SimpleCouchbaseClientFactory; + +/** + * Configuration for a {@link CouchbaseClientFactory}. + * + * @author Stephane Nicoll + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnSingleCandidate(Cluster.class) +@ConditionalOnProperty("spring.data.couchbase.bucket-name") +class CouchbaseClientFactoryConfiguration { + + @Bean + @ConditionalOnMissingBean + CouchbaseClientFactory couchbaseClientFactory(Cluster cluster, CouchbaseDataProperties properties) { + return new SimpleCouchbaseClientFactory(cluster, properties.getBucketName(), properties.getScopeName()); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseClientFactoryDependentConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseClientFactoryDependentConfiguration.java new file mode 100644 index 0000000000..a886437946 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseClientFactoryDependentConfiguration.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.couchbase; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.CouchbaseClientFactory; +import org.springframework.data.couchbase.config.BeanNames; +import org.springframework.data.couchbase.core.CouchbaseTemplate; +import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter; +import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping; + +/** + * Configuration for Couchbase-related beans that depend on a + * {@link CouchbaseClientFactory}. + * + * @author Stephane Nicoll + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnSingleCandidate(CouchbaseClientFactory.class) +class CouchbaseClientFactoryDependentConfiguration { + + @Bean(name = BeanNames.COUCHBASE_TEMPLATE) + @ConditionalOnMissingBean(name = BeanNames.COUCHBASE_TEMPLATE) + CouchbaseTemplate couchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory, + MappingCouchbaseConverter mappingCouchbaseConverter) { + return new CouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter); + } + + @Bean(name = BeanNames.COUCHBASE_OPERATIONS_MAPPING) + @ConditionalOnMissingBean(name = BeanNames.COUCHBASE_OPERATIONS_MAPPING) + RepositoryOperationsMapping couchbaseRepositoryOperationsMapping(CouchbaseTemplate couchbaseTemplate) { + return new RepositoryOperationsMapping(couchbaseTemplate); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfiguration.java new file mode 100644 index 0000000000..1f55f2a54c --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfiguration.java @@ -0,0 +1,63 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.couchbase; + +import jakarta.validation.Validator; + +import com.couchbase.client.java.Bucket; + +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.ConditionalOnSingleCandidate; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; +import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener; +import org.springframework.data.couchbase.repository.CouchbaseRepository; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Couchbase support. + * + * @author Eddú Meléndez + * @author Stephane Nicoll + * @since 1.4.0 + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({ Bucket.class, CouchbaseRepository.class }) +@AutoConfigureAfter({ CouchbaseAutoConfiguration.class, ValidationAutoConfiguration.class }) +@EnableConfigurationProperties(CouchbaseDataProperties.class) +@Import({ CouchbaseDataConfiguration.class, CouchbaseClientFactoryConfiguration.class, + CouchbaseClientFactoryDependentConfiguration.class }) +public class CouchbaseDataAutoConfiguration { + + @Configuration(proxyBeanMethods = false) + @ConditionalOnClass(Validator.class) + public static class ValidationConfiguration { + + @Bean + @ConditionalOnSingleCandidate(Validator.class) + public ValidatingCouchbaseEventListener validationEventListener(Validator validator) { + return new ValidatingCouchbaseEventListener(validator); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataConfiguration.java new file mode 100644 index 0000000000..52b7220bcf --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataConfiguration.java @@ -0,0 +1,83 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.couchbase; + +import java.util.Collections; + +import org.springframework.beans.BeanUtils; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.domain.EntityScanner; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.config.BeanNames; +import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions; +import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter; +import org.springframework.data.couchbase.core.convert.translation.JacksonTranslationService; +import org.springframework.data.couchbase.core.convert.translation.TranslationService; +import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext; +import org.springframework.data.couchbase.core.mapping.Document; +import org.springframework.data.mapping.model.FieldNamingStrategy; + +/** + * Configuration for Spring Data's couchbase support. + * + * @author Stephane Nicoll + */ +@Configuration(proxyBeanMethods = false) +class CouchbaseDataConfiguration { + + @Bean + @ConditionalOnMissingBean + MappingCouchbaseConverter couchbaseMappingConverter(CouchbaseDataProperties properties, + CouchbaseMappingContext couchbaseMappingContext, CouchbaseCustomConversions couchbaseCustomConversions) { + MappingCouchbaseConverter converter = new MappingCouchbaseConverter(couchbaseMappingContext, + properties.getTypeKey()); + converter.setCustomConversions(couchbaseCustomConversions); + return converter; + } + + @Bean + @ConditionalOnMissingBean + TranslationService couchbaseTranslationService() { + return new JacksonTranslationService(); + } + + @Bean(name = BeanNames.COUCHBASE_MAPPING_CONTEXT) + @ConditionalOnMissingBean(name = BeanNames.COUCHBASE_MAPPING_CONTEXT) + CouchbaseMappingContext couchbaseMappingContext(CouchbaseDataProperties properties, + ApplicationContext applicationContext, CouchbaseCustomConversions couchbaseCustomConversions) + throws Exception { + CouchbaseMappingContext mappingContext = new CouchbaseMappingContext(); + mappingContext.setInitialEntitySet(new EntityScanner(applicationContext).scan(Document.class)); + mappingContext.setSimpleTypeHolder(couchbaseCustomConversions.getSimpleTypeHolder()); + Class fieldNamingStrategy = properties.getFieldNamingStrategy(); + if (fieldNamingStrategy != null) { + mappingContext + .setFieldNamingStrategy((FieldNamingStrategy) BeanUtils.instantiateClass(fieldNamingStrategy)); + } + mappingContext.setAutoIndexCreation(properties.isAutoIndex()); + return mappingContext; + } + + @Bean(name = BeanNames.COUCHBASE_CUSTOM_CONVERSIONS) + @ConditionalOnMissingBean(name = BeanNames.COUCHBASE_CUSTOM_CONVERSIONS) + CouchbaseCustomConversions couchbaseCustomConversions() { + return new CouchbaseCustomConversions(Collections.emptyList()); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataProperties.java new file mode 100644 index 0000000000..1230e41af7 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataProperties.java @@ -0,0 +1,97 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.couchbase; + +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * Configuration properties for Spring Data Couchbase. + * + * @author Stephane Nicoll + * @since 1.4.0 + */ +@ConfigurationProperties(prefix = "spring.data.couchbase") +public class CouchbaseDataProperties { + + /** + * Automatically create views and indexes. Use the meta-data provided by + * "@ViewIndexed", "@N1qlPrimaryIndexed" and "@N1qlSecondaryIndexed". + */ + private boolean autoIndex; + + /** + * Name of the bucket to connect to. + */ + private String bucketName; + + /** + * Name of the scope used for all collection access. + */ + private String scopeName; + + /** + * Fully qualified name of the FieldNamingStrategy to use. + */ + private Class fieldNamingStrategy; + + /** + * Name of the field that stores the type information for complex types when using + * "MappingCouchbaseConverter". + */ + private String typeKey = "_class"; + + public boolean isAutoIndex() { + return this.autoIndex; + } + + public void setAutoIndex(boolean autoIndex) { + this.autoIndex = autoIndex; + } + + public String getBucketName() { + return this.bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } + + public String getScopeName() { + return this.scopeName; + } + + public void setScopeName(String scopeName) { + this.scopeName = scopeName; + } + + public Class getFieldNamingStrategy() { + return this.fieldNamingStrategy; + } + + public void setFieldNamingStrategy(Class fieldNamingStrategy) { + this.fieldNamingStrategy = fieldNamingStrategy; + } + + public String getTypeKey() { + return this.typeKey; + } + + public void setTypeKey(String typeKey) { + this.typeKey = typeKey; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveDataAutoConfiguration.java new file mode 100644 index 0000000000..104a941964 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveDataAutoConfiguration.java @@ -0,0 +1,42 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.couchbase; + +import com.couchbase.client.java.Cluster; +import reactor.core.publisher.Flux; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.couchbase.repository.ReactiveCouchbaseRepository; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Reactive Couchbase + * support. + * + * @author Alex Derkach + * @since 2.0.0 + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({ Cluster.class, ReactiveCouchbaseRepository.class, Flux.class }) +@AutoConfigureAfter(CouchbaseDataAutoConfiguration.class) +@Import(CouchbaseReactiveDataConfiguration.class) +public class CouchbaseReactiveDataAutoConfiguration { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveDataConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveDataConfiguration.java new file mode 100644 index 0000000000..8450cef5f3 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveDataConfiguration.java @@ -0,0 +1,52 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.couchbase; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.CouchbaseClientFactory; +import org.springframework.data.couchbase.config.BeanNames; +import org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate; +import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter; +import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping; + +/** + * Configuration for Spring Data's couchbase reactive support. + * + * @author Stephane Nicoll + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnSingleCandidate(CouchbaseClientFactory.class) +class CouchbaseReactiveDataConfiguration { + + @Bean(name = BeanNames.REACTIVE_COUCHBASE_TEMPLATE) + @ConditionalOnMissingBean(name = BeanNames.REACTIVE_COUCHBASE_TEMPLATE) + ReactiveCouchbaseTemplate reactiveCouchbaseTemplate(CouchbaseClientFactory couchbaseClientFactory, + MappingCouchbaseConverter mappingCouchbaseConverter) { + return new ReactiveCouchbaseTemplate(couchbaseClientFactory, mappingCouchbaseConverter); + } + + @Bean(name = BeanNames.REACTIVE_COUCHBASE_OPERATIONS_MAPPING) + @ConditionalOnMissingBean(name = BeanNames.REACTIVE_COUCHBASE_OPERATIONS_MAPPING) + ReactiveRepositoryOperationsMapping reactiveCouchbaseRepositoryOperationsMapping( + ReactiveCouchbaseTemplate reactiveCouchbaseTemplate) { + return new ReactiveRepositoryOperationsMapping(reactiveCouchbaseTemplate); + } + +} 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 new file mode 100644 index 0000000000..c120b9b6b8 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesAutoConfiguration.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.couchbase; + +import com.couchbase.client.java.Cluster; +import reactor.core.publisher.Flux; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +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.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; +import org.springframework.data.couchbase.repository.config.ReactiveRepositoryOperationsMapping; +import org.springframework.data.couchbase.repository.support.ReactiveCouchbaseRepositoryFactoryBean; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Couchbase Reactive + * Repositories. + * + * @author Alex Derkach + * @since 2.0.0 + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({ Cluster.class, ReactiveCouchbaseRepository.class, Flux.class }) +@ConditionalOnRepositoryType(store = "couchbase", type = RepositoryType.REACTIVE) +@ConditionalOnBean(ReactiveRepositoryOperationsMapping.class) +@ConditionalOnMissingBean(ReactiveCouchbaseRepositoryFactoryBean.class) +@Import(CouchbaseReactiveRepositoriesRegistrar.class) +@AutoConfigureAfter(CouchbaseReactiveDataAutoConfiguration.class) +public class CouchbaseReactiveRepositoriesAutoConfiguration { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesRegistrar.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesRegistrar.java new file mode 100644 index 0000000000..ae31598905 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesRegistrar.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2019 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 + * + * https://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.couchbase; + +import java.lang.annotation.Annotation; + +import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.data.couchbase.repository.config.EnableReactiveCouchbaseRepositories; +import org.springframework.data.couchbase.repository.config.ReactiveCouchbaseRepositoryConfigurationExtension; +import org.springframework.data.repository.config.RepositoryConfigurationExtension; + +/** + * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Couchbase + * Reactive Repositories. + * + * @author Alex Derkach + */ +class CouchbaseReactiveRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport { + + @Override + protected Class getAnnotation() { + return EnableReactiveCouchbaseRepositories.class; + } + + @Override + protected Class getConfiguration() { + return EnableReactiveCouchbaseRepositoriesConfiguration.class; + } + + @Override + protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() { + return new ReactiveCouchbaseRepositoryConfigurationExtension(); + } + + @EnableReactiveCouchbaseRepositories + private static class EnableReactiveCouchbaseRepositoriesConfiguration { + + } + +} 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 new file mode 100644 index 0000000000..536a23b580 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfiguration.java @@ -0,0 +1,49 @@ +/* + * Copyright 2012-2019 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 + * + * https://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.couchbase; + +import com.couchbase.client.java.Bucket; + +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.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; +import org.springframework.data.couchbase.repository.config.RepositoryOperationsMapping; +import org.springframework.data.couchbase.repository.support.CouchbaseRepositoryFactoryBean; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Couchbase + * Repositories. + * + * @author Eddú Meléndez + * @author Stephane Nicoll + * @since 1.4.0 + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({ Bucket.class, CouchbaseRepository.class }) +@ConditionalOnBean(RepositoryOperationsMapping.class) +@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/couchbase/CouchbaseRepositoriesRegistrar.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesRegistrar.java new file mode 100644 index 0000000000..2264682c0b --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesRegistrar.java @@ -0,0 +1,55 @@ +/* + * Copyright 2012-2019 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 + * + * https://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.couchbase; + +import java.lang.annotation.Annotation; + +import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.data.couchbase.repository.config.CouchbaseRepositoryConfigurationExtension; +import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories; +import org.springframework.data.repository.config.RepositoryConfigurationExtension; + +/** + * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Couchbase + * Repositories. + * + * @author Eddú Meléndez + */ +class CouchbaseRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport { + + @Override + protected Class getAnnotation() { + return EnableCouchbaseRepositories.class; + } + + @Override + protected Class getConfiguration() { + return EnableCouchbaseRepositoriesConfiguration.class; + } + + @Override + protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() { + return new CouchbaseRepositoryConfigurationExtension(); + } + + @EnableCouchbaseRepositories + private static class EnableCouchbaseRepositoriesConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/package-info.java new file mode 100644 index 0000000000..5f4e192d47 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/package-info.java @@ -0,0 +1,20 @@ +/* + * Copyright 2012-2019 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 + * + * https://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. + */ + +/** + * Auto-configuration for Spring Data Couchbase. + */ +package org.springframework.boot.autoconfigure.data.couchbase; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScan.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScan.java index ebc741bb6d..bfe47ff9a8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScan.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScan.java @@ -38,9 +38,11 @@ import org.springframework.core.annotation.AliasFor; * {@link org.springframework.data.mapping.context.AbstractMappingContext#setInitialEntitySet(java.util.Set) * initial entity set} used with Spring Data * {@link org.springframework.data.mongodb.core.mapping.MongoMappingContext MongoDB}, - * {@link org.springframework.data.neo4j.core.mapping.Neo4jMappingContext Neo4j} and + * {@link org.springframework.data.neo4j.core.mapping.Neo4jMappingContext Neo4j}, * {@link org.springframework.data.cassandra.core.mapping.CassandraMappingContext - * Cassandra} mapping contexts. + * Cassandra} and + * {@link org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext + * Couchbase} mapping contexts. * *

* One of {@link #basePackageClasses()}, {@link #basePackages()} or its alias diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 9bd2faba0d..98b6ba194e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -39,6 +39,10 @@ org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfigura org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraReactiveRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.cassandra.CassandraRepositoriesAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.couchbase.CouchbaseDataAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveDataAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.couchbase.CouchbaseReactiveRepositoriesAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.couchbase.CouchbaseRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/AbstractCacheAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/AbstractCacheAutoConfigurationTests.java index 2ccb2d8785..1bea14f872 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/AbstractCacheAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/AbstractCacheAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2020 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. @@ -33,6 +33,7 @@ import org.springframework.cache.concurrent.ConcurrentMapCacheManager; import org.springframework.cache.support.SimpleCacheManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.cache.CouchbaseCacheManager; import org.springframework.data.redis.cache.RedisCacheManager; import static org.assertj.core.api.Assertions.assertThat; @@ -97,6 +98,13 @@ abstract class AbstractCacheAutoConfigurationTests { }; } + @Bean + CacheManagerCustomizer couchbaseCacheManagerCustomizer() { + return new CacheManagerTestCustomizer() { + + }; + } + @Bean CacheManagerCustomizer redisCacheManagerCustomizer() { return new CacheManagerTestCustomizer<>() { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java index f5b56b4a8f..49c9bac3e4 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/cache/CacheAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2021 the original author or authors. + * Copyright 2012-2020 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. @@ -59,6 +59,10 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; +import org.springframework.data.couchbase.CouchbaseClientFactory; +import org.springframework.data.couchbase.cache.CouchbaseCache; +import org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration; +import org.springframework.data.couchbase.cache.CouchbaseCacheManager; import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; @@ -185,6 +189,64 @@ class CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests { }); } + @Test + void couchbaseCacheExplicit() { + this.contextRunner.withUserConfiguration(CouchbaseConfiguration.class) + .withPropertyValues("spring.cache.type=couchbase").run((context) -> { + CouchbaseCacheManager cacheManager = getCacheManager(context, CouchbaseCacheManager.class); + assertThat(cacheManager.getCacheNames()).isEmpty(); + }); + } + + @Test + void couchbaseCacheWithCustomizers() { + this.contextRunner.withUserConfiguration(CouchbaseWithCustomizersConfiguration.class) + .withPropertyValues("spring.cache.type=couchbase") + .run(verifyCustomizers("allCacheManagerCustomizer", "couchbaseCacheManagerCustomizer")); + } + + @Test + void couchbaseCacheExplicitWithCaches() { + this.contextRunner.withUserConfiguration(CouchbaseConfiguration.class) + .withPropertyValues("spring.cache.type=couchbase", "spring.cache.cacheNames[0]=foo", + "spring.cache.cacheNames[1]=bar") + .run((context) -> { + CouchbaseCacheManager cacheManager = getCacheManager(context, CouchbaseCacheManager.class); + assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar"); + Cache cache = cacheManager.getCache("foo"); + assertThat(cache).isInstanceOf(CouchbaseCache.class); + assertThat(((CouchbaseCache) cache).getCacheConfiguration().getExpiry()).hasSeconds(0); + }); + } + + @Test + void couchbaseCacheExplicitWithTtl() { + this.contextRunner.withUserConfiguration(CouchbaseConfiguration.class) + .withPropertyValues("spring.cache.type=couchbase", "spring.cache.cacheNames=foo,bar", + "spring.cache.couchbase.expiration=2000") + .run((context) -> { + CouchbaseCacheManager cacheManager = getCacheManager(context, CouchbaseCacheManager.class); + assertThat(cacheManager.getCacheNames()).containsOnly("foo", "bar"); + Cache cache = cacheManager.getCache("foo"); + assertThat(cache).isInstanceOf(CouchbaseCache.class); + assertThat(((CouchbaseCache) cache).getCacheConfiguration().getExpiry()).hasSeconds(2); + }); + } + + @Test + void couchbaseCacheWithCouchbaseCacheManagerBuilderCustomizer() { + this.contextRunner.withUserConfiguration(CouchbaseConfiguration.class) + .withPropertyValues("spring.cache.type=couchbase", "spring.cache.couchbase.expiration=15s") + .withBean(CouchbaseCacheManagerBuilderCustomizer.class, () -> (builder) -> builder.cacheDefaults( + CouchbaseCacheConfiguration.defaultCacheConfig().entryExpiry(java.time.Duration.ofSeconds(10)))) + .run((context) -> { + CouchbaseCacheManager cacheManager = getCacheManager(context, CouchbaseCacheManager.class); + CouchbaseCacheConfiguration couchbaseCacheConfiguration = getDefaultCouchbaseCacheConfiguration( + cacheManager); + assertThat(couchbaseCacheConfiguration.getExpiry()).isEqualTo(java.time.Duration.ofSeconds(10)); + }); + } + @Test void redisCacheExplicit() { this.contextRunner.withUserConfiguration(RedisConfiguration.class) @@ -550,6 +612,10 @@ class CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests { assertThat(((CaffeineCache) foo).getNativeCache().stats().missCount()).isEqualTo(1L); } + private CouchbaseCacheConfiguration getDefaultCouchbaseCacheConfiguration(CouchbaseCacheManager cacheManager) { + return (CouchbaseCacheConfiguration) ReflectionTestUtils.getField(cacheManager, "defaultCacheConfig"); + } + private RedisCacheConfiguration getDefaultRedisCacheConfiguration(RedisCacheManager cacheManager) { return (RedisCacheConfiguration) ReflectionTestUtils.getField(cacheManager, "defaultCacheConfig"); } @@ -601,6 +667,23 @@ class CacheAutoConfigurationTests extends AbstractCacheAutoConfigurationTests { } + @Configuration(proxyBeanMethods = false) + @EnableCaching + static class CouchbaseConfiguration { + + @Bean + CouchbaseClientFactory couchbaseClientFactory() { + return mock(CouchbaseClientFactory.class); + } + + } + + @Configuration(proxyBeanMethods = false) + @Import({ CouchbaseConfiguration.class, CacheManagerCustomizersConfiguration.class }) + static class CouchbaseWithCustomizersConfiguration { + + } + @Configuration(proxyBeanMethods = false) @EnableCaching static class RedisConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/couchbase/CityCouchbaseRepository.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/couchbase/CityCouchbaseRepository.java new file mode 100644 index 0000000000..94b51988cb --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/couchbase/CityCouchbaseRepository.java @@ -0,0 +1,24 @@ +/* + * Copyright 2012-2019 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 + * + * https://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.alt.couchbase; + +import org.springframework.boot.autoconfigure.data.couchbase.city.City; +import org.springframework.data.repository.Repository; + +public interface CityCouchbaseRepository extends Repository { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/couchbase/ReactiveCityCouchbaseRepository.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/couchbase/ReactiveCityCouchbaseRepository.java new file mode 100644 index 0000000000..62c9296c86 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/alt/couchbase/ReactiveCityCouchbaseRepository.java @@ -0,0 +1,24 @@ +/* + * Copyright 2012-2019 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 + * + * https://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.alt.couchbase; + +import org.springframework.boot.autoconfigure.data.couchbase.city.City; +import org.springframework.data.repository.reactive.ReactiveCrudRepository; + +public interface ReactiveCityCouchbaseRepository extends ReactiveCrudRepository { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java new file mode 100644 index 0000000000..6cb4e0698f --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java @@ -0,0 +1,130 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.couchbase; + +import java.util.Collections; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties; +import org.springframework.boot.autoconfigure.data.couchbase.city.City; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.couchbase.config.BeanNames; +import org.springframework.data.couchbase.core.CouchbaseTemplate; +import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions; +import org.springframework.data.couchbase.core.convert.DefaultCouchbaseTypeMapper; +import org.springframework.data.couchbase.core.convert.MappingCouchbaseConverter; +import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext; +import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener; +import org.springframework.test.util.ReflectionTestUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link CouchbaseDataAutoConfiguration}. + * + * @author Stephane Nicoll + */ +class CouchbaseDataAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(ValidationAutoConfiguration.class, + CouchbaseAutoConfiguration.class, CouchbaseDataAutoConfiguration.class)); + + @Test + void disabledIfCouchbaseIsNotConfigured() { + this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(CouchbaseTemplate.class)); + } + + @Test + void validatorIsPresent() { + this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ValidatingCouchbaseEventListener.class)); + } + + @Test + @SuppressWarnings("unchecked") + void entityScanShouldSetInitialEntitySet() { + this.contextRunner.withUserConfiguration(EntityScanConfig.class).run((context) -> { + CouchbaseMappingContext mappingContext = context.getBean(CouchbaseMappingContext.class); + Set> initialEntitySet = (Set>) ReflectionTestUtils.getField(mappingContext, + "initialEntitySet"); + assertThat(initialEntitySet).containsOnly(City.class); + }); + } + + @Test + void typeKeyDefault() { + this.contextRunner.withUserConfiguration(CouchbaseMockConfiguration.class) + .run((context) -> assertThat(context.getBean(MappingCouchbaseConverter.class).getTypeKey()) + .isEqualTo(DefaultCouchbaseTypeMapper.DEFAULT_TYPE_KEY)); + } + + @Test + void typeKeyCanBeCustomized() { + this.contextRunner.withUserConfiguration(CouchbaseMockConfiguration.class) + .withPropertyValues("spring.data.couchbase.type-key=_custom") + .run((context) -> assertThat(context.getBean(MappingCouchbaseConverter.class).getTypeKey()) + .isEqualTo("_custom")); + } + + @Test + void customConversions() { + this.contextRunner.withUserConfiguration(CustomConversionsConfig.class).run((context) -> { + CouchbaseTemplate template = context.getBean(CouchbaseTemplate.class); + assertThat( + template.getConverter().getConversionService().canConvert(CouchbaseProperties.class, Boolean.class)) + .isTrue(); + }); + } + + @Configuration(proxyBeanMethods = false) + @Import(CouchbaseMockConfiguration.class) + static class CustomConversionsConfig { + + @Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS) + CouchbaseCustomConversions myCustomConversions() { + return new CouchbaseCustomConversions(Collections.singletonList(new MyConverter())); + } + + } + + @Configuration(proxyBeanMethods = false) + @EntityScan("org.springframework.boot.autoconfigure.data.couchbase.city") + @Import(CouchbaseMockConfiguration.class) + static class EntityScanConfig { + + } + + static class MyConverter implements Converter { + + @Override + public Boolean convert(CouchbaseProperties value) { + return true; + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataPropertiesTests.java new file mode 100644 index 0000000000..47d3e3db6d --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataPropertiesTests.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.couchbase; + +import org.junit.jupiter.api.Test; + +import org.springframework.data.couchbase.core.convert.DefaultCouchbaseTypeMapper; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link CouchbaseDataProperties}. + * + * @author Stephane Nicoll + */ +class CouchbaseDataPropertiesTests { + + @Test + void typeKeyHasConsistentDefault() { + assertThat(new CouchbaseDataProperties().getTypeKey()).isEqualTo(DefaultCouchbaseTypeMapper.DEFAULT_TYPE_KEY); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseMockConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseMockConfiguration.java new file mode 100644 index 0000000000..2e9ca2f821 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseMockConfiguration.java @@ -0,0 +1,38 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.couchbase; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.CouchbaseClientFactory; + +import static org.mockito.Mockito.mock; + +/** + * Test configuration that mocks access to Couchbase. + * + * @author Stephane Nicoll + */ +@Configuration(proxyBeanMethods = false) +class CouchbaseMockConfiguration { + + @Bean + CouchbaseClientFactory couchbaseClientFactory() { + return mock(CouchbaseClientFactory.class); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveAndImperativeRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveAndImperativeRepositoriesAutoConfigurationTests.java new file mode 100644 index 0000000000..2fbbac6c22 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveAndImperativeRepositoriesAutoConfigurationTests.java @@ -0,0 +1,85 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.couchbase; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; +import org.springframework.boot.autoconfigure.data.couchbase.city.CityRepository; +import org.springframework.boot.autoconfigure.data.couchbase.city.ReactiveCityRepository; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.context.annotation.ImportSelector; +import org.springframework.core.type.AnnotationMetadata; +import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories; +import org.springframework.data.couchbase.repository.config.EnableReactiveCouchbaseRepositories; +import org.springframework.util.StringUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link CouchbaseRepositoriesAutoConfiguration} and + * {@link CouchbaseReactiveRepositoriesAutoConfiguration}. + * + * @author Stephane Nicoll + */ +class CouchbaseReactiveAndImperativeRepositoriesAutoConfigurationTests { + + @Test + void shouldCreateInstancesForReactiveAndImperativeRepositories() { + new ApplicationContextRunner() + .withUserConfiguration(ImperativeAndReactiveConfiguration.class, BaseConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(CityRepository.class) + .hasSingleBean(ReactiveCityRepository.class)); + } + + @Configuration(proxyBeanMethods = false) + @TestAutoConfigurationPackage(CouchbaseAutoConfiguration.class) + @EnableCouchbaseRepositories(basePackageClasses = CityRepository.class) + @EnableReactiveCouchbaseRepositories(basePackageClasses = ReactiveCityRepository.class) + static class ImperativeAndReactiveConfiguration { + + } + + @Configuration(proxyBeanMethods = false) + @Import({ CouchbaseMockConfiguration.class, Registrar.class }) + static class BaseConfiguration { + + } + + static class Registrar implements ImportSelector { + + @Override + public String[] selectImports(AnnotationMetadata importingClassMetadata) { + List names = new ArrayList<>(); + for (Class type : new Class[] { CouchbaseAutoConfiguration.class, + CouchbaseDataAutoConfiguration.class, CouchbaseRepositoriesAutoConfiguration.class, + CouchbaseReactiveDataAutoConfiguration.class, + CouchbaseReactiveRepositoriesAutoConfiguration.class }) { + names.add(type.getName()); + } + return StringUtils.toStringArray(names); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveDataAutoConfigurationTests.java new file mode 100644 index 0000000000..a949f14aa1 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveDataAutoConfigurationTests.java @@ -0,0 +1,114 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.couchbase; + +import java.util.Collections; +import java.util.Set; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseProperties; +import org.springframework.boot.autoconfigure.data.couchbase.city.City; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.couchbase.config.BeanNames; +import org.springframework.data.couchbase.core.ReactiveCouchbaseTemplate; +import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions; +import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext; +import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener; +import org.springframework.test.util.ReflectionTestUtils; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link CouchbaseReactiveDataAutoConfiguration}. + * + * @author Alex Derkach + * @author Stephane Nicoll + */ +class CouchbaseReactiveDataAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration( + AutoConfigurations.of(ValidationAutoConfiguration.class, CouchbaseAutoConfiguration.class, + CouchbaseDataAutoConfiguration.class, CouchbaseReactiveDataAutoConfiguration.class)); + + @Test + void disabledIfCouchbaseIsNotConfigured() { + this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCouchbaseTemplate.class)); + } + + @Test + void validatorIsPresent() { + this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ValidatingCouchbaseEventListener.class)); + } + + @Test + @SuppressWarnings("unchecked") + void entityScanShouldSetInitialEntitySet() { + this.contextRunner.withUserConfiguration(EntityScanConfig.class).run((context) -> { + CouchbaseMappingContext mappingContext = context.getBean(CouchbaseMappingContext.class); + Set> initialEntitySet = (Set>) ReflectionTestUtils.getField(mappingContext, + "initialEntitySet"); + assertThat(initialEntitySet).containsOnly(City.class); + }); + } + + @Test + void customConversions() { + this.contextRunner.withUserConfiguration(CustomConversionsConfig.class).run((context) -> { + ReactiveCouchbaseTemplate template = context.getBean(ReactiveCouchbaseTemplate.class); + assertThat( + template.getConverter().getConversionService().canConvert(CouchbaseProperties.class, Boolean.class)) + .isTrue(); + }); + } + + @Configuration(proxyBeanMethods = false) + @Import(CouchbaseMockConfiguration.class) + static class CustomConversionsConfig { + + @Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS) + CouchbaseCustomConversions myCustomConversions() { + return new CouchbaseCustomConversions(Collections.singletonList(new MyConverter())); + } + + } + + @Configuration(proxyBeanMethods = false) + @EntityScan("org.springframework.boot.autoconfigure.data.couchbase.city") + @Import(CouchbaseMockConfiguration.class) + static class EntityScanConfig { + + } + + static class MyConverter implements Converter { + + @Override + public Boolean convert(CouchbaseProperties value) { + return true; + } + + } + +} 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 new file mode 100644 index 0000000000..060ea7f0d9 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseReactiveRepositoriesAutoConfigurationTests.java @@ -0,0 +1,108 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.couchbase; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; +import org.springframework.boot.autoconfigure.data.alt.couchbase.CityCouchbaseRepository; +import org.springframework.boot.autoconfigure.data.alt.couchbase.ReactiveCityCouchbaseRepository; +import org.springframework.boot.autoconfigure.data.couchbase.city.City; +import org.springframework.boot.autoconfigure.data.couchbase.city.ReactiveCityRepository; +import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.couchbase.repository.config.EnableCouchbaseRepositories; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link CouchbaseReactiveRepositoriesAutoConfiguration}. + * + * @author Alex Derkach + * @author Stephane Nicoll + */ +class CouchbaseReactiveRepositoriesAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner().withConfiguration( + AutoConfigurations.of(CouchbaseAutoConfiguration.class, CouchbaseDataAutoConfiguration.class, + CouchbaseRepositoriesAutoConfiguration.class, CouchbaseReactiveDataAutoConfiguration.class, + CouchbaseReactiveRepositoriesAutoConfiguration.class)); + + @Test + void couchbaseNotAvailable() { + this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class)); + } + + @Test + void defaultRepository() { + this.contextRunner.withUserConfiguration(DefaultConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(ReactiveCityRepository.class)); + } + + @Test + void imperativeRepositories() { + this.contextRunner.withUserConfiguration(DefaultConfiguration.class) + .withPropertyValues("spring.data.couchbase.repositories.type=imperative") + .run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class)); + } + + @Test + void disabledRepositories() { + this.contextRunner.withUserConfiguration(DefaultConfiguration.class) + .withPropertyValues("spring.data.couchbase.repositories.type=none") + .run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class)); + } + + @Test + void noRepositoryAvailable() { + this.contextRunner.withUserConfiguration(NoRepositoryConfiguration.class) + .run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityRepository.class)); + } + + @Test + void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { + this.contextRunner.withUserConfiguration(CustomizedConfiguration.class) + .run((context) -> assertThat(context).doesNotHaveBean(ReactiveCityCouchbaseRepository.class)); + } + + @Configuration(proxyBeanMethods = false) + @TestAutoConfigurationPackage(City.class) + @Import(CouchbaseMockConfiguration.class) + static class DefaultConfiguration { + + } + + @Configuration(proxyBeanMethods = false) + @TestAutoConfigurationPackage(EmptyDataPackage.class) + @Import(CouchbaseMockConfiguration.class) + static class NoRepositoryConfiguration { + + } + + @Configuration(proxyBeanMethods = false) + @TestAutoConfigurationPackage(CouchbaseReactiveRepositoriesAutoConfigurationTests.class) + @EnableCouchbaseRepositories(basePackageClasses = CityCouchbaseRepository.class) + @Import(CouchbaseMockConfiguration.class) + static class CustomizedConfiguration { + + } + +} 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 new file mode 100644 index 0000000000..ac628cc4fa --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseRepositoriesAutoConfigurationTests.java @@ -0,0 +1,96 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.couchbase; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; +import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; +import org.springframework.boot.autoconfigure.data.couchbase.city.City; +import org.springframework.boot.autoconfigure.data.couchbase.city.CityRepository; +import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link CouchbaseRepositoriesAutoConfiguration}. + * + * @author Eddú Meléndez + * @author Stephane Nicoll + */ +class CouchbaseRepositoriesAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withConfiguration(AutoConfigurations.of(CouchbaseAutoConfiguration.class, + CouchbaseDataAutoConfiguration.class, CouchbaseRepositoriesAutoConfiguration.class)); + + @Test + void couchbaseNotAvailable() { + this.contextRunner.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class)); + } + + @Test + void defaultRepository() { + this.contextRunner.withUserConfiguration(DefaultConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(CityRepository.class)); + } + + @Test + void reactiveRepositories() { + this.contextRunner.withUserConfiguration(DefaultConfiguration.class) + .withPropertyValues("spring.data.couchbase.repositories.type=reactive") + .run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class)); + } + + @Test + void disabledRepositories() { + this.contextRunner.withUserConfiguration(DefaultConfiguration.class) + .withPropertyValues("spring.data.couchbase.repositories.type=none") + .run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class)); + } + + @Test + void noRepositoryAvailable() { + this.contextRunner.withUserConfiguration(NoRepositoryConfiguration.class) + .run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class)); + } + + @Configuration(proxyBeanMethods = false) + @TestAutoConfigurationPackage(City.class) + static class CouchbaseNotAvailableConfiguration { + + } + + @Configuration(proxyBeanMethods = false) + @TestAutoConfigurationPackage(City.class) + @Import(CouchbaseMockConfiguration.class) + static class DefaultConfiguration { + + } + + @Configuration(proxyBeanMethods = false) + @TestAutoConfigurationPackage(EmptyDataPackage.class) + @Import(CouchbaseMockConfiguration.class) + static class NoRepositoryConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/City.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/City.java new file mode 100644 index 0000000000..51c657d9a0 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/City.java @@ -0,0 +1,32 @@ +/* + * Copyright 2012-2020 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 + * + * https://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.couchbase.city; + +import org.springframework.data.annotation.Id; +import org.springframework.data.couchbase.core.mapping.Document; +import org.springframework.data.couchbase.core.mapping.Field; + +@Document +public class City { + + @Id + private String id; + + @Field + private String name; + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/CityRepository.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/CityRepository.java new file mode 100644 index 0000000000..bb22f2d64f --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/CityRepository.java @@ -0,0 +1,23 @@ +/* + * Copyright 2012-2019 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 + * + * https://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.couchbase.city; + +import org.springframework.data.repository.Repository; + +public interface CityRepository extends Repository { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/ReactiveCityRepository.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/ReactiveCityRepository.java new file mode 100644 index 0000000000..548a290903 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/city/ReactiveCityRepository.java @@ -0,0 +1,29 @@ +/* + * Copyright 2012-2019 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 + * + * https://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.couchbase.city; + +import reactor.core.publisher.Mono; + +import org.springframework.data.repository.Repository; + +public interface ReactiveCityRepository extends Repository { + + Mono save(City city); + + Mono findById(Long id); + +} diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 1397f0c3d1..39b7d62249 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1145,6 +1145,8 @@ bom { "spring-boot-starter-cache", "spring-boot-starter-data-cassandra", "spring-boot-starter-data-cassandra-reactive", + "spring-boot-starter-data-couchbase", + "spring-boot-starter-data-couchbase-reactive", "spring-boot-starter-data-elasticsearch", "spring-boot-starter-data-jdbc", "spring-boot-starter-data-jpa", diff --git a/spring-boot-project/spring-boot-docs/build.gradle b/spring-boot-project/spring-boot-docs/build.gradle index c842f1f7b4..51327a914f 100644 --- a/spring-boot-project/spring-boot-docs/build.gradle +++ b/spring-boot-project/spring-boot-docs/build.gradle @@ -118,6 +118,7 @@ dependencies { implementation("org.springframework.amqp:spring-rabbit") implementation("org.springframework.batch:spring-batch-core") implementation("org.springframework.data:spring-data-cassandra") + implementation("org.springframework.data:spring-data-couchbase") implementation("org.springframework.data:spring-data-elasticsearch") { exclude group: "commons-logging", module: "commons-logging" } @@ -258,6 +259,7 @@ tasks.withType(org.asciidoctor.gradle.jvm.AbstractAsciidoctorTask) { "spring-batch-version": versionConstraints["org.springframework.batch:spring-batch-core"], "spring-boot-version": project.version, "spring-data-commons-version": versionConstraints["org.springframework.data:spring-data-commons"], + "spring-data-couchbase-version": versionConstraints["org.springframework.data:spring-data-couchbase"], "spring-data-envers-version": versionConstraints["org.springframework.data:spring-data-envers"], "spring-data-jdbc-version": versionConstraints["org.springframework.data:spring-data-jdbc"], "spring-data-jpa-version": versionConstraints["org.springframework.data:spring-data-jpa"], diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/anchor-rewrite.properties b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/anchor-rewrite.properties index 09aa395cad..bfef0fdf82 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/anchor-rewrite.properties +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/anchor-rewrite.properties @@ -258,6 +258,7 @@ boot-features-connecting-to-cassandra=features.nosql.cassandra.connecting boot-features-spring-data-cassandra-repositories=features.nosql.cassandra.repositories boot-features-couchbase=features.nosql.couchbase boot-features-connecting-to-couchbase=features.nosql.couchbase.connecting +boot-features-spring-data-couchbase-repositories=features.nosql.couchbase.repositories boot-features-ldap=features.nosql.ldap boot-features-ldap-connecting=features.nosql.ldap.connecting boot-features-ldap-spring-data-repositories=features.nosql.ldap.repositories @@ -270,6 +271,7 @@ boot-features-caching-provider-generic=features.caching.provider.generic boot-features-caching-provider-jcache=features.caching.provider.jcache boot-features-caching-provider-hazelcast=features.caching.provider.hazelcast boot-features-caching-provider-infinispan=features.caching.provider.infinispan +boot-features-caching-provider-couchbase=features.caching.provider.couchbase boot-features-caching-provider-redis=features.caching.provider.redis boot-features-caching-provider-caffeine=features.caching.provider.caffeine boot-features-caching-provider-simple=features.caching.provider.simple @@ -766,6 +768,7 @@ features.caching.provider.generic=io.caching.provider.generic features.caching.provider.jcache=io.caching.provider.jcache features.caching.provider.hazelcast=io.caching.provider.hazelcast features.caching.provider.infinispan=io.caching.provider.infinispan +features.caching.provider.couchbase=io.caching.provider.couchbase features.caching.provider.redis=io.caching.provider.redis features.caching.provider.caffeine=io.caching.provider.caffeine features.caching.provider.simple=io.caching.provider.simple @@ -882,6 +885,7 @@ features.nosql.cassandra.connecting=data.nosql.cassandra.connecting features.nosql.cassandra.repositories=data.nosql.cassandra.repositories features.nosql.couchbase=data.nosql.couchbase features.nosql.couchbase.connecting=data.nosql.couchbase.connecting +features.nosql.couchbase.repositories=data.nosql.couchbase.repositories features.nosql.ldap=data.nosql.ldap features.nosql.ldap.connecting=data.nosql.ldap.connecting features.nosql.ldap.repositories=data.nosql.ldap.repositories diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/attributes.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/attributes.adoc index aa7e253680..709bfa018b 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/attributes.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/attributes.adoc @@ -57,6 +57,8 @@ :spring-data: https://spring.io/projects/spring-data :spring-data-cassandra: https://spring.io/projects/spring-data-cassandra :spring-data-commons-api: https://docs.spring.io/spring-data/commons/docs/{spring-data-commons-version}/api/org/springframework/data +:spring-data-couchbase: https://spring.io/projects/spring-data-couchbase +:spring-data-couchbase-docs: https://docs.spring.io/spring-data/couchbase/docs/{spring-data-couchbase-version}/reference/html/ :spring-data-elasticsearch: https://spring.io/projects/spring-data-elasticsearch :spring-data-elasticsearch-docs: https://docs.spring.io/spring-data/elasticsearch/docs/current/reference/html/ :spring-data-envers: https://spring.io/projects/spring-data-envers diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/data/nosql.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/data/nosql.adoc index 2cdc69d6f4..2c01cffebc 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/data/nosql.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/data/nosql.adoc @@ -8,6 +8,7 @@ Spring Data provides additional projects that help you access a variety of NoSQL * {spring-data-redis}[Redis] * {spring-data-gemfire}[GemFire] or {spring-data-geode}[Geode] * {spring-data-cassandra}[Cassandra] +* {spring-data-couchbase}[Couchbase] * {spring-data-ldap}[LDAP] Spring Boot provides auto-configuration for Redis, MongoDB, Neo4j, Solr, Elasticsearch, Cassandra, Couchbase, LDAP and InfluxDB. @@ -455,7 +456,9 @@ TIP: For complete details of Spring Data Cassandra, see the https://docs.spring. [[data.nosql.couchbase]] === Couchbase https://www.couchbase.com/[Couchbase] is an open-source, distributed, multi-model NoSQL document-oriented database that is optimized for interactive applications. -Spring Boot offers auto-configuration for Couchbase. +Spring Boot offers auto-configuration for Couchbase and the abstractions on top of it provided by https://github.com/spring-projects/spring-data-couchbase[Spring Data Couchbase]. +There are `spring-boot-starter-data-couchbase` and `spring-boot-starter-data-couchbase-reactive` "`Starters`" for collecting the dependencies in a convenient way. + [[data.nosql.couchbase.connecting]] @@ -493,6 +496,45 @@ To take more control, one or more `ClusterEnvironmentBuilderCustomizer` beans ca +[[data.nosql.couchbase.repositories]] +==== Spring Data Couchbase Repositories +Spring Data includes repository support for Couchbase. +For complete details of Spring Data Couchbase, see the {spring-data-couchbase-docs}[reference documentation]. + +You can inject an auto-configured `CouchbaseTemplate` instance as you would with any other Spring Bean, provided a `CouchbaseClientFactory` bean is available. +This happens when a `Cluster` is available, as described above, and a bucket name has been specified: + +[source,yaml,indent=0,subs="verbatim",configprops,configblocks] +---- + spring: + data: + couchbase: + bucket-name: "my-bucket" +---- + +The following examples shows how to inject a `CouchbaseTemplate` bean: + +[source,java,indent=0,subs="verbatim"] +---- +include::{docs-java}/data/nosql/couchbase/repositories/MyBean.java[] +---- + +There are a few beans that you can define in your own configuration to override those provided by the auto-configuration: + +* A `CouchbaseMappingContext` `@Bean` with a name of `couchbaseMappingContext`. +* A `CustomConversions` `@Bean` with a name of `couchbaseCustomConversions`. +* A `CouchbaseTemplate` `@Bean` with a name of `couchbaseTemplate`. + +To avoid hard-coding those names in your own config, you can reuse `BeanNames` provided by Spring Data Couchbase. +For instance, you can customize the converters to use, as follows: + +[source,java,indent=0,subs="verbatim"] +---- +include::{docs-java}/data/nosql/couchbase/repositories/MyCouchbaseConfiguration.java[] +---- + + + [[data.nosql.ldap]] === LDAP https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol[LDAP] (Lightweight Directory Access Protocol) is an open, vendor-neutral, industry standard application protocol for accessing and maintaining distributed directory information services over an IP network. diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/io/caching.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/io/caching.adoc index 202816129c..f6cc47fc35 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/io/caching.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/io/caching.adoc @@ -42,6 +42,7 @@ If you have not defined a bean of type `CacheManager` or a `CacheResolver` named . <> . <> (Hazelcast and others) . <> +. <> . <> . <> . <> @@ -116,6 +117,31 @@ If a `HazelcastInstance` has been auto-configured, it is automatically wrapped i +[[io.caching.provider.couchbase]] +==== Couchbase +If Spring Data Couchbase is available and Couchbase is <>, a `CouchbaseCacheManager` is auto-configured. +It is possible to create additional caches on startup by setting the configprop:spring.cache.cache-names[] property and cache defaults can be configured by using `spring.cache.couchbase.*` properties. +For instance, the following configuration creates `cache1` and `cache2` caches with an entry _expiration_ of 10 minutes: + +[source,yaml,indent=0,subs="verbatim",configprops,configblocks] +---- + spring: + cache: + cache-names: "cache1,cache2" + couchbase: + expiration: "10m" +---- + +If you need more control over the configuration, consider registering a `CouchbaseCacheManagerBuilderCustomizer` bean. +The following example shows a customizer that configures a specific entry expiration for `cache1` and `cache2`: + +[source,java,indent=0,subs="verbatim"] +---- +include::{docs-java}/io/caching/provider/couchbase/MyCouchbaseCacheManagerConfiguration.java[] +---- + + + [[io.caching.provider.redis]] ==== Redis If https://redis.io/[Redis] is available and configured, a `RedisCacheManager` is auto-configured. diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/CouchbaseProperties.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/CouchbaseProperties.java new file mode 100644 index 0000000000..8245286846 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/CouchbaseProperties.java @@ -0,0 +1,21 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.docs.data.nosql.couchbase.repositories; + +class CouchbaseProperties { + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyBean.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyBean.java new file mode 100644 index 0000000000..b4774209e5 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyBean.java @@ -0,0 +1,37 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.docs.data.nosql.couchbase.repositories; + +import org.springframework.data.couchbase.core.CouchbaseTemplate; +import org.springframework.stereotype.Component; + +@Component +public class MyBean { + + private final CouchbaseTemplate template; + + public MyBean(CouchbaseTemplate template) { + this.template = template; + } + + // @fold:on // ... + public String someMethod() { + return this.template.getBucketName(); + } + // @fold:off + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyConverter.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyConverter.java new file mode 100644 index 0000000000..d7020dfc09 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyConverter.java @@ -0,0 +1,28 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.docs.data.nosql.couchbase.repositories; + +import org.springframework.core.convert.converter.Converter; + +class MyConverter implements Converter { + + @Override + public Boolean convert(CouchbaseProperties value) { + return true; + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyCouchbaseConfiguration.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyCouchbaseConfiguration.java new file mode 100644 index 0000000000..02d7b721cd --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/data/nosql/couchbase/repositories/MyCouchbaseConfiguration.java @@ -0,0 +1,34 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.docs.data.nosql.couchbase.repositories; + +import org.assertj.core.util.Arrays; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.config.BeanNames; +import org.springframework.data.couchbase.core.convert.CouchbaseCustomConversions; + +@Configuration(proxyBeanMethods = false) +public class MyCouchbaseConfiguration { + + @Bean(BeanNames.COUCHBASE_CUSTOM_CONVERSIONS) + public CouchbaseCustomConversions myCustomConversions() { + return new CouchbaseCustomConversions(Arrays.asList(new MyConverter())); + } + +} diff --git a/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/caching/provider/couchbase/MyCouchbaseCacheManagerConfiguration.java b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/caching/provider/couchbase/MyCouchbaseCacheManagerConfiguration.java new file mode 100644 index 0000000000..f8a1c036f7 --- /dev/null +++ b/spring-boot-project/spring-boot-docs/src/main/java/org/springframework/boot/docs/io/caching/provider/couchbase/MyCouchbaseCacheManagerConfiguration.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012-2021 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 + * + * https://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.docs.io.caching.provider.couchbase; + +import java.time.Duration; + +import org.springframework.boot.autoconfigure.cache.CouchbaseCacheManagerBuilderCustomizer; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.couchbase.cache.CouchbaseCacheConfiguration; + +@Configuration(proxyBeanMethods = false) +public class MyCouchbaseCacheManagerConfiguration { + + @Bean + public CouchbaseCacheManagerBuilderCustomizer myCouchbaseCacheManagerBuilderCustomizer() { + // @formatter:off + return (builder) -> builder + .withCacheConfiguration("cache1", CouchbaseCacheConfiguration + .defaultCacheConfig().entryExpiry(Duration.ofSeconds(10))) + .withCacheConfiguration("cache2", CouchbaseCacheConfiguration + .defaultCacheConfig().entryExpiry(Duration.ofMinutes(1))); + // @formatter:on + + } + +} diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase-reactive/build.gradle b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase-reactive/build.gradle new file mode 100644 index 0000000000..ec8c533472 --- /dev/null +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase-reactive/build.gradle @@ -0,0 +1,12 @@ +plugins { + id "org.springframework.boot.starter" +} + +description = "Starter for using Couchbase document-oriented database and Spring Data Couchbase Reactive" + +dependencies { + api(project(":spring-boot-project:spring-boot-starters:spring-boot-starter")) + api("io.projectreactor:reactor-core") + api("io.reactivex:rxjava-reactive-streams") + api("org.springframework.data:spring-data-couchbase") +} diff --git a/spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase/build.gradle b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase/build.gradle new file mode 100644 index 0000000000..17742429df --- /dev/null +++ b/spring-boot-project/spring-boot-starters/spring-boot-starter-data-couchbase/build.gradle @@ -0,0 +1,10 @@ +plugins { + id "org.springframework.boot.starter" +} + +description = "Starter for using Couchbase document-oriented database and Spring Data Couchbase" + +dependencies { + api(project(":spring-boot-project:spring-boot-starters:spring-boot-starter")) + api("org.springframework.data:spring-data-couchbase") +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-cache/build.gradle b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-cache/build.gradle index 7664156c00..9ea95627f4 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-cache/build.gradle +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-cache/build.gradle @@ -9,6 +9,9 @@ def caches = [ "caffeine": [ "com.github.ben-manes.caffeine:caffeine" ], + "couchbase": [ + project(":spring-boot-project:spring-boot-starters:spring-boot-starter-data-couchbase") + ], "hazelcast": [ "com.hazelcast:hazelcast", "com.hazelcast:hazelcast-spring" diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/build.gradle b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/build.gradle new file mode 100644 index 0000000000..9f4ceffe3c --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/build.gradle @@ -0,0 +1,12 @@ +plugins { + id "java" + id "org.springframework.boot.conventions" +} + +description = "Spring Boot Data Couchbase smoke test" + +dependencies { + implementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-data-couchbase")) + + testImplementation(project(":spring-boot-project:spring-boot-starters:spring-boot-starter-test")) +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/SampleCouchbaseApplication.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/SampleCouchbaseApplication.java new file mode 100644 index 0000000000..96dcd52f41 --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/SampleCouchbaseApplication.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2019 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 + * + * https://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 smoketest.data.couchbase; + +import java.util.UUID; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.CommandLineRunner; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SampleCouchbaseApplication implements CommandLineRunner { + + @Autowired + private UserRepository userRepository; + + public static void main(String[] args) { + SpringApplication.run(SampleCouchbaseApplication.class); + } + + @Override + public void run(String... args) throws Exception { + this.userRepository.deleteAll(); + User user = saveUser(); + System.out.println(this.userRepository.findById(user.getId())); + } + + private User saveUser() { + User user = new User(); + user.setId(UUID.randomUUID().toString()); + user.setFirstName("Alice"); + user.setLastName("Smith"); + return this.userRepository.save(user); + } + +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/User.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/User.java new file mode 100644 index 0000000000..2f7364c216 --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/User.java @@ -0,0 +1,65 @@ +/* + * Copyright 2012-2020 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 + * + * https://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 smoketest.data.couchbase; + +import org.springframework.data.annotation.Id; +import org.springframework.data.couchbase.core.mapping.Document; +import org.springframework.data.couchbase.core.mapping.Field; + +@Document +public class User { + + @Id + private String id; + + @Field + private String firstName; + + @Field + private String lastName; + + public String getId() { + return this.id; + } + + public void setId(String id) { + this.id = id; + } + + public String getFirstName() { + return this.firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return this.lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + @Override + public String toString() { + return "User{id='" + this.id + '\'' + ", firstName='" + this.firstName + '\'' + ", lastName='" + this.lastName + + '\'' + '}'; + } + +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/UserRepository.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/UserRepository.java new file mode 100644 index 0000000000..ff1ad58c16 --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/java/smoketest/data/couchbase/UserRepository.java @@ -0,0 +1,23 @@ +/* + * Copyright 2012-2020 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 + * + * https://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 smoketest.data.couchbase; + +import org.springframework.data.couchbase.repository.CouchbaseRepository; + +public interface UserRepository extends CouchbaseRepository { + +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/resources/application.properties b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/resources/application.properties new file mode 100644 index 0000000000..9cc0b988b7 --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/main/resources/application.properties @@ -0,0 +1,8 @@ +spring.couchbase.connection-string=couchbase://127.0.0.1 +spring.couchbase.username=admin +spring.couchbase.password=secret + +spring.couchbase.env.timeouts.connect=15s + +spring.data.couchbase.auto-index=true +spring.data.couchbase.bucket-name=default diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/test/java/smoketest/data/couchbase/SampleCouchbaseApplicationTests.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/test/java/smoketest/data/couchbase/SampleCouchbaseApplicationTests.java new file mode 100644 index 0000000000..8c70795a9c --- /dev/null +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-couchbase/src/test/java/smoketest/data/couchbase/SampleCouchbaseApplicationTests.java @@ -0,0 +1,59 @@ +/* + * Copyright 2012-2021 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 + * + * https://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 smoketest.data.couchbase; + +import com.couchbase.client.core.error.AmbiguousTimeoutException; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import org.springframework.boot.builder.SpringApplicationBuilder; +import org.springframework.boot.test.system.CapturedOutput; +import org.springframework.boot.test.system.OutputCaptureExtension; +import org.springframework.core.NestedCheckedException; + +import static org.assertj.core.api.Assertions.assertThat; + +@ExtendWith(OutputCaptureExtension.class) +class SampleCouchbaseApplicationTests { + + @Test + void testDefaultSettings(CapturedOutput output) { + try { + new SpringApplicationBuilder(SampleCouchbaseApplication.class).run("--server.port=0"); + } + catch (RuntimeException ex) { + if (serverNotRunning(ex)) { + return; + } + } + assertThat(output).contains("firstName='Alice', lastName='Smith'"); + } + + private boolean serverNotRunning(RuntimeException ex) { + NestedCheckedException nested = new NestedCheckedException("failed", ex) { + }; + if (nested.contains(AmbiguousTimeoutException.class)) { + Throwable root = nested.getRootCause(); + // This is not ideal, we should have a better way to know what is going on + if (root.getMessage().contains("QueryRequest, Reason: TIMEOUT")) { + return true; + } + } + return false; + } + +}