From 5777aa56156bfffcdbf22ad8756cbea90d2b6df2 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 29 Jul 2020 18:08:35 +0200 Subject: [PATCH 1/4] Start building against Spring Data 2020.0.0 snapshots See gh-22647 --- ...patcherServletsMappingDescriptionProvider.java | 15 ++++++++------- .../rest/SpringBootRepositoryRestConfigurer.java | 9 ++++++++- .../RepositoryRestMvcAutoConfigurationTests.java | 9 +++++---- .../spring-boot-dependencies/build.gradle | 2 +- 4 files changed, 22 insertions(+), 13 deletions(-) diff --git a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletsMappingDescriptionProvider.java b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletsMappingDescriptionProvider.java index 0d40fa5201..86a6fbdf1a 100644 --- a/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletsMappingDescriptionProvider.java +++ b/spring-boot-project/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/web/mappings/servlet/DispatcherServletsMappingDescriptionProvider.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -32,7 +32,6 @@ import org.springframework.boot.actuate.web.mappings.HandlerMethodDescription; import org.springframework.boot.actuate.web.mappings.MappingDescriptionProvider; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.ApplicationContext; -import org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping; import org.springframework.util.ClassUtils; import org.springframework.web.context.WebApplicationContext; import org.springframework.web.method.HandlerMethod; @@ -51,6 +50,7 @@ import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMappi * @author Stephane Nicoll * @since 2.0.0 */ +@SuppressWarnings("deprecation") public class DispatcherServletsMappingDescriptionProvider implements MappingDescriptionProvider { private static final List> descriptionProviders; @@ -171,8 +171,8 @@ public class DispatcherServletsMappingDescriptionProvider implements MappingDesc } - private static final class DelegatingHandlerMappingDescriptionProvider - implements HandlerMappingDescriptionProvider { + private static final class DelegatingHandlerMappingDescriptionProvider implements + HandlerMappingDescriptionProvider { private final List> descriptionProviders; @@ -182,12 +182,13 @@ public class DispatcherServletsMappingDescriptionProvider implements MappingDesc } @Override - public Class getMappingClass() { - return DelegatingHandlerMapping.class; + public Class getMappingClass() { + return org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping.class; } @Override - public List describe(DelegatingHandlerMapping handlerMapping) { + public List describe( + org.springframework.data.rest.webmvc.support.DelegatingHandlerMapping handlerMapping) { List descriptions = new ArrayList<>(); for (HandlerMapping delegate : handlerMapping.getDelegates()) { descriptions.addAll( diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/rest/SpringBootRepositoryRestConfigurer.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/rest/SpringBootRepositoryRestConfigurer.java index 7c6a1f30e1..45b925c62d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/rest/SpringBootRepositoryRestConfigurer.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/rest/SpringBootRepositoryRestConfigurer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -23,6 +23,7 @@ import org.springframework.core.annotation.Order; import org.springframework.data.rest.core.config.RepositoryRestConfiguration; import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; +import org.springframework.web.servlet.config.annotation.CorsRegistry; /** * A {@code RepositoryRestConfigurer} that applies configuration items from the @@ -43,7 +44,13 @@ class SpringBootRepositoryRestConfigurer implements RepositoryRestConfigurer { private RepositoryRestProperties properties; @Override + @SuppressWarnings("deprecation") public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { + configureRepositoryRestConfiguration(config, null); + } + + @Override + public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) { this.properties.applyTo(config); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/rest/RepositoryRestMvcAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/rest/RepositoryRestMvcAutoConfigurationTests.java index 236f8b506d..9a14631112 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/rest/RepositoryRestMvcAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/rest/RepositoryRestMvcAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -42,6 +42,7 @@ import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguratio import org.springframework.http.MediaType; import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder; import org.springframework.mock.web.MockServletContext; +import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import static org.assertj.core.api.Assertions.assertThat; @@ -76,7 +77,7 @@ class RepositoryRestMvcAutoConfigurationTests { assertThat(this.context.getBean(RepositoryRestMvcConfiguration.class)).isNotNull(); RepositoryRestConfiguration bean = this.context.getBean(RepositoryRestConfiguration.class); URI expectedUri = URI.create("/foo"); - assertThat(bean.getBaseUri()).as("Custom basePath not set").isEqualTo(expectedUri); + assertThat(bean.getBasePath()).as("Custom basePath not set").isEqualTo(expectedUri); BaseUri baseUri = this.context.getBean(BaseUri.class); assertThat(expectedUri).as("Custom basePath has not been applied to BaseUri bean").isEqualTo(baseUri.getUri()); } @@ -119,7 +120,7 @@ class RepositoryRestMvcAutoConfigurationTests { load(TestConfigurationWithRestMvcConfig.class, "spring.data.rest.base-path:foo"); assertThat(this.context.getBean(RepositoryRestMvcConfiguration.class)).isNotNull(); RepositoryRestConfiguration bean = this.context.getBean(RepositoryRestConfiguration.class); - assertThat(bean.getBaseUri()).isEqualTo(URI.create("")); + assertThat(bean.getBasePath()).isEqualTo(URI.create("")); } private void load(Class config, String... environment) { @@ -174,7 +175,7 @@ class RepositoryRestMvcAutoConfigurationTests { static class TestRepositoryRestConfigurer implements RepositoryRestConfigurer { @Override - public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { + public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) { config.setRepositoryDetectionStrategy(RepositoryDetectionStrategies.ALL); config.setDefaultMediaType(MediaType.parseMediaType("application/my-custom-json")); config.setMaxPageSize(78); diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index a56f4e421b..64d5e4365e 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1563,7 +1563,7 @@ bom { ] } } - library("Spring Data Bom", "2020.0.0-M1") { + library("Spring Data Bom", "2020.0.0-SNAPSHOT") { group("org.springframework.data") { imports = [ "spring-data-bom" From ff038be773a40c872e977c0f97d7f99ff37d3125 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 29 Jul 2020 18:09:13 +0200 Subject: [PATCH 2/4] Upgrade to Elasticsearch 7.8.1 Closes gh-22648 --- spring-boot-project/spring-boot-dependencies/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 64d5e4365e..489ddb4d00 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -271,7 +271,7 @@ bom { ] } } - library("Elasticsearch", "7.7.1") { + library("Elasticsearch", "7.8.1") { group("org.elasticsearch") { modules = [ "elasticsearch" From 15cd343737a94bdc56383666ad7e8182743eb68b Mon Sep 17 00:00:00 2001 From: Gerrit Meier Date: Fri, 10 Jul 2020 13:19:05 +0200 Subject: [PATCH 3/4] Upgrade to Spring Data Neo4j 6 See gh-22299 --- .../spring-boot-autoconfigure/build.gradle | 3 - .../Neo4jBookmarkManagementConfiguration.java | 65 ---- .../neo4j/Neo4jDataAutoConfiguration.java | 113 ++---- .../data/neo4j/Neo4jDataConfiguration.java | 88 +++++ .../data/neo4j/Neo4jDataProperties.java | 47 +++ .../data/neo4j/Neo4jProperties.java | 177 ---------- .../neo4j/Neo4jReactiveDataConfiguration.java | 92 +++++ ...eo4jReactiveRepositoriesConfiguration.java | 44 +++ ...eactiveRepositoriesConfigureRegistrar.java | 54 +++ .../Neo4jRepositoriesAutoConfiguration.java | 32 +- .../neo4j/Neo4jRepositoriesConfiguration.java | 41 +++ ... Neo4jRepositoriesConfigureRegistrar.java} | 10 +- .../data/neo4j/package-info.java | 2 +- .../boot/autoconfigure/domain/EntityScan.java | 6 +- ...o4jRepositoriesAutoConfigurationTests.java | 30 +- .../data/neo4j/MockedDriverConfiguration.java | 49 +++ .../Neo4jDataAutoConfigurationTests.java | 331 +++++++----------- .../data/neo4j/Neo4jPropertiesTests.java | 191 ---------- ...riesAutoConfigurationIntegrationTests.java | 76 ++++ ...o4jRepositoriesAutoConfigurationTests.java | 126 ++++--- ...activeNeo4jDataAutoConfigurationTests.java | 197 +++++++++++ .../autoconfigure/data/neo4j/city/City.java | 12 +- .../neo4j/city/ReactiveCityRepository.java | 26 ++ .../data/neo4j/country/Country.java | 13 +- .../country/ReactiveCountryRepository.java | 23 ++ .../spring-boot-dependencies/build.gradle | 13 - .../neo4j/DataNeo4jTestIntegrationTests.java | 12 +- ...taNeo4jTestPropertiesIntegrationTests.java | 2 +- ...TestWithIncludeFilterIntegrationTests.java | 2 +- .../DataNeo4jTypeExcludeFilterTests.java | 69 ++++ .../data/neo4j/ExampleGraph.java | 15 +- .../data/neo4j/ExampleService.java | 14 +- .../ReactiveDataNeo4jIntegrationTests.java | 100 ++++++ .../spring-boot-test-support/build.gradle | 1 - spring-boot-project/spring-boot/build.gradle | 1 - .../java/smoketest/data/neo4j/Customer.java | 10 +- 36 files changed, 1220 insertions(+), 867 deletions(-) delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jBookmarkManagementConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataProperties.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jProperties.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfiguration.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfigureRegistrar.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfiguration.java rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/{Neo4jRepositoriesRegistrar.java => Neo4jRepositoriesConfigureRegistrar.java} (81%) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MockedDriverConfiguration.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jPropertiesTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationIntegrationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/ReactiveNeo4jDataAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/ReactiveCityRepository.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/ReactiveCountryRepository.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTypeExcludeFilterTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ReactiveDataNeo4jIntegrationTests.java diff --git a/spring-boot-project/spring-boot-autoconfigure/build.gradle b/spring-boot-project/spring-boot-autoconfigure/build.gradle index b982361e7a..58265433bc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-autoconfigure/build.gradle @@ -171,9 +171,6 @@ dependencies { testImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") testImplementation("org.junit.jupiter:junit-jupiter") testImplementation("org.mockito:mockito-core") - testImplementation("org.neo4j:neo4j-ogm-bolt-native-types") - testImplementation("org.neo4j:neo4j-ogm-http-driver") - testImplementation("org.neo4j:neo4j-ogm-embedded-driver") testImplementation("org.springframework:spring-test") testImplementation("org.springframework.kafka:spring-kafka-test") testImplementation("org.springframework.security:spring-security-test") diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jBookmarkManagementConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jBookmarkManagementConfiguration.java deleted file mode 100644 index 0d71fb6866..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jBookmarkManagementConfiguration.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * 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.neo4j; - -import com.github.benmanes.caffeine.cache.Caffeine; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.cache.caffeine.CaffeineCacheManager; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; -import org.springframework.context.annotation.ScopedProxyMode; -import org.springframework.data.neo4j.bookmark.BeanFactoryBookmarkOperationAdvisor; -import org.springframework.data.neo4j.bookmark.BookmarkInterceptor; -import org.springframework.data.neo4j.bookmark.BookmarkManager; -import org.springframework.data.neo4j.bookmark.CaffeineBookmarkManager; -import org.springframework.web.context.WebApplicationContext; - -/** - * Provides a {@link BookmarkManager} for Neo4j's bookmark support based on Caffeine if - * available. Depending on the application's type (web or not) the bookmark manager will - * be bound to the application or the request, as recommend by Spring Data Neo4j. - * - * @author Michael Simons - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ Caffeine.class, CaffeineCacheManager.class }) -@ConditionalOnMissingBean(BookmarkManager.class) -@ConditionalOnBean({ BeanFactoryBookmarkOperationAdvisor.class, BookmarkInterceptor.class }) -class Neo4jBookmarkManagementConfiguration { - - private static final String BOOKMARK_MANAGER_BEAN_NAME = "bookmarkManager"; - - @Bean(BOOKMARK_MANAGER_BEAN_NAME) - @ConditionalOnWebApplication - @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.INTERFACES) - BookmarkManager requestScopedBookmarkManager() { - return new CaffeineBookmarkManager(); - } - - @Bean(BOOKMARK_MANAGER_BEAN_NAME) - @ConditionalOnNotWebApplication - BookmarkManager singletonScopedBookmarkManager() { - return new CaffeineBookmarkManager(); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java index bc02c39ce4..f50ecd55a0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java @@ -16,111 +16,62 @@ package org.springframework.boot.autoconfigure.data.neo4j; -import java.util.List; +import java.util.Set; -import org.neo4j.ogm.session.SessionFactory; -import org.neo4j.ogm.session.event.EventListener; +import org.neo4j.driver.Driver; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.autoconfigure.AutoConfigurationPackages; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.autoconfigure.domain.EntityScanPackages; -import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; +import org.springframework.boot.autoconfigure.domain.EntityScanner; +import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.data.neo4j.transaction.Neo4jTransactionManager; -import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.util.StringUtils; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.data.neo4j.core.convert.Neo4jConversions; +import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext; +import org.springframework.data.neo4j.core.schema.Node; /** - * {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j. + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j. Automatic + * configuration of base infrastructure that imports configuration for both imperative and + * reactive Neo4j repositories. * * @author Michael Hunger * @author Josh Long * @author Vince Bickers * @author Stephane Nicoll * @author Kazuki Shimizu - * @author Michael Simons + * @author Michael J Simons * @since 1.4.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ SessionFactory.class, Neo4jTransactionManager.class, PlatformTransactionManager.class }) -@EnableConfigurationProperties(Neo4jProperties.class) -@Import(Neo4jBookmarkManagementConfiguration.class) +@ConditionalOnBean(Driver.class) +@EnableConfigurationProperties(Neo4jDataProperties.class) +@AutoConfigureAfter(Neo4jAutoConfiguration.class) +@AutoConfigureBefore(TransactionAutoConfiguration.class) +@Import({ Neo4jDataConfiguration.class, Neo4jReactiveDataConfiguration.class }) public class Neo4jDataAutoConfiguration { @Bean - @ConditionalOnMissingBean(PlatformTransactionManager.class) - public Neo4jTransactionManager transactionManager(SessionFactory sessionFactory, - ObjectProvider transactionManagerCustomizers) { - Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(sessionFactory); - transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager)); - return transactionManager; + @ConditionalOnMissingBean + public Neo4jConversions neo4jConversions() { + return new Neo4jConversions(); } - @Configuration(proxyBeanMethods = false) - @ConditionalOnMissingBean(SessionFactory.class) - static class Neo4jOgmSessionFactoryConfiguration { - - @Bean - @ConditionalOnMissingBean - org.neo4j.ogm.config.Configuration configuration(Neo4jProperties properties) { - return properties.createConfiguration(); - } - - @Bean - SessionFactory sessionFactory(org.neo4j.ogm.config.Configuration configuration, BeanFactory beanFactory, - ObjectProvider eventListeners) { - SessionFactory sessionFactory = new SessionFactory(configuration, getPackagesToScan(beanFactory)); - eventListeners.orderedStream().forEach(sessionFactory::register); - return sessionFactory; - } - - private String[] getPackagesToScan(BeanFactory beanFactory) { - List packages = EntityScanPackages.get(beanFactory).getPackageNames(); - if (packages.isEmpty() && AutoConfigurationPackages.has(beanFactory)) { - packages = AutoConfigurationPackages.get(beanFactory); - } - return StringUtils.toStringArray(packages); - } - - } - - @Configuration(proxyBeanMethods = false) - @ConditionalOnWebApplication(type = Type.SERVLET) - @ConditionalOnClass({ WebMvcConfigurer.class, OpenSessionInViewInterceptor.class }) - @ConditionalOnMissingBean(OpenSessionInViewInterceptor.class) - @ConditionalOnProperty(prefix = "spring.data.neo4j", name = "open-in-view", havingValue = "true") - static class Neo4jWebConfiguration { - - @Bean - OpenSessionInViewInterceptor neo4jOpenSessionInViewInterceptor() { - return new OpenSessionInViewInterceptor(); - } - - @Bean - WebMvcConfigurer neo4jOpenSessionInViewInterceptorConfigurer(OpenSessionInViewInterceptor interceptor) { - return new WebMvcConfigurer() { - - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addWebRequestInterceptor(interceptor); - } - - }; - } - + @Bean + @ConditionalOnMissingBean + public Neo4jMappingContext neo4jMappingContext(ApplicationContext applicationContext, + Neo4jConversions neo4jConversions) throws ClassNotFoundException { + Set> initialEntityClasses = new EntityScanner(applicationContext).scan(Node.class); + Neo4jMappingContext context = new Neo4jMappingContext(neo4jConversions); + context.setInitialEntitySet(initialEntityClasses); + return context; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataConfiguration.java new file mode 100644 index 0000000000..070ab1471c --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataConfiguration.java @@ -0,0 +1,88 @@ +/* + * 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.neo4j; + +import org.neo4j.driver.Driver; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +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.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.env.Environment; +import org.springframework.data.neo4j.config.Neo4jDefaultCallbacksRegistrar; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.Neo4jClient; +import org.springframework.data.neo4j.core.Neo4jOperations; +import org.springframework.data.neo4j.core.Neo4jTemplate; +import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; +import org.springframework.transaction.PlatformTransactionManager; + +/** + * Internal configuration of Neo4j client and transaction manager. + * + * @author Michael J. Simons + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({ Neo4jTransactionManager.class, PlatformTransactionManager.class }) +@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.IMPERATIVE) +@AutoConfigureAfter(Neo4jAutoConfiguration.class) +@AutoConfigureBefore(Neo4jRepositoriesConfiguration.class) +@Import(Neo4jDefaultCallbacksRegistrar.class) +class Neo4jDataConfiguration { + + @Bean("databaseSelectionProvider") + @ConditionalOnMissingBean + DatabaseSelectionProvider defaultSelectionProvider(Environment environment) { + String database = environment.getProperty("spring.data.neo4j.database"); + if (database != null) { + return DatabaseSelectionProvider.createStaticDatabaseSelectionProvider(database); + } + return DatabaseSelectionProvider.getDefaultSelectionProvider(); + } + + @Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME) + @ConditionalOnMissingBean + Neo4jClient neo4jClient(Driver driver) { + return Neo4jClient.create(driver); + } + + @Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME) + @ConditionalOnMissingBean(Neo4jOperations.class) + Neo4jTemplate neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext, + DatabaseSelectionProvider databaseNameProvider) { + return new Neo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider); + } + + @Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME) + @ConditionalOnMissingBean(PlatformTransactionManager.class) + Neo4jTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider, + ObjectProvider optionalCustomizers) { + Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(driver, databaseNameProvider); + optionalCustomizers.ifAvailable((customizer) -> customizer.customize(transactionManager)); + return transactionManager; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataProperties.java new file mode 100644 index 0000000000..dad06eca71 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataProperties.java @@ -0,0 +1,47 @@ +/* + * 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.neo4j; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; + +/** + * Configuration properties for Spring Data Neo4j. + * + * @author Michael J. Simons + * @since 2.4.0 + */ +@ConfigurationProperties(prefix = "spring.data.neo4j") +public class Neo4jDataProperties { + + /** + * A statically configured database. This property is only applicable when connecting + * against a 4.0 cluster or server and will lead to errors if used with a prior + * version of Neo4j. Leave this null (the default) to indicate that you like the + * server to decide the default database to use. + */ + private String database; + + public String getDatabase() { + return this.database; + } + + public void setDatabase(String database) { + this.database = database; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jProperties.java deleted file mode 100644 index 57bf0660d4..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jProperties.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * 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.neo4j; - -import org.neo4j.ogm.config.AutoIndexMode; -import org.neo4j.ogm.config.Configuration; -import org.neo4j.ogm.config.Configuration.Builder; - -import org.springframework.beans.BeansException; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.util.ClassUtils; - -/** - * Configuration properties for Neo4j. - * - * @author Stephane Nicoll - * @author Michael Hunger - * @author Vince Bickers - * @author Aurélien Leboulanger - * @author Michael Simons - * @since 1.4.0 - */ -@ConfigurationProperties(prefix = "spring.data.neo4j") -public class Neo4jProperties implements ApplicationContextAware { - - static final String EMBEDDED_DRIVER = "org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver"; - - static final String HTTP_DRIVER = "org.neo4j.ogm.drivers.http.driver.HttpDriver"; - - static final String DEFAULT_BOLT_URI = "bolt://localhost:7687"; - - static final String BOLT_DRIVER = "org.neo4j.ogm.drivers.bolt.driver.BoltDriver"; - - /** - * URI used by the driver. Auto-detected by default. - */ - private String uri; - - /** - * Login user of the server. - */ - private String username; - - /** - * Login password of the server. - */ - private String password; - - /** - * Auto index mode. - */ - private AutoIndexMode autoIndex = AutoIndexMode.NONE; - - /** - * Whether to use Neo4j native types wherever possible. - */ - private boolean useNativeTypes = false; - - private final Embedded embedded = new Embedded(); - - private ClassLoader classLoader = Neo4jProperties.class.getClassLoader(); - - public String getUri() { - return this.uri; - } - - public void setUri(String uri) { - this.uri = uri; - } - - public String getUsername() { - return this.username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return this.password; - } - - public void setPassword(String password) { - this.password = password; - } - - public AutoIndexMode getAutoIndex() { - return this.autoIndex; - } - - public void setAutoIndex(AutoIndexMode autoIndex) { - this.autoIndex = autoIndex; - } - - public boolean isUseNativeTypes() { - return this.useNativeTypes; - } - - public void setUseNativeTypes(boolean useNativeTypes) { - this.useNativeTypes = useNativeTypes; - } - - public Embedded getEmbedded() { - return this.embedded; - } - - @Override - public void setApplicationContext(ApplicationContext ctx) throws BeansException { - this.classLoader = ctx.getClassLoader(); - } - - /** - * Create a {@link Configuration} based on the state of this instance. - * @return a configuration - */ - public Configuration createConfiguration() { - Builder builder = new Builder(); - configure(builder); - return builder.build(); - } - - private void configure(Builder builder) { - if (this.uri != null) { - builder.uri(this.uri); - } - else { - configureUriWithDefaults(builder); - } - if (this.username != null && this.password != null) { - builder.credentials(this.username, this.password); - } - builder.autoIndex(getAutoIndex().getName()); - if (this.useNativeTypes) { - builder.useNativeTypes(); - } - } - - private void configureUriWithDefaults(Builder builder) { - if (!getEmbedded().isEnabled() || !ClassUtils.isPresent(EMBEDDED_DRIVER, this.classLoader)) { - builder.uri(DEFAULT_BOLT_URI); - } - } - - public static class Embedded { - - /** - * Whether to enable embedded mode if the embedded driver is available. - */ - private boolean enabled = true; - - public boolean isEnabled() { - return this.enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataConfiguration.java new file mode 100644 index 0000000000..c43fb455eb --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataConfiguration.java @@ -0,0 +1,92 @@ +/* + * 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.neo4j; + +import org.neo4j.driver.Driver; +import reactor.core.publisher.Flux; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType; +import org.springframework.boot.autoconfigure.data.RepositoryType; +import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.annotation.Order; +import org.springframework.data.neo4j.config.Neo4jDefaultReactiveCallbacksRegistrar; +import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; +import org.springframework.data.neo4j.core.ReactiveNeo4jClient; +import org.springframework.data.neo4j.core.ReactiveNeo4jOperations; +import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; +import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext; +import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; +import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension; +import org.springframework.transaction.ReactiveTransactionManager; + +/** + * Internal configuration for the reactive Neo4j client. + * + * @author Michael J. Simons + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({ ReactiveNeo4jTransactionManager.class, ReactiveTransactionManager.class, Flux.class }) +@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.REACTIVE) +@AutoConfigureAfter(Neo4jAutoConfiguration.class) +@AutoConfigureBefore(Neo4jReactiveRepositoriesConfiguration.class) +@Import(Neo4jDefaultReactiveCallbacksRegistrar.class) +class Neo4jReactiveDataConfiguration { + + @Bean("reactiveDatabaseSelectionProvider") + @ConditionalOnProperty(prefix = "spring.data.neo4j", name = "database") + @ConditionalOnMissingBean + @Order(-30) + ReactiveDatabaseSelectionProvider staticDatabaseSelectionProvider(Neo4jDataProperties dataProperties) { + return ReactiveDatabaseSelectionProvider.createStaticDatabaseSelectionProvider(dataProperties.getDatabase()); + } + + @Bean("reactiveDatabaseSelectionProvider") + @ConditionalOnMissingBean + @Order(-20) + ReactiveDatabaseSelectionProvider defaultSelectionProvider() { + return ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider(); + } + + @Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME) + @ConditionalOnMissingBean + ReactiveNeo4jClient neo4jClient(Driver driver) { + return ReactiveNeo4jClient.create(driver); + } + + @Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME) + @ConditionalOnMissingBean(ReactiveNeo4jOperations.class) + ReactiveNeo4jTemplate neo4jTemplate(ReactiveNeo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext, + ReactiveDatabaseSelectionProvider databaseNameProvider) { + return new ReactiveNeo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider); + } + + @Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME) + @ConditionalOnMissingBean(ReactiveTransactionManager.class) + ReactiveTransactionManager transactionManager(Driver driver, + ReactiveDatabaseSelectionProvider databaseNameProvider) { + return new ReactiveNeo4jTransactionManager(driver, databaseNameProvider); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfiguration.java new file mode 100644 index 0000000000..281ba5ce4e --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfiguration.java @@ -0,0 +1,44 @@ +/* + * 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.neo4j; + +import reactor.core.publisher.Flux; + +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.neo4j.repository.ReactiveNeo4jRepository; +import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension; +import org.springframework.data.neo4j.repository.support.ReactiveNeo4jRepositoryFactoryBean; + +/** + * Imports the registrar for reactive Neo4j repositories. + * + * @author Michael J. Simons + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({ Flux.class, ReactiveNeo4jRepository.class }) +@ConditionalOnMissingBean({ ReactiveNeo4jRepositoryFactoryBean.class, + ReactiveNeo4jRepositoryConfigurationExtension.class }) +@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.REACTIVE) +@Import(Neo4jReactiveRepositoriesConfigureRegistrar.class) +final class Neo4jReactiveRepositoriesConfiguration { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfigureRegistrar.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfigureRegistrar.java new file mode 100644 index 0000000000..5561bc9e44 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfigureRegistrar.java @@ -0,0 +1,54 @@ +/* + * 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.neo4j; + +import java.lang.annotation.Annotation; + +import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport; +import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; +import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension; +import org.springframework.data.repository.config.RepositoryConfigurationExtension; + +/** + * {@link ImportBeanDefinitionRegistrar} used to auto-configure reactive Spring Data Neo4j + * Repositories. + * + * @author Michael J. Simons + */ +final class Neo4jReactiveRepositoriesConfigureRegistrar extends AbstractRepositoryConfigurationSourceSupport { + + @Override + protected Class getAnnotation() { + return EnableReactiveNeo4jRepositories.class; + } + + @Override + protected Class getConfiguration() { + return SpringDataNeo4jConfiguration.class; + } + + @Override + protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() { + return new ReactiveNeo4jRepositoryConfigurationExtension(); + } + + @EnableReactiveNeo4jRepositories + private static class SpringDataNeo4jConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java index 54de8aaa2f..c611ad42c5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -16,45 +16,29 @@ package org.springframework.boot.autoconfigure.data.neo4j; -import org.neo4j.ogm.session.Neo4jSession; +import org.neo4j.driver.Driver; import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.data.neo4j.repository.Neo4jRepository; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; -import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; -import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean; /** - * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Neo4j - * Repositories. - *

- * Activates when there is no bean of type {@link Neo4jRepositoryFactoryBean} configured - * in the context, the Spring Data Neo4j {@link Neo4jRepository} type is on the classpath, - * the Neo4j client driver API is on the classpath, and there is no other configured - * {@link Neo4jRepository}. - *

- * Once in effect, the auto-configuration is the equivalent of enabling Neo4j repositories - * using the {@link EnableNeo4jRepositories @EnableNeo4jRepositories} annotation. + * Shared entry point for the configuration of Spring Data Neo4j repositories in their + * imperative and reactive forms. * * @author Dave Syer * @author Oliver Gierke * @author Josh Long - * @since 1.4.0 + * @author Michael J. Simons * @see EnableNeo4jRepositories + * @since 1.4.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ Neo4jSession.class, Neo4jRepository.class }) -@ConditionalOnMissingBean({ Neo4jRepositoryFactoryBean.class, Neo4jRepositoryConfigurationExtension.class }) -@ConditionalOnProperty(prefix = "spring.data.neo4j.repositories", name = "enabled", havingValue = "true", - matchIfMissing = true) -@Import(Neo4jRepositoriesRegistrar.class) +@ConditionalOnClass(Driver.class) @AutoConfigureAfter(Neo4jDataAutoConfiguration.class) +@Import({ Neo4jRepositoriesConfiguration.class, Neo4jReactiveRepositoriesConfiguration.class }) public class Neo4jRepositoriesAutoConfiguration { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfiguration.java new file mode 100644 index 0000000000..7a190c6822 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfiguration.java @@ -0,0 +1,41 @@ +/* + * 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.neo4j; + +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.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; +import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean; + +/** + * Imports the registrar for imperative Neo4j repositories. + * + * @author Michael J. Simons + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass(Neo4jRepository.class) +@ConditionalOnMissingBean({ Neo4jRepositoryFactoryBean.class, Neo4jRepositoryConfigurationExtension.class }) +@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.IMPERATIVE) +@Import(Neo4jRepositoriesConfigureRegistrar.class) +class Neo4jRepositoriesConfiguration { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesRegistrar.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfigureRegistrar.java similarity index 81% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesRegistrar.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfigureRegistrar.java index 976581095e..268dff593b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesRegistrar.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfigureRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -19,7 +19,6 @@ package org.springframework.boot.autoconfigure.data.neo4j; import java.lang.annotation.Annotation; import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport; -import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; import org.springframework.data.repository.config.RepositoryConfigurationExtension; @@ -29,8 +28,9 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi * Repositories. * * @author Michael Hunger + * @author Michael J. Simons */ -class Neo4jRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport { +class Neo4jRepositoriesConfigureRegistrar extends AbstractRepositoryConfigurationSourceSupport { @Override protected Class getAnnotation() { @@ -39,7 +39,7 @@ class Neo4jRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSu @Override protected Class getConfiguration() { - return EnableNeo4jRepositoriesConfiguration.class; + return SpringDataNeo4jConfiguration.class; } @Override @@ -48,7 +48,7 @@ class Neo4jRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSu } @EnableNeo4jRepositories - private static class EnableNeo4jRepositoriesConfiguration { + private static class SpringDataNeo4jConfiguration { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/package-info.java index 38b1e038a4..4a6a7a12db 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/package-info.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. 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 c8fc7da791..fd1b388ae8 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 @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -34,12 +34,11 @@ import org.springframework.core.annotation.AliasFor; *

  • Set the * {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#setPackagesToScan(String...) * packages scanned} for JPA entities.
  • - *
  • Set the packages used with Neo4J's {@link org.neo4j.ogm.session.SessionFactory - * SessionFactory}.
  • *
  • Set the * {@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}, * {@link org.springframework.data.cassandra.core.mapping.CassandraMappingContext * Cassandra} and * {@link org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext @@ -52,6 +51,7 @@ import org.springframework.core.annotation.AliasFor; * annotation. * * @author Phillip Webb + * @author Michael J. Simons * @since 1.4.0 * @see EntityScanPackages */ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java index 419c940790..e9d160029f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java @@ -19,8 +19,6 @@ package org.springframework.boot.autoconfigure.data.neo4j; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver; - import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration; import org.springframework.boot.autoconfigure.data.jpa.city.City; @@ -31,13 +29,19 @@ import org.springframework.boot.autoconfigure.data.neo4j.empty.EmptyMarker; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; -import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.data.neo4j.config.AbstractNeo4jConfig; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.neo4j.driver.Config; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.internal.logging.Slf4jLogging; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -48,6 +52,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Michael Hunger * @author Vince Bickers * @author Stephane Nicoll + * @author Michael J. Simons */ class MixedNeo4jRepositoriesAutoConfigurationTests { @@ -94,7 +99,6 @@ class MixedNeo4jRepositoriesAutoConfigurationTests { private void load(Class config, String... environment) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.setClassLoader(new FilteredClassLoader(EmbeddedDriver.class)); TestPropertyValues.of(environment).and("spring.datasource.initialization-mode=never").applyTo(context); context.register(config); context.register(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, @@ -108,7 +112,14 @@ class MixedNeo4jRepositoriesAutoConfigurationTests { @TestAutoConfigurationPackage(EmptyMarker.class) // Not this package or its parent @EnableNeo4jRepositories(basePackageClasses = Country.class) - static class TestConfiguration { + static class TestConfiguration extends AbstractNeo4jConfig { + + @Override + @Bean + public Driver driver() { + return GraphDatabase.driver("bolt://neo4j.test:7687", + Config.builder().withLogging(new Slf4jLogging()).build()); + } } @@ -117,7 +128,14 @@ class MixedNeo4jRepositoriesAutoConfigurationTests { @EnableNeo4jRepositories(basePackageClasses = Country.class) @EntityScan(basePackageClasses = City.class) @EnableJpaRepositories(basePackageClasses = CityRepository.class) - static class MixedConfiguration { + static class MixedConfiguration extends AbstractNeo4jConfig { + + @Override + @Bean + public Driver driver() { + return GraphDatabase.driver("bolt://neo4j.test:7687", + Config.builder().withLogging(new Slf4jLogging()).build()); + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MockedDriverConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MockedDriverConfiguration.java new file mode 100644 index 0000000000..8c2a3a4277 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MockedDriverConfiguration.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.neo4j; + +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.neo4j.driver.SessionConfig; +import org.neo4j.driver.types.TypeSystem; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Driver configuration mocked to avoid instantiation of a real driver with connection + * creation. + * + * @author Michael J. Simons + */ +@Configuration(proxyBeanMethods = false) +class MockedDriverConfiguration { + + @Bean + Driver driver() { + Driver driver = mock(Driver.class); + TypeSystem typeSystem = mock(TypeSystem.class); + Session session = mock(Session.class); + when(driver.defaultTypeSystem()).thenReturn(typeSystem); + when(driver.session(Mockito.any(SessionConfig.class))).thenReturn(session); + return driver; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java index 1f523d026e..d678521498 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 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. @@ -16,257 +16,168 @@ package org.springframework.boot.autoconfigure.data.neo4j; -import com.github.benmanes.caffeine.cache.Caffeine; -import org.junit.jupiter.api.Test; -import org.neo4j.ogm.driver.NativeTypesNotAvailableException; -import org.neo4j.ogm.driver.NativeTypesNotSupportedException; -import org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver; -import org.neo4j.ogm.session.Session; -import org.neo4j.ogm.session.SessionFactory; -import org.neo4j.ogm.session.event.Event; -import org.neo4j.ogm.session.event.EventListener; -import org.neo4j.ogm.session.event.PersistenceEvent; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.boot.autoconfigure.AutoConfigurationPackages; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.data.neo4j.city.City; -import org.springframework.boot.autoconfigure.data.neo4j.country.Country; -import org.springframework.boot.autoconfigure.domain.EntityScan; -import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.boot.test.context.runner.WebApplicationContextRunner; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.annotation.EnableBookmarkManagement; -import org.springframework.data.neo4j.bookmark.BookmarkManager; -import org.springframework.data.neo4j.mapping.Neo4jMappingContext; -import org.springframework.data.neo4j.transaction.Neo4jTransactionManager; -import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor; -import org.springframework.web.context.WebApplicationContext; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; +import org.springframework.data.neo4j.core.DatabaseSelection; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.Neo4jClient; +import org.springframework.data.neo4j.core.Neo4jOperations; +import org.springframework.data.neo4j.core.Neo4jTemplate; +import org.springframework.data.neo4j.core.convert.Neo4jConversions; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.transaction.PlatformTransactionManager; /** - * Tests for {@link Neo4jDataAutoConfiguration}. Tests should not use the embedded driver - * as it requires the complete Neo4j-Kernel and server to function properly. - * - * @author Stephane Nicoll - * @author Michael Hunger - * @author Vince Bickers - * @author Andy Wilkinson - * @author Kazuki Shimizu - * @author Michael Simons + * @author Michael J. Simons */ class Neo4jDataAutoConfigurationTests { - private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() - .withClassLoader(new FilteredClassLoader(EmbeddedDriver.class)) - .withUserConfiguration(TestConfiguration.class).withConfiguration( - AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class)); + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.data.neo4j.repositories.type=imperative") + .withUserConfiguration(MockedDriverConfiguration.class) + .withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class)); @Test - void defaultConfiguration() { - this.contextRunner.withPropertyValues("spring.data.neo4j.uri=http://localhost:8989").run((context) -> { - assertThat(context).hasSingleBean(org.neo4j.ogm.config.Configuration.class); - assertThat(context).hasSingleBean(SessionFactory.class); - assertThat(context).hasSingleBean(Neo4jTransactionManager.class); - assertThat(context).doesNotHaveBean(OpenSessionInViewInterceptor.class); - assertThat(context).doesNotHaveBean(BookmarkManager.class); + void shouldProvideConversions() { + contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jConversions.class)); + } + + @Test + void shouldProvideDefaultDatabaseNameProvider() { + contextRunner.run(ctx -> { + assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class); + DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class); + assertThat(databaseNameProvider).isSameAs(DatabaseSelectionProvider.getDefaultSelectionProvider()); }); } @Test - void customNeo4jTransactionManagerUsingProperties() { - this.contextRunner.withPropertyValues("spring.transaction.default-timeout=30", - "spring.transaction.rollback-on-commit-failure:true").run((context) -> { - Neo4jTransactionManager transactionManager = context.getBean(Neo4jTransactionManager.class); - assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30); - assertThat(transactionManager.isRollbackOnCommitFailure()).isTrue(); + void shouldProvideStaticDatabaseNameProviderIfConfigured() { + contextRunner.withPropertyValues("spring.data.neo4j.database=foobar").run(ctx -> { + assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class); + DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class); + assertThat(databaseNameProvider.getDatabaseSelection()).isEqualTo(DatabaseSelection.byName("foobar")); + }); + } + + @Test + void shouldRespectExistingDatabaseNameProvider() { + contextRunner.withPropertyValues("spring.data.neo4j.database=foobar") + .withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> { + assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class); + DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class); + assertThat(databaseNameProvider.getDatabaseSelection()) + .isEqualTo(DatabaseSelection.byName("whatever")); }); } @Test - void customSessionFactory() { - this.contextRunner.withUserConfiguration(CustomSessionFactory.class).run((context) -> { - assertThat(context).doesNotHaveBean(org.neo4j.ogm.config.Configuration.class); - assertThat(context).hasSingleBean(SessionFactory.class); + void shouldRequireAllNeededClasses() { + contextRunner + .withClassLoader( + new FilteredClassLoader(Neo4jTransactionManager.class, PlatformTransactionManager.class)) + .run(ctx -> assertThat(ctx).doesNotHaveBean(Neo4jClient.class).doesNotHaveBean(Neo4jTemplate.class) + .doesNotHaveBean(Neo4jTransactionManager.class)); + } + + @Test + void shouldCreateNewNeo4jClient() { + contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jClient.class)); + } + + @Test + void shouldNotReplaceExistingNeo4jClient() { + contextRunner.withUserConfiguration(ConfigurationWithExistingClient.class) + .run(ctx -> assertThat(ctx).hasSingleBean(Neo4jClient.class).hasBean("myCustomClient")); + } + + @Test + void shouldCreateNewNeo4jTemplate() { + contextRunner.withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> { + assertThat(ctx).hasSingleBean(Neo4jTemplate.class); + + // Verify that the template uses the provided database name + // provider + Neo4jTemplate template = ctx.getBean(Neo4jTemplate.class); + DatabaseSelectionProvider provider = (DatabaseSelectionProvider) ReflectionTestUtils.getField(template, + "databaseSelectionProvider"); + assertThat(provider).isSameAs(ctx.getBean(DatabaseSelectionProvider.class)); }); } @Test - void customSessionFactoryShouldNotDisableOtherDefaults() { - this.contextRunner.withUserConfiguration(CustomSessionFactory.class).run((context) -> { - assertThat(context).hasSingleBean(SessionFactory.class); - assertThat(context.getBean(SessionFactory.class)).isSameAs(context.getBean("customSessionFactory")); - assertThat(context).hasSingleBean(Neo4jTransactionManager.class); - assertThat(context).doesNotHaveBean(OpenSessionInViewInterceptor.class); + void shouldNotReplaceExistingNeo4jTemplate() { + contextRunner.withUserConfiguration(ConfigurationWithExistingTemplate.class) + .run(ctx -> assertThat(ctx).hasSingleBean(Neo4jOperations.class).hasBean("myCustomOperations")); + } + + @Test + void shouldCreateNewTransactionManager() { + contextRunner.withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> { + assertThat(ctx).hasSingleBean(Neo4jTransactionManager.class); + + // Verify that the transaction manager uses the provided + // database name provider + Neo4jTransactionManager transactionManager = ctx.getBean(Neo4jTransactionManager.class); + DatabaseSelectionProvider provider = (DatabaseSelectionProvider) ReflectionTestUtils + .getField(transactionManager, "databaseSelectionProvider"); + assertThat(provider).isSameAs(ctx.getBean(DatabaseSelectionProvider.class)); }); } @Test - void customConfiguration() { - this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> { - assertThat(context.getBean(org.neo4j.ogm.config.Configuration.class)) - .isSameAs(context.getBean("myConfiguration")); - assertThat(context).hasSingleBean(SessionFactory.class); - assertThat(context).hasSingleBean(org.neo4j.ogm.config.Configuration.class); - }); + void shouldHonourExistingTransactionManager() { + contextRunner.withUserConfiguration(ConfigurationWithExistingTransactionManager.class) + .run(ctx -> assertThat(ctx).hasSingleBean(PlatformTransactionManager.class) + .hasBean("myCustomTransactionManager")); } - @Test - void usesAutoConfigurationPackageToPickUpDomainTypes() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.setClassLoader(new FilteredClassLoader(EmbeddedDriver.class)); - String cityPackage = City.class.getPackage().getName(); - AutoConfigurationPackages.register(context, cityPackage); - context.register(Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class); - try { - context.refresh(); - assertDomainTypesDiscovered(context.getBean(Neo4jMappingContext.class), City.class); + @Configuration + static class ConfigurationWithExistingClient { + + @Bean("myCustomClient") + Neo4jClient neo4jClient(Driver driver) { + return Neo4jClient.create(driver); } - finally { - context.close(); + + } + + @Configuration + static class ConfigurationWithExistingTemplate { + + @Bean("myCustomOperations") + Neo4jOperations neo4jOperations() { + return mock(Neo4jOperations.class); } + } - @Test - void openSessionInViewInterceptorCanBeEnabled() { - this.contextRunner.withPropertyValues("spring.data.neo4j.open-in-view:true") - .run((context) -> assertThat(context).hasSingleBean(OpenSessionInViewInterceptor.class)); - } + @Configuration + static class ConfigurationWithExistingTransactionManager { - @Test - void shouldBeAbleToUseNativeTypesWithBolt() { - this.contextRunner - .withPropertyValues("spring.data.neo4j.uri=bolt://localhost:7687", - "spring.data.neo4j.use-native-types:true") - .withConfiguration( - AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class)) - .run((context) -> assertThat(context).getBean(org.neo4j.ogm.config.Configuration.class) - .hasFieldOrPropertyWithValue("useNativeTypes", true)); - } - - @Test - void shouldFailWhenNativeTypesAreNotAvailable() { - this.contextRunner.withClassLoader(new FilteredClassLoader("org.neo4j.ogm.drivers.bolt.types")) - .withPropertyValues("spring.data.neo4j.uri=bolt://localhost:7687", - "spring.data.neo4j.use-native-types:true") - .withConfiguration( - AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class)) - .run((context) -> { - assertThat(context).hasFailed(); - assertThat(context.getStartupFailure()) - .hasRootCauseInstanceOf(NativeTypesNotAvailableException.class); - }); - } - - @Test - void shouldFailWhenNativeTypesAreNotSupported() { - this.contextRunner - .withPropertyValues("spring.data.neo4j.uri=http://localhost:7474", - "spring.data.neo4j.use-native-types:true") - .withConfiguration( - AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class)) - .run((context) -> { - assertThat(context).hasFailed(); - assertThat(context.getStartupFailure()) - .hasRootCauseInstanceOf(NativeTypesNotSupportedException.class); - }); - } - - @Test - void eventListenersAreAutoRegistered() { - this.contextRunner.withUserConfiguration(EventListenerConfiguration.class).run((context) -> { - Session session = context.getBean(SessionFactory.class).openSession(); - session.notifyListeners(new PersistenceEvent(null, Event.TYPE.PRE_SAVE)); - verify(context.getBean("eventListenerOne", EventListener.class)).onPreSave(any(Event.class)); - verify(context.getBean("eventListenerTwo", EventListener.class)).onPreSave(any(Event.class)); - }); - } - - @Test - void providesARequestScopedBookmarkManagerIfNecessaryAndPossible() { - this.contextRunner.withUserConfiguration(BookmarkManagementEnabledConfiguration.class).run((context) -> { - BeanDefinition bookmarkManagerBean = context.getBeanFactory() - .getBeanDefinition("scopedTarget.bookmarkManager"); - assertThat(bookmarkManagerBean.getScope()).isEqualTo(WebApplicationContext.SCOPE_REQUEST); - }); - } - - @Test - void providesASingletonScopedBookmarkManagerIfNecessaryAndPossible() { - new ApplicationContextRunner().withClassLoader(new FilteredClassLoader(EmbeddedDriver.class)) - .withUserConfiguration(TestConfiguration.class, BookmarkManagementEnabledConfiguration.class) - .withConfiguration( - AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class)) - .run((context) -> { - assertThat(context).hasSingleBean(BookmarkManager.class); - assertThat(context.getBeanDefinitionNames()).doesNotContain("scopedTarget.bookmarkManager"); - }); - } - - @Test - void doesNotProvideABookmarkManagerIfNotPossible() { - this.contextRunner.withClassLoader(new FilteredClassLoader(Caffeine.class, EmbeddedDriver.class)) - .withUserConfiguration(BookmarkManagementEnabledConfiguration.class) - .run((context) -> assertThat(context).doesNotHaveBean(BookmarkManager.class)); - } - - private static void assertDomainTypesDiscovered(Neo4jMappingContext mappingContext, Class... types) { - for (Class type : types) { - assertThat(mappingContext.getPersistentEntity(type)).isNotNull(); + @Bean("myCustomTransactionManager") + PlatformTransactionManager transactionManager() { + return mock(PlatformTransactionManager.class); } - } - - @Configuration(proxyBeanMethods = false) - @EntityScan(basePackageClasses = Country.class) - static class TestConfiguration { } - @Configuration(proxyBeanMethods = false) - static class CustomSessionFactory { + @Configuration + static class ConfigurationWithExistingDatabaseSelectionProvider { @Bean - SessionFactory customSessionFactory() { - return mock(SessionFactory.class); - } - - } - - @Configuration(proxyBeanMethods = false) - static class CustomConfiguration { - - @Bean - org.neo4j.ogm.config.Configuration myConfiguration() { - return new org.neo4j.ogm.config.Configuration.Builder().uri("http://localhost:12345").build(); - } - - } - - @Configuration(proxyBeanMethods = false) - @EnableBookmarkManagement - static class BookmarkManagementEnabledConfiguration { - - } - - @Configuration(proxyBeanMethods = false) - static class EventListenerConfiguration { - - @Bean - EventListener eventListenerOne() { - return mock(EventListener.class); - } - - @Bean - EventListener eventListenerTwo() { - return mock(EventListener.class); + DatabaseSelectionProvider databaseSelectionProvider() { + return () -> DatabaseSelection.byName("whatever"); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jPropertiesTests.java deleted file mode 100644 index afbad5cce2..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jPropertiesTests.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * 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.neo4j; - -import java.util.Base64; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; -import org.neo4j.ogm.config.AutoIndexMode; -import org.neo4j.ogm.config.Configuration; -import org.neo4j.ogm.config.Credentials; -import org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver; - -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.test.context.FilteredClassLoader; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link Neo4jProperties}. - * - * @author Stephane Nicoll - * @author Michael Simons - */ -class Neo4jPropertiesTests { - - private AnnotationConfigApplicationContext context; - - @AfterEach - void close() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - void defaultUseEmbeddedInMemoryIfAvailable() { - Neo4jProperties properties = load(true); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.EMBEDDED_DRIVER, null); - } - - @Test - void defaultUseBoltDriverIfEmbeddedDriverIsNotAvailable() { - Neo4jProperties properties = load(false); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.BOLT_DRIVER, Neo4jProperties.DEFAULT_BOLT_URI); - } - - @Test - void httpUriUseHttpDriver() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=http://localhost:7474"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.HTTP_DRIVER, "http://localhost:7474"); - } - - @Test - void httpsUriUseHttpDriver() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=https://localhost:7474"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.HTTP_DRIVER, "https://localhost:7474"); - } - - @Test - void boltUriUseBoltDriver() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=bolt://localhost:7687"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.BOLT_DRIVER, "bolt://localhost:7687"); - } - - @Test - void fileUriUseEmbeddedServer() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=file://var/tmp/graph.db"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.EMBEDDED_DRIVER, "file://var/tmp/graph.db"); - } - - @Test - void credentialsAreSet() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=http://localhost:7474", - "spring.data.neo4j.username=user", "spring.data.neo4j.password=secret"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.HTTP_DRIVER, "http://localhost:7474"); - assertCredentials(configuration, "user", "secret"); - } - - @Test - void credentialsAreSetFromUri() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=https://user:secret@my-server:7474"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.HTTP_DRIVER, "https://my-server:7474"); - assertCredentials(configuration, "user", "secret"); - } - - @Test - void autoIndexNoneByDefault() { - Neo4jProperties properties = load(true); - Configuration configuration = properties.createConfiguration(); - assertThat(configuration.getAutoIndex()).isEqualTo(AutoIndexMode.NONE); - } - - @Test - void autoIndexCanBeConfigured() { - Neo4jProperties properties = load(true, "spring.data.neo4j.auto-index=validate"); - Configuration configuration = properties.createConfiguration(); - assertThat(configuration.getAutoIndex()).isEqualTo(AutoIndexMode.VALIDATE); - } - - @Test - void embeddedModeDisabledUseBoltUri() { - Neo4jProperties properties = load(true, "spring.data.neo4j.embedded.enabled=false"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.BOLT_DRIVER, Neo4jProperties.DEFAULT_BOLT_URI); - } - - @Test - void embeddedModeWithRelativeLocation() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=file:relative/path/to/my.db"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.EMBEDDED_DRIVER, "file:relative/path/to/my.db"); - } - - @Test - void nativeTypesAreSetToFalseByDefault() { - Neo4jProperties properties = load(true); - Configuration configuration = properties.createConfiguration(); - assertThat(configuration.getUseNativeTypes()).isFalse(); - } - - @Test - void nativeTypesCanBeConfigured() { - Neo4jProperties properties = load(true, "spring.data.neo4j.use-native-types=true"); - Configuration configuration = properties.createConfiguration(); - assertThat(configuration.getUseNativeTypes()).isTrue(); - } - - private static void assertDriver(Configuration actual, String driver, String uri) { - assertThat(actual).isNotNull(); - assertThat(actual.getDriverClassName()).isEqualTo(driver); - assertThat(actual.getURI()).isEqualTo(uri); - } - - private static void assertCredentials(Configuration actual, String username, String password) { - Credentials credentials = actual.getCredentials(); - if (username == null && password == null) { - assertThat(credentials).isNull(); - } - else { - assertThat(credentials).isNotNull(); - Object content = credentials.credentials(); - assertThat(content).isInstanceOf(String.class); - String[] auth = new String(Base64.getDecoder().decode((String) content)).split(":"); - assertThat(auth).containsExactly(username, password); - } - } - - Neo4jProperties load(boolean embeddedAvailable, String... environment) { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - if (!embeddedAvailable) { - ctx.setClassLoader(new FilteredClassLoader(EmbeddedDriver.class)); - } - TestPropertyValues.of(environment).applyTo(ctx); - ctx.register(TestConfiguration.class); - ctx.refresh(); - this.context = ctx; - return this.context.getBean(Neo4jProperties.class); - } - - @org.springframework.context.annotation.Configuration(proxyBeanMethods = false) - @EnableConfigurationProperties(Neo4jProperties.class) - static class TestConfiguration { - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationIntegrationTests.java new file mode 100644 index 0000000000..f6a8592c15 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationIntegrationTests.java @@ -0,0 +1,76 @@ +/* + * 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.neo4j; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository; +import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.Neo4jContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test to ensure that the properties get read and applied during the auto-configuration. + * + * @author Michael J. Simons + */ +@SpringBootTest(properties = "spring.data.neo4j.repositories.type=imperative") +@Testcontainers(disabledWithoutDocker = true) +public class Neo4jRepositoriesAutoConfigurationIntegrationTests { + + @Container + private static Neo4jContainer neo4jServer = new Neo4jContainer<>("neo4j:4.0"); + + @DynamicPropertySource + static void neo4jProperties(DynamicPropertyRegistry registry) { + + registry.add("spring.neo4j.uri", neo4jServer::getBoltUrl); + registry.add("spring.neo4j.authentication.username", () -> "neo4j"); + registry.add("spring.neo4j.authentication.password", neo4jServer::getAdminPassword); + } + + private final CountryRepository countryRepository; + + @Autowired + Neo4jRepositoriesAutoConfigurationIntegrationTests(CountryRepository countryRepository) { + this.countryRepository = countryRepository; + } + + @Test + void ensureRepositoryIsReady() { + + assertThat(countryRepository.count()).isEqualTo(0); + } + + @Configuration + @EnableNeo4jRepositories(basePackageClasses = CountryRepository.class) + @ImportAutoConfiguration({ Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class, + Neo4jRepositoriesAutoConfiguration.class }) + static class TestConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java index c1539936da..c8e0ac302d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java @@ -16,25 +16,31 @@ package org.springframework.boot.autoconfigure.data.neo4j; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -import org.neo4j.ogm.session.SessionFactory; - -import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.mockito.Mockito; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.autoconfigure.data.alt.neo4j.CityNeo4jRepository; import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; import org.springframework.boot.autoconfigure.data.neo4j.city.City; import org.springframework.boot.autoconfigure.data.neo4j.city.CityRepository; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.autoconfigure.data.neo4j.city.ReactiveCityRepository; +import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository; +import org.springframework.boot.autoconfigure.data.neo4j.country.ReactiveCountryRepository; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.mapping.Neo4jMappingContext; +import org.springframework.data.neo4j.core.Neo4jClient; +import org.springframework.data.neo4j.core.ReactiveNeo4jClient; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; +import org.springframework.data.neo4j.repository.support.ReactiveNeo4jRepositoryFactoryBean; +import reactor.core.publisher.Flux; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** * Tests for {@link Neo4jRepositoriesAutoConfiguration}. @@ -44,50 +50,88 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; * @author Michael Hunger * @author Vince Bickers * @author Stephane Nicoll + * @author Michael J. Simons */ class Neo4jRepositoriesAutoConfigurationTests { - private AnnotationConfigApplicationContext context; + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withUserConfiguration(MockedDriverConfiguration.class) + .withConfiguration(AutoConfigurations.of(Neo4jRepositoriesAutoConfigurationTests.class, + Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class)); - @AfterEach - void close() { - this.context.close(); + @Test + void defaultRepositoryConfigurationShouldWork() { + this.contextRunner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.data.neo4j.repositories.type=imperative") + .run(ctx -> assertThat(ctx).hasSingleBean(CityRepository.class)); } @Test - void testDefaultRepositoryConfiguration() { - prepareApplicationContext(TestConfiguration.class); - assertThat(this.context.getBean(CityRepository.class)).isNotNull(); - Neo4jMappingContext mappingContext = this.context.getBean(Neo4jMappingContext.class); - assertThat(mappingContext.getPersistentEntity(City.class)).isNotNull(); + void repositoryConfigurationShouldNotCreateArbitraryRepos() { + this.contextRunner.withUserConfiguration(EmptyConfiguration.class) + .withPropertyValues("spring.data.neo4j.repositories.type=imperative").run(ctx -> assertThat(ctx) + .hasSingleBean(Neo4jTransactionManager.class).doesNotHaveBean(Neo4jRepository.class)); } @Test - void testNoRepositoryConfiguration() { - prepareApplicationContext(EmptyConfiguration.class); - assertThat(this.context.getBean(SessionFactory.class)).isNotNull(); - } + void configurationOfRepositoryTypeShouldWork() { + this.contextRunner.withPropertyValues("spring.data.neo4j.repositories.type=none") + .withUserConfiguration(TestConfiguration.class).withClassLoader(new FilteredClassLoader(Flux.class)) + .run(ctx -> assertThat(ctx).doesNotHaveBean(Neo4jTransactionManager.class) + .doesNotHaveBean(ReactiveNeo4jClient.class).doesNotHaveBean(Neo4jRepository.class)); - @Test - void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { - prepareApplicationContext(CustomizedConfiguration.class); - assertThat(this.context.getBean(CityNeo4jRepository.class)).isNotNull(); + this.contextRunner.withPropertyValues("spring.data.neo4j.repositories.type=imperative") + .withUserConfiguration(TestConfiguration.class) + .run(ctx -> assertThat(ctx).hasSingleBean(Neo4jTransactionManager.class) + .hasSingleBean(Neo4jClient.class).doesNotHaveBean(ReactiveNeo4jRepository.class)); } @Test void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() { - prepareApplicationContext(SortOfInvalidCustomConfiguration.class); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.context.getBean(CityRepository.class)); + this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class) + .withPropertyValues("spring.data.neo4j.repositories.type=imperative").run(ctx -> assertThat(ctx) + .hasSingleBean(Neo4jTransactionManager.class).doesNotHaveBean(Neo4jRepository.class)); } - private void prepareApplicationContext(Class... configurationClasses) { - this.context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("spring.data.neo4j.uri=http://localhost:9797").applyTo(this.context); - this.context.register(configurationClasses); - this.context.register(Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - this.context.refresh(); + @Test + void shouldRespectAtEnableNeo4jRepositories() { + this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomRepositoryScan.class) + .withPropertyValues("spring.data.neo4j.repositories.type=imperative") + .run(ctx -> assertThat(ctx).doesNotHaveBean(CityRepository.class) + .doesNotHaveBean(ReactiveCityRepository.class).hasSingleBean(CountryRepository.class) + .doesNotHaveBean(ReactiveCountryRepository.class)); + } + + @Test + void shouldRespectAtEnableReactiveNeo4jRepositories() { + this.contextRunner + .withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomReactiveRepositoryScan.class) + .withPropertyValues("spring.data.neo4j.repositories.type=reactive") + .run(ctx -> assertThat(ctx).doesNotHaveBean(CityRepository.class) + .doesNotHaveBean(ReactiveCityRepository.class).doesNotHaveBean(CountryRepository.class) + .hasSingleBean(ReactiveCountryRepository.class)); + } + + @Configuration(proxyBeanMethods = false) + @EnableNeo4jRepositories(basePackageClasses = CountryRepository.class) + static class WithCustomRepositoryScan { + + } + + @Configuration(proxyBeanMethods = false) + @EnableReactiveNeo4jRepositories(basePackageClasses = ReactiveCountryRepository.class) + static class WithCustomReactiveRepositoryScan { + + } + + @Configuration(proxyBeanMethods = false) + static class WithFakeEnabledReactiveNeo4jRepositories { + + @Bean + ReactiveNeo4jRepositoryFactoryBean reactiveNeo4jRepositoryFactoryBean() { + return Mockito.mock(ReactiveNeo4jRepositoryFactoryBean.class); + } + } @Configuration(proxyBeanMethods = false) @@ -103,14 +147,6 @@ class Neo4jRepositoriesAutoConfigurationTests { } @Configuration(proxyBeanMethods = false) - @TestAutoConfigurationPackage(Neo4jRepositoriesAutoConfigurationTests.class) - @EnableNeo4jRepositories(basePackageClasses = CityNeo4jRepository.class) - static class CustomizedConfiguration { - - } - - @Configuration(proxyBeanMethods = false) - // To not find any repositories @EnableNeo4jRepositories("foo.bar") @TestAutoConfigurationPackage(Neo4jRepositoriesAutoConfigurationTests.class) static class SortOfInvalidCustomConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/ReactiveNeo4jDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/ReactiveNeo4jDataAutoConfigurationTests.java new file mode 100644 index 0000000000..dfdf47bd70 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/ReactiveNeo4jDataAutoConfigurationTests.java @@ -0,0 +1,197 @@ +/* + * 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.neo4j; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.DatabaseSelection; +import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; +import org.springframework.data.neo4j.core.ReactiveNeo4jClient; +import org.springframework.data.neo4j.core.ReactiveNeo4jOperations; +import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; +import org.springframework.data.neo4j.core.convert.Neo4jConversions; +import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.transaction.ReactiveTransactionManager; + +/** + * @author Michael J. Simons + */ +class ReactiveNeo4jDataAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.data.neo4j.repositories.type=reactive") + .withUserConfiguration(MockedDriverConfiguration.class) + .withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class)); + + @Test + void shouldProvideConversions() { + contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jConversions.class)); + } + + @Test + void shouldProvideDefaultDatabaseNameProvider() { + contextRunner.run(ctx -> { + assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class); + ReactiveDatabaseSelectionProvider databaseNameProvider = ctx + .getBean(ReactiveDatabaseSelectionProvider.class); + assertThat(databaseNameProvider).isSameAs(ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider()); + }); + } + + @Test + void shouldProvideStaticDatabaseNameProviderIfConfigured() { + contextRunner.withPropertyValues("spring.data.neo4j.database=foobar").run(ctx -> { + assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class); + ReactiveDatabaseSelectionProvider databaseNameProvider = ctx + .getBean(ReactiveDatabaseSelectionProvider.class); + StepVerifier.create(databaseNameProvider.getDatabaseSelection().map(DatabaseSelection::getValue)) + .expectNext("foobar").expectComplete(); + }); + } + + @Test + void shouldRespectExistingDatabaseNameProvider() { + contextRunner.withPropertyValues("spring.data.neo4j.database=foobar") + .withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class).run(ctx -> { + assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class); + ReactiveDatabaseSelectionProvider databaseNameProvider = ctx + .getBean(ReactiveDatabaseSelectionProvider.class); + StepVerifier.create(databaseNameProvider.getDatabaseSelection().map(DatabaseSelection::getValue)) + .expectNext("whatever").expectComplete(); + }); + } + + @Test + void shouldRequireAllNeededClasses() { + contextRunner + .withClassLoader(new FilteredClassLoader(ReactiveNeo4jTransactionManager.class, + ReactiveTransactionManager.class, Flux.class)) + .run(ctx -> assertThat(ctx).doesNotHaveBean(ReactiveNeo4jClient.class) + .doesNotHaveBean(ReactiveNeo4jTemplate.class) + .doesNotHaveBean(ReactiveNeo4jTransactionManager.class)); + } + + @Test + void shouldCreateNewReactiveNeo4jClient() { + contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(ReactiveNeo4jClient.class)); + } + + @Test + void shouldNotReplaceExistingReactiveNeo4jClient() { + contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveClient.class) + .run(ctx -> assertThat(ctx).hasSingleBean(ReactiveNeo4jClient.class).hasBean("myCustomReactiveClient")); + } + + @Test + void shouldCreateNewNeo4jTemplate() { + contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class) + .run(ctx -> { + assertThat(ctx).hasSingleBean(ReactiveNeo4jTemplate.class); + + // Verify that the template uses the provided database name + // provider + ReactiveNeo4jTemplate template = ctx.getBean(ReactiveNeo4jTemplate.class); + ReactiveDatabaseSelectionProvider provider = (ReactiveDatabaseSelectionProvider) ReflectionTestUtils + .getField(template, "databaseSelectionProvider"); + assertThat(provider).isSameAs(ctx.getBean(ReactiveDatabaseSelectionProvider.class)); + }); + } + + @Test + void shouldNotReplaceExistingNeo4jTemplate() { + contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveTemplate.class).run(ctx -> assertThat(ctx) + .hasSingleBean(ReactiveNeo4jOperations.class).hasBean("myCustomReactiveOperations")); + } + + @Test + void shouldCreateNewTransactionManager() { + contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class) + .run(ctx -> { + assertThat(ctx).hasSingleBean(ReactiveNeo4jTransactionManager.class); + + // Verify that the transaction manager uses the provided + // database name provider + ReactiveNeo4jTransactionManager transactionManager = ctx + .getBean(ReactiveNeo4jTransactionManager.class); + ReactiveDatabaseSelectionProvider provider = (ReactiveDatabaseSelectionProvider) ReflectionTestUtils + .getField(transactionManager, "databaseSelectionProvider"); + assertThat(provider).isSameAs(ctx.getBean(ReactiveDatabaseSelectionProvider.class)); + }); + } + + @Test + void shouldHonourExistingTransactionManager() { + contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveTransactionManager.class) + .run(ctx -> assertThat(ctx).hasSingleBean(ReactiveTransactionManager.class) + .hasBean("myCustomReactiveTransactionManager")); + } + + @Configuration + static class ConfigurationWithExistingReactiveClient { + + @Bean("myCustomReactiveClient") + ReactiveNeo4jClient neo4jClient(Driver driver) { + return ReactiveNeo4jClient.create(driver); + } + + } + + @Configuration + static class ConfigurationWithExistingReactiveTemplate { + + @Bean("myCustomReactiveOperations") + ReactiveNeo4jOperations neo4jOperations() { + return mock(ReactiveNeo4jOperations.class); + } + + } + + @Configuration + static class ConfigurationWithExistingReactiveTransactionManager { + + @Bean("myCustomReactiveTransactionManager") + ReactiveTransactionManager transactionManager() { + return mock(ReactiveTransactionManager.class); + } + + } + + @Configuration + static class ConfigurationWithExistingReactiveDatabaseSelectionProvider { + + @Bean + ReactiveDatabaseSelectionProvider databaseNameProvider() { + return () -> Mono.just(DatabaseSelection.byName("whatever")); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/City.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/City.java index 1ae1b828c0..27f1db193f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/City.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/City.java @@ -18,13 +18,12 @@ package org.springframework.boot.autoconfigure.data.neo4j.city; import java.io.Serializable; -import org.neo4j.ogm.annotation.GeneratedValue; -import org.neo4j.ogm.annotation.Id; -import org.neo4j.ogm.annotation.NodeEntity; - import org.springframework.boot.autoconfigure.data.neo4j.country.Country; +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; -@NodeEntity +@Node public class City implements Serializable { private static final long serialVersionUID = 1L; @@ -41,9 +40,6 @@ public class City implements Serializable { private String map; - public City() { - } - public City(String name, Country country) { this.name = name; this.country = country; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/ReactiveCityRepository.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/ReactiveCityRepository.java new file mode 100644 index 0000000000..215d9f1716 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/ReactiveCityRepository.java @@ -0,0 +1,26 @@ +/* + * 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.neo4j.city; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; + +public interface ReactiveCityRepository extends ReactiveNeo4jRepository { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/Country.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/Country.java index d1e2631891..34c504c098 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/Country.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/Country.java @@ -16,13 +16,13 @@ package org.springframework.boot.autoconfigure.data.neo4j.country; +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + import java.io.Serializable; -import org.neo4j.ogm.annotation.GeneratedValue; -import org.neo4j.ogm.annotation.Id; -import org.neo4j.ogm.annotation.NodeEntity; - -@NodeEntity +@Node public class Country implements Serializable { private static final long serialVersionUID = 1L; @@ -33,9 +33,6 @@ public class Country implements Serializable { private String name; - public Country() { - } - public Country(String name) { this.name = name; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/ReactiveCountryRepository.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/ReactiveCountryRepository.java new file mode 100644 index 0000000000..790aa84d94 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/ReactiveCountryRepository.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.neo4j.country; + +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; + +public interface ReactiveCountryRepository extends ReactiveNeo4jRepository { + +} diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 489ddb4d00..a79f8abba8 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1177,19 +1177,6 @@ bom { ] } } - library("Neo4j OGM", "3.2.12") { - group("org.neo4j") { - modules = [ - "neo4j-ogm-api", - "neo4j-ogm-bolt-driver", - "neo4j-ogm-bolt-native-types", - "neo4j-ogm-core", - "neo4j-ogm-embedded-driver", - "neo4j-ogm-embedded-native-types", - "neo4j-ogm-http-driver" - ] - } - } library("Netty", "4.1.50.Final") { group("io.netty") { imports = [ diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestIntegrationTests.java index 90f06dc040..c10b33a03c 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestIntegrationTests.java @@ -19,7 +19,8 @@ package org.springframework.boot.test.autoconfigure.data.neo4j; import java.time.Duration; import org.junit.jupiter.api.Test; -import org.neo4j.ogm.session.Session; + +import org.springframework.data.neo4j.core.Neo4jTemplate; import org.testcontainers.containers.Neo4jContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -49,7 +50,7 @@ class DataNeo4jTestIntegrationTests { .withStartupTimeout(Duration.ofMinutes(10)); @Autowired - private Session session; + private Neo4jTemplate neo4jTemplate; @Autowired private ExampleRepository exampleRepository; @@ -59,17 +60,16 @@ class DataNeo4jTestIntegrationTests { @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { - registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl); + registry.add("spring.neo4j.uri", neo4j::getBoltUrl); } @Test void testRepository() { - ExampleGraph exampleGraph = new ExampleGraph(); - exampleGraph.setDescription("Look, new @DataNeo4jTest!"); + ExampleGraph exampleGraph = new ExampleGraph("Look, new @DataNeo4jTest!"); assertThat(exampleGraph.getId()).isNull(); ExampleGraph savedGraph = this.exampleRepository.save(exampleGraph); assertThat(savedGraph.getId()).isNotNull(); - assertThat(this.session.countEntitiesOfType(ExampleGraph.class)).isEqualTo(1); + assertThat(this.neo4jTemplate.count(ExampleGraph.class)).isEqualTo(1); } @Test diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java index cd9c80a3b8..b4efc9eac0 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java @@ -49,7 +49,7 @@ class DataNeo4jTestPropertiesIntegrationTests { @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { - registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl); + registry.add("spring.neo4j.uri", neo4j::getBoltUrl); } @Test diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestWithIncludeFilterIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestWithIncludeFilterIntegrationTests.java index 7533e60b52..a8812f06cf 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestWithIncludeFilterIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestWithIncludeFilterIntegrationTests.java @@ -50,7 +50,7 @@ class DataNeo4jTestWithIncludeFilterIntegrationTests { @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { - registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl); + registry.add("spring.neo4j.uri", neo4j::getBoltUrl); } @Test diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTypeExcludeFilterTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTypeExcludeFilterTests.java new file mode 100644 index 0000000000..dda71f1dd4 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTypeExcludeFilterTests.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019-2020 "Neo4j," + * Neo4j Sweden AB [https://neo4j.com] + * + * This file is part of Neo4j. + * + * 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.test.autoconfigure.data.neo4j; + +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Michael J. Simons + */ +class DataNeo4jTypeExcludeFilterTests { + + private MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + + @Test + void matchWithExcludeFilter() throws Exception { + DataNeo4jTypeExcludeFilter filter = new DataNeo4jTypeExcludeFilter(WithExcludeFilter.class); + assertThat(excludes(filter, ExampleService.class)).isTrue(); + assertThat(excludes(filter, ExampleRepository.class)).isTrue(); + } + + @Test + void matchWithoutExcludeFilter() throws Exception { + DataNeo4jTypeExcludeFilter filter = new DataNeo4jTypeExcludeFilter(WithoutExcludeFilter.class); + assertThat(excludes(filter, ExampleService.class)).isTrue(); + assertThat(excludes(filter, ExampleRepository.class)).isFalse(); + } + + @DataNeo4jTest( + excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ExampleRepository.class)) + static class WithExcludeFilter { + + } + + @DataNeo4jTest + static class WithoutExcludeFilter { + + } + + private boolean excludes(DataNeo4jTypeExcludeFilter filter, Class type) throws IOException { + MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(type.getName()); + return filter.match(metadataReader, this.metadataReaderFactory); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleGraph.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleGraph.java index 41d3fb2aa2..4c3736a2d4 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleGraph.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleGraph.java @@ -16,17 +16,18 @@ package org.springframework.boot.test.autoconfigure.data.neo4j; -import org.neo4j.ogm.annotation.GeneratedValue; -import org.neo4j.ogm.annotation.Id; -import org.neo4j.ogm.annotation.NodeEntity; -import org.neo4j.ogm.annotation.Property; +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; +import org.springframework.data.neo4j.core.schema.Property; /** * Example graph used with {@link DataNeo4jTest @DataNeo4jTest} tests. * * @author Eddú Meléndez + * @author Michael J. Simons */ -@NodeEntity +@Node public class ExampleGraph { @Id @@ -36,6 +37,10 @@ public class ExampleGraph { @Property private String description; + public ExampleGraph(String description) { + this.description = description; + } + public Long getId() { return this.id; } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleService.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleService.java index 58e1493848..619299a77b 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleService.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleService.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -16,26 +16,26 @@ package org.springframework.boot.test.autoconfigure.data.neo4j; -import org.neo4j.ogm.session.Session; - +import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.stereotype.Service; /** * Example service used with {@link DataNeo4jTest @DataNeo4jTest} tests. * * @author Eddú Meléndez + * @author Michael J. Simons */ @Service public class ExampleService { - private final Session session; + private final Neo4jTemplate neo4jTemplate; - public ExampleService(Session session) { - this.session = session; + public ExampleService(Neo4jTemplate neo4jTemplate) { + this.neo4jTemplate = neo4jTemplate; } public boolean hasNode(Class clazz) { - return this.session.countEntitiesOfType(clazz) == 1; + return this.neo4jTemplate.count(clazz) == 1; } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ReactiveDataNeo4jIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ReactiveDataNeo4jIntegrationTests.java new file mode 100644 index 0000000000..c85a900c4b --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ReactiveDataNeo4jIntegrationTests.java @@ -0,0 +1,100 @@ +/* + * 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.test.autoconfigure.data.neo4j; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; +import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.ReactiveTransactionManager; +import org.testcontainers.containers.Neo4jContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.time.Duration; + +import org.neo4j.driver.AccessMode; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.neo4j.driver.SessionConfig; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +/** + * Integration tests for the reactive SDN/RX Neo4j test slice. + * + * @author Michael J. Simons + * @since 2.4.0 + */ +@DataNeo4jTest +@Testcontainers(disabledWithoutDocker = true) +class ReactiveDataNeo4jIntegrationTests { + + @Container + static final Neo4jContainer neo4j = new Neo4jContainer<>("neo4j:4.0").withoutAuthentication() + .withStartupTimeout(Duration.ofMinutes(10)); + + @DynamicPropertySource + static void neo4jProperties(DynamicPropertyRegistry registry) { + registry.add("spring.neo4j.uri", neo4j::getBoltUrl); + } + + @Autowired + private Driver driver; + + @Autowired + private ReactiveNeo4jTemplate neo4jTemplate; + + @Autowired + private ApplicationContext applicationContext; + + @Test + void testTemplate() { + + Mono.just(new ExampleGraph("Look, new @DataNeo4jTest with reactive!")).flatMap(neo4jTemplate::save) + .as(StepVerifier::create).expectNextCount(1).verifyComplete(); + + try (Session session = driver.session(SessionConfig.builder().withDefaultAccessMode(AccessMode.READ).build())) { + long cnt = session.run("MATCH (n:ExampleGraph) RETURN count(n) as cnt").single().get("cnt").asLong(); + assertThat(cnt).isEqualTo(1L); + } + } + + @Test + void didNotInjectExampleService() { + assertThatExceptionOfType(NoSuchBeanDefinitionException.class) + .isThrownBy(() -> this.applicationContext.getBean(ExampleService.class)); + } + + @Test + void didProvideOnlyReactiveTransactionManager() { + + assertThat(this.applicationContext.getBean(ReactiveTransactionManager.class)) + .isInstanceOf(ReactiveNeo4jTransactionManager.class); + assertThatExceptionOfType(NoSuchBeanDefinitionException.class) + .isThrownBy(() -> this.applicationContext.getBean(PlatformTransactionManager.class)); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/build.gradle b/spring-boot-project/spring-boot-tools/spring-boot-test-support/build.gradle index 7985225b9b..9c282c20d2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/build.gradle +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/build.gradle @@ -14,7 +14,6 @@ dependencies { compileOnly("org.junit.jupiter:junit-jupiter") compileOnly("org.junit.platform:junit-platform-engine") compileOnly("org.mockito:mockito-core") - compileOnly("org.neo4j:neo4j-ogm-core") compileOnly("org.springframework:spring-context") compileOnly("org.springframework.data:spring-data-redis") compileOnly("org.testcontainers:testcontainers") diff --git a/spring-boot-project/spring-boot/build.gradle b/spring-boot-project/spring-boot/build.gradle index cf1be0543a..06f8f6d07c 100644 --- a/spring-boot-project/spring-boot/build.gradle +++ b/spring-boot-project/spring-boot/build.gradle @@ -56,7 +56,6 @@ dependencies { optional("org.hibernate.validator:hibernate-validator") optional("org.jboss:jboss-transaction-spi") optional("org.liquibase:liquibase-core") - optional("org.neo4j:neo4j-ogm-core") optional("org.slf4j:jul-to-slf4j") optional("org.slf4j:slf4j-api") optional("org.springframework:spring-messaging") diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-neo4j/src/main/java/smoketest/data/neo4j/Customer.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-neo4j/src/main/java/smoketest/data/neo4j/Customer.java index 52b6d59f32..b9663eece4 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-neo4j/src/main/java/smoketest/data/neo4j/Customer.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-neo4j/src/main/java/smoketest/data/neo4j/Customer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -16,11 +16,11 @@ package smoketest.data.neo4j; -import org.neo4j.ogm.annotation.GeneratedValue; -import org.neo4j.ogm.annotation.Id; -import org.neo4j.ogm.annotation.NodeEntity; +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; -@NodeEntity +@Node public class Customer { @Id From 9bc71fe44fb69f3971edcf7456cf7fc892778870 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Wed, 29 Jul 2020 10:54:02 +0200 Subject: [PATCH 4/4] Polish "Upgrade to Spring Data Neo4j 6" See gh-22299 --- .../neo4j/Neo4jDataAutoConfiguration.java | 54 ++++- .../data/neo4j/Neo4jDataConfiguration.java | 88 -------- .../data/neo4j/Neo4jDataProperties.java | 6 +- ...> Neo4jReactiveDataAutoConfiguration.java} | 48 ++--- ...eactiveRepositoriesAutoConfiguration.java} | 15 +- ...> Neo4jReactiveRepositoriesRegistrar.java} | 9 +- .../Neo4jRepositoriesAutoConfiguration.java | 27 ++- .../neo4j/Neo4jRepositoriesConfiguration.java | 41 ---- ...r.java => Neo4jRepositoriesRegistrar.java} | 10 +- .../boot/autoconfigure/domain/EntityScan.java | 1 - ...itional-spring-configuration-metadata.json | 68 +++++- .../main/resources/META-INF/spring.factories | 2 + ...o4jRepositoriesAutoConfigurationTests.java | 15 +- .../data/neo4j/MockedDriverConfiguration.java | 14 +- .../Neo4jDataAutoConfigurationTests.java | 152 +++++--------- ...o4jReactiveDataAutoConfigurationTests.java | 145 +++++++++++++ ...iveRepositoriesAutoConfigurationTests.java | 112 ++++++++++ ...riesAutoConfigurationIntegrationTests.java | 21 +- ...o4jRepositoriesAutoConfigurationTests.java | 63 ++---- ...activeNeo4jDataAutoConfigurationTests.java | 197 ------------------ .../autoconfigure/data/neo4j/city/City.java | 2 +- .../neo4j/city/ReactiveCityRepository.java | 5 +- .../data/neo4j/country/Country.java | 6 +- .../country/ReactiveCountryRepository.java | 2 +- .../src/docs/asciidoc/howto.adoc | 2 +- .../docs/asciidoc/spring-boot-features.adoc | 41 ---- .../main/resources/META-INF/spring.factories | 3 + .../neo4j/DataNeo4jTestIntegrationTests.java | 13 +- ...taNeo4jTestPropertiesIntegrationTests.java | 6 +- ...ataNeo4jTestReactiveIntegrationTests.java} | 50 ++--- ...TestWithIncludeFilterIntegrationTests.java | 6 +- .../DataNeo4jTypeExcludeFilterTests.java | 69 ------ .../data/neo4j/ExampleGraph.java | 3 +- .../data/neo4j/ExampleReactiveRepository.java | 28 +++ .../src/main/resources/application.properties | 1 - 35 files changed, 593 insertions(+), 732 deletions(-) delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataConfiguration.java rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/{Neo4jReactiveDataConfiguration.java => Neo4jReactiveDataAutoConfiguration.java} (63%) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/{Neo4jReactiveRepositoriesConfiguration.java => Neo4jReactiveRepositoriesAutoConfiguration.java} (74%) rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/{Neo4jReactiveRepositoriesConfigureRegistrar.java => Neo4jReactiveRepositoriesRegistrar.java} (82%) delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfiguration.java rename spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/{Neo4jRepositoriesConfigureRegistrar.java => Neo4jRepositoriesRegistrar.java} (81%) create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataAutoConfigurationTests.java create mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesAutoConfigurationTests.java delete mode 100644 spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/ReactiveNeo4jDataAutoConfigurationTests.java rename spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/{ReactiveDataNeo4jIntegrationTests.java => DataNeo4jTestReactiveIntegrationTests.java} (67%) delete mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTypeExcludeFilterTests.java create mode 100644 spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleReactiveRepository.java diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java index f50ecd55a0..cd5f3a917b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java @@ -20,42 +20,52 @@ import java.util.Set; import org.neo4j.driver.Driver; +import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureBefore; 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.domain.EntityScanner; import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; +import org.springframework.data.neo4j.config.Neo4jDefaultCallbacksRegistrar; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.Neo4jClient; +import org.springframework.data.neo4j.core.Neo4jOperations; +import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.data.neo4j.core.convert.Neo4jConversions; import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext; import org.springframework.data.neo4j.core.schema.Node; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; +import org.springframework.transaction.PlatformTransactionManager; /** - * {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j. Automatic - * configuration of base infrastructure that imports configuration for both imperative and - * reactive Neo4j repositories. + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j. * * @author Michael Hunger * @author Josh Long * @author Vince Bickers * @author Stephane Nicoll * @author Kazuki Shimizu - * @author Michael J Simons + * @author Michael J. Simons * @since 1.4.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnBean(Driver.class) +@ConditionalOnClass({ Driver.class, Neo4jTransactionManager.class, PlatformTransactionManager.class }) @EnableConfigurationProperties(Neo4jDataProperties.class) -@AutoConfigureAfter(Neo4jAutoConfiguration.class) +@ConditionalOnBean(Driver.class) @AutoConfigureBefore(TransactionAutoConfiguration.class) -@Import({ Neo4jDataConfiguration.class, Neo4jReactiveDataConfiguration.class }) +@AutoConfigureAfter(Neo4jAutoConfiguration.class) +@Import(Neo4jDefaultCallbacksRegistrar.class) public class Neo4jDataAutoConfiguration { @Bean @@ -74,4 +84,34 @@ public class Neo4jDataAutoConfiguration { return context; } + @Bean + @ConditionalOnMissingBean + public DatabaseSelectionProvider databaseSelectionProvider(Neo4jDataProperties properties) { + String database = properties.getDatabase(); + return (database != null) ? DatabaseSelectionProvider.createStaticDatabaseSelectionProvider(database) + : DatabaseSelectionProvider.getDefaultSelectionProvider(); + } + + @Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME) + @ConditionalOnMissingBean + public Neo4jClient neo4jClient(Driver driver) { + return Neo4jClient.create(driver); + } + + @Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME) + @ConditionalOnMissingBean(Neo4jOperations.class) + public Neo4jTemplate neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext, + DatabaseSelectionProvider databaseNameProvider) { + return new Neo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider); + } + + @Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME) + @ConditionalOnMissingBean(PlatformTransactionManager.class) + public Neo4jTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider, + ObjectProvider optionalCustomizers) { + Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(driver, databaseNameProvider); + optionalCustomizers.ifAvailable((customizer) -> customizer.customize(transactionManager)); + return transactionManager; + } + } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataConfiguration.java deleted file mode 100644 index 070ab1471c..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataConfiguration.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * 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.neo4j; - -import org.neo4j.driver.Driver; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; -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.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; -import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.core.env.Environment; -import org.springframework.data.neo4j.config.Neo4jDefaultCallbacksRegistrar; -import org.springframework.data.neo4j.core.DatabaseSelectionProvider; -import org.springframework.data.neo4j.core.Neo4jClient; -import org.springframework.data.neo4j.core.Neo4jOperations; -import org.springframework.data.neo4j.core.Neo4jTemplate; -import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext; -import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; -import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; -import org.springframework.transaction.PlatformTransactionManager; - -/** - * Internal configuration of Neo4j client and transaction manager. - * - * @author Michael J. Simons - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ Neo4jTransactionManager.class, PlatformTransactionManager.class }) -@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.IMPERATIVE) -@AutoConfigureAfter(Neo4jAutoConfiguration.class) -@AutoConfigureBefore(Neo4jRepositoriesConfiguration.class) -@Import(Neo4jDefaultCallbacksRegistrar.class) -class Neo4jDataConfiguration { - - @Bean("databaseSelectionProvider") - @ConditionalOnMissingBean - DatabaseSelectionProvider defaultSelectionProvider(Environment environment) { - String database = environment.getProperty("spring.data.neo4j.database"); - if (database != null) { - return DatabaseSelectionProvider.createStaticDatabaseSelectionProvider(database); - } - return DatabaseSelectionProvider.getDefaultSelectionProvider(); - } - - @Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME) - @ConditionalOnMissingBean - Neo4jClient neo4jClient(Driver driver) { - return Neo4jClient.create(driver); - } - - @Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME) - @ConditionalOnMissingBean(Neo4jOperations.class) - Neo4jTemplate neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext, - DatabaseSelectionProvider databaseNameProvider) { - return new Neo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider); - } - - @Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME) - @ConditionalOnMissingBean(PlatformTransactionManager.class) - Neo4jTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider, - ObjectProvider optionalCustomizers) { - Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(driver, databaseNameProvider); - optionalCustomizers.ifAvailable((customizer) -> customizer.customize(transactionManager)); - return transactionManager; - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataProperties.java index dad06eca71..ea1c190524 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataProperties.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataProperties.java @@ -17,7 +17,6 @@ package org.springframework.boot.autoconfigure.data.neo4j; import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.data.neo4j.core.DatabaseSelectionProvider; /** * Configuration properties for Spring Data Neo4j. @@ -29,10 +28,7 @@ import org.springframework.data.neo4j.core.DatabaseSelectionProvider; public class Neo4jDataProperties { /** - * A statically configured database. This property is only applicable when connecting - * against a 4.0 cluster or server and will lead to errors if used with a prior - * version of Neo4j. Leave this null (the default) to indicate that you like the - * server to decide the default database to use. + * Database name to use. By default, the server decides the default database to use. */ private String database; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataAutoConfiguration.java similarity index 63% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataConfiguration.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataAutoConfiguration.java index c43fb455eb..58bcb406d2 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataAutoConfiguration.java @@ -20,17 +20,13 @@ import org.neo4j.driver.Driver; import reactor.core.publisher.Flux; import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType; -import org.springframework.boot.autoconfigure.data.RepositoryType; -import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.core.annotation.Order; import org.springframework.data.neo4j.config.Neo4jDefaultReactiveCallbacksRegistrar; import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; import org.springframework.data.neo4j.core.ReactiveNeo4jClient; @@ -42,49 +38,45 @@ import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryC import org.springframework.transaction.ReactiveTransactionManager; /** - * Internal configuration for the reactive Neo4j client. + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's reactive Neo4j + * support. * * @author Michael J. Simons + * @author Stephane Nicoll + * @since 2.4.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ ReactiveNeo4jTransactionManager.class, ReactiveTransactionManager.class, Flux.class }) -@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.REACTIVE) -@AutoConfigureAfter(Neo4jAutoConfiguration.class) -@AutoConfigureBefore(Neo4jReactiveRepositoriesConfiguration.class) +@ConditionalOnClass({ Driver.class, ReactiveNeo4jTransactionManager.class, ReactiveTransactionManager.class, + Flux.class }) +@ConditionalOnBean(Driver.class) +@AutoConfigureAfter(Neo4jDataAutoConfiguration.class) @Import(Neo4jDefaultReactiveCallbacksRegistrar.class) -class Neo4jReactiveDataConfiguration { +public class Neo4jReactiveDataAutoConfiguration { - @Bean("reactiveDatabaseSelectionProvider") - @ConditionalOnProperty(prefix = "spring.data.neo4j", name = "database") + @Bean @ConditionalOnMissingBean - @Order(-30) - ReactiveDatabaseSelectionProvider staticDatabaseSelectionProvider(Neo4jDataProperties dataProperties) { - return ReactiveDatabaseSelectionProvider.createStaticDatabaseSelectionProvider(dataProperties.getDatabase()); - } - - @Bean("reactiveDatabaseSelectionProvider") - @ConditionalOnMissingBean - @Order(-20) - ReactiveDatabaseSelectionProvider defaultSelectionProvider() { - return ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider(); + public ReactiveDatabaseSelectionProvider reactiveDatabaseSelectionProvider(Neo4jDataProperties dataProperties) { + String database = dataProperties.getDatabase(); + return (database != null) ? ReactiveDatabaseSelectionProvider.createStaticDatabaseSelectionProvider(database) + : ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider(); } @Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME) @ConditionalOnMissingBean - ReactiveNeo4jClient neo4jClient(Driver driver) { + public ReactiveNeo4jClient reactiveNeo4jClient(Driver driver) { return ReactiveNeo4jClient.create(driver); } @Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME) @ConditionalOnMissingBean(ReactiveNeo4jOperations.class) - ReactiveNeo4jTemplate neo4jTemplate(ReactiveNeo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext, - ReactiveDatabaseSelectionProvider databaseNameProvider) { + public ReactiveNeo4jTemplate reactiveNeo4jTemplate(ReactiveNeo4jClient neo4jClient, + Neo4jMappingContext neo4jMappingContext, ReactiveDatabaseSelectionProvider databaseNameProvider) { return new ReactiveNeo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider); } @Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME) @ConditionalOnMissingBean(ReactiveTransactionManager.class) - ReactiveTransactionManager transactionManager(Driver driver, + public ReactiveTransactionManager reactiveTransactionManager(Driver driver, ReactiveDatabaseSelectionProvider databaseNameProvider) { return new ReactiveNeo4jTransactionManager(driver, databaseNameProvider); } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesAutoConfiguration.java similarity index 74% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfiguration.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesAutoConfiguration.java index 281ba5ce4e..27cb2ee200 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesAutoConfiguration.java @@ -16,8 +16,11 @@ package org.springframework.boot.autoconfigure.data.neo4j; +import org.neo4j.driver.Driver; 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.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType; @@ -29,16 +32,20 @@ import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryC import org.springframework.data.neo4j.repository.support.ReactiveNeo4jRepositoryFactoryBean; /** - * Imports the registrar for reactive Neo4j repositories. + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Neo4j Reactive + * Repositories. * * @author Michael J. Simons + * @author Stephane Nicoll + * @since 2.4.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ Flux.class, ReactiveNeo4jRepository.class }) +@ConditionalOnClass({ Driver.class, ReactiveNeo4jRepository.class, Flux.class }) @ConditionalOnMissingBean({ ReactiveNeo4jRepositoryFactoryBean.class, ReactiveNeo4jRepositoryConfigurationExtension.class }) @ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.REACTIVE) -@Import(Neo4jReactiveRepositoriesConfigureRegistrar.class) -final class Neo4jReactiveRepositoriesConfiguration { +@Import(Neo4jReactiveRepositoriesRegistrar.class) +@AutoConfigureAfter(Neo4jReactiveDataAutoConfiguration.class) +public class Neo4jReactiveRepositoriesAutoConfiguration { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfigureRegistrar.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesRegistrar.java similarity index 82% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfigureRegistrar.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesRegistrar.java index 5561bc9e44..e52749df55 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfigureRegistrar.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesRegistrar.java @@ -19,17 +19,18 @@ package org.springframework.boot.autoconfigure.data.neo4j; import java.lang.annotation.Annotation; import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension; import org.springframework.data.repository.config.RepositoryConfigurationExtension; /** - * {@link ImportBeanDefinitionRegistrar} used to auto-configure reactive Spring Data Neo4j + * {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Neo4j reactive * Repositories. * * @author Michael J. Simons */ -final class Neo4jReactiveRepositoriesConfigureRegistrar extends AbstractRepositoryConfigurationSourceSupport { +class Neo4jReactiveRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport { @Override protected Class getAnnotation() { @@ -38,7 +39,7 @@ final class Neo4jReactiveRepositoriesConfigureRegistrar extends AbstractReposito @Override protected Class getConfiguration() { - return SpringDataNeo4jConfiguration.class; + return EnableReactiveNeo4jRepositoriesConfiguration.class; } @Override @@ -47,7 +48,7 @@ final class Neo4jReactiveRepositoriesConfigureRegistrar extends AbstractReposito } @EnableReactiveNeo4jRepositories - private static class SpringDataNeo4jConfiguration { + private static class EnableReactiveNeo4jRepositoriesConfiguration { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java index c611ad42c5..76977f3e7c 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java @@ -19,26 +19,43 @@ package org.springframework.boot.autoconfigure.data.neo4j; import org.neo4j.driver.Driver; import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.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.neo4j.repository.Neo4jRepository; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; +import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean; /** - * Shared entry point for the configuration of Spring Data Neo4j repositories in their - * imperative and reactive forms. + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Neo4j + * Repositories. + *

    + * Activates when there is no bean of type {@link Neo4jRepositoryFactoryBean} or + * {@link Neo4jRepositoryConfigurationExtension} configured in the context, the Spring + * Data Neo4j {@link Neo4jRepository} type is on the classpath, the Neo4j client driver + * API is on the classpath, and there is no other configured {@link Neo4jRepository}. + *

    + * Once in effect, the auto-configuration is the equivalent of enabling Neo4j repositories + * using the {@link EnableNeo4jRepositories @EnableNeo4jRepositories} annotation. * * @author Dave Syer * @author Oliver Gierke * @author Josh Long * @author Michael J. Simons - * @see EnableNeo4jRepositories * @since 1.4.0 + * @see EnableNeo4jRepositories */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass(Driver.class) +@ConditionalOnClass({ Driver.class, Neo4jRepository.class }) +@ConditionalOnMissingBean({ Neo4jRepositoryFactoryBean.class, Neo4jRepositoryConfigurationExtension.class }) +@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.IMPERATIVE) +@Import(Neo4jRepositoriesRegistrar.class) @AutoConfigureAfter(Neo4jDataAutoConfiguration.class) -@Import({ Neo4jRepositoriesConfiguration.class, Neo4jReactiveRepositoriesConfiguration.class }) public class Neo4jRepositoriesAutoConfiguration { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfiguration.java deleted file mode 100644 index 7a190c6822..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfiguration.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * 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.neo4j; - -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.neo4j.repository.Neo4jRepository; -import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; -import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean; - -/** - * Imports the registrar for imperative Neo4j repositories. - * - * @author Michael J. Simons - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass(Neo4jRepository.class) -@ConditionalOnMissingBean({ Neo4jRepositoryFactoryBean.class, Neo4jRepositoryConfigurationExtension.class }) -@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.IMPERATIVE) -@Import(Neo4jRepositoriesConfigureRegistrar.class) -class Neo4jRepositoriesConfiguration { - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfigureRegistrar.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesRegistrar.java similarity index 81% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfigureRegistrar.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesRegistrar.java index 268dff593b..976581095e 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfigureRegistrar.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 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. @@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.data.neo4j; import java.lang.annotation.Annotation; import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; import org.springframework.data.repository.config.RepositoryConfigurationExtension; @@ -28,9 +29,8 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi * Repositories. * * @author Michael Hunger - * @author Michael J. Simons */ -class Neo4jRepositoriesConfigureRegistrar extends AbstractRepositoryConfigurationSourceSupport { +class Neo4jRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport { @Override protected Class getAnnotation() { @@ -39,7 +39,7 @@ class Neo4jRepositoriesConfigureRegistrar extends AbstractRepositoryConfiguratio @Override protected Class getConfiguration() { - return SpringDataNeo4jConfiguration.class; + return EnableNeo4jRepositoriesConfiguration.class; } @Override @@ -48,7 +48,7 @@ class Neo4jRepositoriesConfigureRegistrar extends AbstractRepositoryConfiguratio } @EnableNeo4jRepositories - private static class SpringDataNeo4jConfiguration { + private static class EnableNeo4jRepositoriesConfiguration { } 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 fd1b388ae8..5b9b47c3b5 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 @@ -51,7 +51,6 @@ import org.springframework.core.annotation.AliasFor; * annotation. * * @author Phillip Webb - * @author Michael J. Simons * @since 1.4.0 * @see EntityScanPackages */ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 194db53153..acd3527413 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -651,19 +651,81 @@ }, { "name": "spring.data.neo4j.auto-index", - "defaultValue": "none" + "description": "Auto index mode.", + "defaultValue": "none", + "deprecation": { + "reason": "Automatic index creation is no longer supported.", + "level": "error" + } + }, + { + "name": "spring.data.neo4j.embedded.enabled", + "type": "java.lang.Boolean", + "description": "Whether to enable embedded mode if the embedded driver is available.", + "deprecation": { + "reason": "Embedded mode is no longer supported, please use Testcontainers instead.", + "level": "error" + } }, { "name": "spring.data.neo4j.open-in-view", "type": "java.lang.Boolean", "description": "Register OpenSessionInViewInterceptor that binds a Neo4j Session to the thread for the entire processing of the request.", - "defaultValue": false + "deprecation": { + "level": "error" + } + }, + { + "name": "spring.data.neo4j.password", + "type": "java.lang.String", + "description": "Login password of the server.", + "deprecation": { + "replacement": "spring.neo4j.authentication.password", + "level": "error" + } }, { "name": "spring.data.neo4j.repositories.enabled", "type": "java.lang.Boolean", "description": "Whether to enable Neo4j repositories.", - "defaultValue": true + "defaultValue": true, + "deprecation": { + "replacement": "spring.data.neo4j.repositories.type", + "level": "error" + } + }, + { + "name": "spring.data.neo4j.repositories.type", + "type": "org.springframework.boot.autoconfigure.data.RepositoryType", + "description": "Type of Neo4j repositories to enable.", + "defaultValue": "auto" + }, + { + "name": "spring.data.neo4j.uri", + "type": "java.lang.String", + "description": "URI used by the driver. Auto-detected by default.", + "deprecation": { + "replacement": "spring.neo4j.uri", + "level": "error" + } + }, + { + "name": "spring.data.neo4j.use-native-types", + "type": "java.lang.Boolean", + "description": "Whether to use Neo4j native types wherever possible.", + "deprecation": { + "reason": "Native type support is now built-in.", + "level": "error" + } + }, + { + "name": "spring.data.neo4j.username", + "type": "java.lang.String", + "description": "Login user of the server.", + "deprecation": { + "replacement": "spring.neo4j.authentication.password", + "level": "error" + } }, { "name": "spring.data.r2dbc.repositories.enabled", 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 144b482523..fdd60832eb 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 @@ -51,6 +51,8 @@ org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfigura org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveDataAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java index e9d160029f..eb949d32fd 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -19,6 +19,11 @@ package org.springframework.boot.autoconfigure.data.neo4j; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.neo4j.driver.Config; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.internal.logging.Slf4jLogging; + import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration; import org.springframework.boot.autoconfigure.data.jpa.city.City; @@ -37,11 +42,6 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.data.neo4j.config.AbstractNeo4jConfig; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; -import org.neo4j.driver.Config; -import org.neo4j.driver.Driver; -import org.neo4j.driver.GraphDatabase; -import org.neo4j.driver.internal.logging.Slf4jLogging; - import static org.assertj.core.api.Assertions.assertThat; /** @@ -103,7 +103,8 @@ class MixedNeo4jRepositoriesAutoConfigurationTests { context.register(config); context.register(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, JpaRepositoriesAutoConfiguration.class, Neo4jDataAutoConfiguration.class, - Neo4jRepositoriesAutoConfiguration.class); + Neo4jReactiveDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class, + Neo4jReactiveRepositoriesAutoConfiguration.class); context.refresh(); this.context = context; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MockedDriverConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MockedDriverConfiguration.java index 8c2a3a4277..4740cf67dc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MockedDriverConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MockedDriverConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -16,16 +16,16 @@ package org.springframework.boot.autoconfigure.data.neo4j; import org.mockito.Mockito; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - import org.neo4j.driver.Driver; import org.neo4j.driver.Session; import org.neo4j.driver.SessionConfig; import org.neo4j.driver.types.TypeSystem; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; /** * Driver configuration mocked to avoid instantiation of a real driver with connection @@ -41,8 +41,8 @@ class MockedDriverConfiguration { Driver driver = mock(Driver.class); TypeSystem typeSystem = mock(TypeSystem.class); Session session = mock(Session.class); - when(driver.defaultTypeSystem()).thenReturn(typeSystem); - when(driver.session(Mockito.any(SessionConfig.class))).thenReturn(session); + given(driver.defaultTypeSystem()).willReturn(typeSystem); + given(driver.session(Mockito.any(SessionConfig.class))).willReturn(session); return driver; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java index d678521498..686ade7e25 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -16,14 +16,10 @@ package org.springframework.boot.autoconfigure.data.neo4j; -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - import org.junit.jupiter.api.Test; -import org.neo4j.driver.Driver; + import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; -import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -34,150 +30,110 @@ import org.springframework.data.neo4j.core.Neo4jOperations; import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.data.neo4j.core.convert.Neo4jConversions; import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; -import org.springframework.test.util.ReflectionTestUtils; import org.springframework.transaction.PlatformTransactionManager; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + /** + * Tests for {@link Neo4jDataAutoConfiguration}. + * + * @author Stephane Nicoll + * @author Michael Hunger + * @author Vince Bickers + * @author Andy Wilkinson + * @author Kazuki Shimizu * @author Michael J. Simons */ class Neo4jDataAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withPropertyValues("spring.data.neo4j.repositories.type=imperative") .withUserConfiguration(MockedDriverConfiguration.class) .withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class)); @Test void shouldProvideConversions() { - contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jConversions.class)); + this.contextRunner.run((context) -> assertThat(context).hasSingleBean(Neo4jConversions.class)); } @Test void shouldProvideDefaultDatabaseNameProvider() { - contextRunner.run(ctx -> { - assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class); - DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class); - assertThat(databaseNameProvider).isSameAs(DatabaseSelectionProvider.getDefaultSelectionProvider()); + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(DatabaseSelectionProvider.class); + assertThat(context.getBean(DatabaseSelectionProvider.class)) + .isSameAs(DatabaseSelectionProvider.getDefaultSelectionProvider()); }); } @Test - void shouldProvideStaticDatabaseNameProviderIfConfigured() { - contextRunner.withPropertyValues("spring.data.neo4j.database=foobar").run(ctx -> { - assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class); - DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class); - assertThat(databaseNameProvider.getDatabaseSelection()).isEqualTo(DatabaseSelection.byName("foobar")); + void shouldUseDatabaseNameIfSet() { + this.contextRunner.withPropertyValues("spring.data.neo4j.database=test").run((context) -> { + assertThat(context).hasSingleBean(DatabaseSelectionProvider.class); + assertThat(context.getBean(DatabaseSelectionProvider.class).getDatabaseSelection()) + .isEqualTo(DatabaseSelection.byName("test")); }); } @Test - void shouldRespectExistingDatabaseNameProvider() { - contextRunner.withPropertyValues("spring.data.neo4j.database=foobar") - .withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> { - assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class); - DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class); - assertThat(databaseNameProvider.getDatabaseSelection()) - .isEqualTo(DatabaseSelection.byName("whatever")); + void shouldReuseExistingDatabaseNameProvider() { + this.contextRunner.withPropertyValues("spring.data.neo4j.database=ignored") + .withUserConfiguration(CustomDatabaseSelectionProviderConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(DatabaseSelectionProvider.class); + assertThat(context.getBean(DatabaseSelectionProvider.class).getDatabaseSelection()) + .isEqualTo(DatabaseSelection.byName("custom")); }); } @Test - void shouldRequireAllNeededClasses() { - contextRunner - .withClassLoader( - new FilteredClassLoader(Neo4jTransactionManager.class, PlatformTransactionManager.class)) - .run(ctx -> assertThat(ctx).doesNotHaveBean(Neo4jClient.class).doesNotHaveBean(Neo4jTemplate.class) - .doesNotHaveBean(Neo4jTransactionManager.class)); + void shouldProvideNeo4jClient() { + this.contextRunner.run((context) -> assertThat(context).hasSingleBean(Neo4jClient.class)); } @Test - void shouldCreateNewNeo4jClient() { - contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jClient.class)); + void shouldReuseExistingNeo4jClient() { + this.contextRunner.withBean("myCustomClient", Neo4jClient.class, () -> mock(Neo4jClient.class)) + .run((context) -> assertThat(context).hasSingleBean(Neo4jClient.class).hasBean("myCustomClient")); } @Test - void shouldNotReplaceExistingNeo4jClient() { - contextRunner.withUserConfiguration(ConfigurationWithExistingClient.class) - .run(ctx -> assertThat(ctx).hasSingleBean(Neo4jClient.class).hasBean("myCustomClient")); - } - - @Test - void shouldCreateNewNeo4jTemplate() { - contextRunner.withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> { - assertThat(ctx).hasSingleBean(Neo4jTemplate.class); - - // Verify that the template uses the provided database name - // provider - Neo4jTemplate template = ctx.getBean(Neo4jTemplate.class); - DatabaseSelectionProvider provider = (DatabaseSelectionProvider) ReflectionTestUtils.getField(template, - "databaseSelectionProvider"); - assertThat(provider).isSameAs(ctx.getBean(DatabaseSelectionProvider.class)); + void shouldProvideNeo4jTemplate() { + this.contextRunner.withUserConfiguration(CustomDatabaseSelectionProviderConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(Neo4jTemplate.class); + assertThat(context.getBean(Neo4jTemplate.class)).extracting("databaseSelectionProvider") + .isSameAs(context.getBean(DatabaseSelectionProvider.class)); }); } @Test - void shouldNotReplaceExistingNeo4jTemplate() { - contextRunner.withUserConfiguration(ConfigurationWithExistingTemplate.class) - .run(ctx -> assertThat(ctx).hasSingleBean(Neo4jOperations.class).hasBean("myCustomOperations")); + void shouldReuseExistingNeo4jTemplate() { + this.contextRunner.withBean("myCustomOperations", Neo4jOperations.class, () -> mock(Neo4jOperations.class)).run( + (context) -> assertThat(context).hasSingleBean(Neo4jOperations.class).hasBean("myCustomOperations")); } @Test - void shouldCreateNewTransactionManager() { - contextRunner.withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> { - assertThat(ctx).hasSingleBean(Neo4jTransactionManager.class); - - // Verify that the transaction manager uses the provided - // database name provider - Neo4jTransactionManager transactionManager = ctx.getBean(Neo4jTransactionManager.class); - DatabaseSelectionProvider provider = (DatabaseSelectionProvider) ReflectionTestUtils - .getField(transactionManager, "databaseSelectionProvider"); - assertThat(provider).isSameAs(ctx.getBean(DatabaseSelectionProvider.class)); + void shouldProvideTransactionManager() { + this.contextRunner.withUserConfiguration(CustomDatabaseSelectionProviderConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(Neo4jTransactionManager.class); + assertThat(context.getBean(Neo4jTransactionManager.class)).extracting("databaseSelectionProvider") + .isSameAs(context.getBean(DatabaseSelectionProvider.class)); }); } @Test - void shouldHonourExistingTransactionManager() { - contextRunner.withUserConfiguration(ConfigurationWithExistingTransactionManager.class) - .run(ctx -> assertThat(ctx).hasSingleBean(PlatformTransactionManager.class) + void shouldReuseExistingTransactionManager() { + this.contextRunner + .withBean("myCustomTransactionManager", PlatformTransactionManager.class, + () -> mock(PlatformTransactionManager.class)) + .run((context) -> assertThat(context).hasSingleBean(PlatformTransactionManager.class) .hasBean("myCustomTransactionManager")); } - @Configuration - static class ConfigurationWithExistingClient { - - @Bean("myCustomClient") - Neo4jClient neo4jClient(Driver driver) { - return Neo4jClient.create(driver); - } - - } - - @Configuration - static class ConfigurationWithExistingTemplate { - - @Bean("myCustomOperations") - Neo4jOperations neo4jOperations() { - return mock(Neo4jOperations.class); - } - - } - - @Configuration - static class ConfigurationWithExistingTransactionManager { - - @Bean("myCustomTransactionManager") - PlatformTransactionManager transactionManager() { - return mock(PlatformTransactionManager.class); - } - - } - - @Configuration - static class ConfigurationWithExistingDatabaseSelectionProvider { + @Configuration(proxyBeanMethods = false) + static class CustomDatabaseSelectionProviderConfiguration { @Bean DatabaseSelectionProvider databaseSelectionProvider() { - return () -> DatabaseSelection.byName("whatever"); + return () -> DatabaseSelection.byName("custom"); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataAutoConfigurationTests.java new file mode 100644 index 0000000000..b4e7c5ac04 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataAutoConfigurationTests.java @@ -0,0 +1,145 @@ +/* + * 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.neo4j; + +import org.junit.jupiter.api.Test; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.DatabaseSelection; +import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; +import org.springframework.data.neo4j.core.ReactiveNeo4jClient; +import org.springframework.data.neo4j.core.ReactiveNeo4jOperations; +import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; +import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; +import org.springframework.transaction.ReactiveTransactionManager; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; + +/** + * Tests for {@link Neo4jReactiveDataAutoConfiguration}. + * + * @author Michael J. Simons + * @author Stephane Nicoll + */ +class Neo4jReactiveDataAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withUserConfiguration(MockedDriverConfiguration.class) + .withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class, + Neo4jReactiveDataAutoConfiguration.class)); + + @Test + void shouldProvideDefaultDatabaseNameProvider() { + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(ReactiveDatabaseSelectionProvider.class); + assertThat(context.getBean(ReactiveDatabaseSelectionProvider.class)) + .isSameAs(ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider()); + }); + } + + @Test + void shouldUseDatabaseNameIfSet() { + this.contextRunner.withPropertyValues("spring.data.neo4j.database=test").run((context) -> { + assertThat(context).hasSingleBean(ReactiveDatabaseSelectionProvider.class); + StepVerifier.create(context.getBean(ReactiveDatabaseSelectionProvider.class).getDatabaseSelection()) + .consumeNextWith((databaseSelection) -> assertThat(databaseSelection.getValue()).isEqualTo("test")) + .expectComplete(); + }); + } + + @Test + void shouldReuseExistingDatabaseNameProvider() { + this.contextRunner.withPropertyValues("spring.data.neo4j.database=ignored") + .withUserConfiguration(CustomReactiveDatabaseSelectionProviderConfiguration.class).run((context) -> { + assertThat(context).hasSingleBean(ReactiveDatabaseSelectionProvider.class); + StepVerifier.create(context.getBean(ReactiveDatabaseSelectionProvider.class).getDatabaseSelection()) + .consumeNextWith( + (databaseSelection) -> assertThat(databaseSelection.getValue()).isEqualTo("custom")) + .expectComplete(); + }); + } + + @Test + void shouldProvideReactiveNeo4jClient() { + this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jClient.class)); + } + + @Test + void shouldReuseExistingReactiveNeo4jClient() { + this.contextRunner + .withBean("myCustomReactiveClient", ReactiveNeo4jClient.class, () -> mock(ReactiveNeo4jClient.class)) + .run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jClient.class) + .hasBean("myCustomReactiveClient")); + } + + @Test + void shouldProvideReactiveNeo4jTemplate() { + this.contextRunner.withUserConfiguration(CustomReactiveDatabaseSelectionProviderConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(ReactiveNeo4jTemplate.class); + assertThat(context.getBean(ReactiveNeo4jTemplate.class)).extracting("databaseSelectionProvider") + .isSameAs(context.getBean(ReactiveDatabaseSelectionProvider.class)); + }); + } + + @Test + void shouldReuseExistingReactiveNeo4jTemplate() { + this.contextRunner + .withBean("myCustomReactiveOperations", ReactiveNeo4jOperations.class, + () -> mock(ReactiveNeo4jOperations.class)) + .run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jOperations.class) + .hasBean("myCustomReactiveOperations")); + } + + @Test + void shouldProvideReactiveTransactionManager() { + this.contextRunner.withUserConfiguration(CustomReactiveDatabaseSelectionProviderConfiguration.class) + .run((context) -> { + assertThat(context).hasSingleBean(ReactiveNeo4jTransactionManager.class); + assertThat(context.getBean(ReactiveNeo4jTransactionManager.class)) + .extracting("databaseSelectionProvider") + .isSameAs(context.getBean(ReactiveDatabaseSelectionProvider.class)); + }); + } + + @Test + void shouldReuseExistingReactiveTransactionManager() { + this.contextRunner + .withBean("myCustomReactiveTransactionManager", ReactiveTransactionManager.class, + () -> mock(ReactiveTransactionManager.class)) + .run((context) -> assertThat(context).hasSingleBean(ReactiveTransactionManager.class) + .hasBean("myCustomReactiveTransactionManager")); + } + + @Configuration(proxyBeanMethods = false) + static class CustomReactiveDatabaseSelectionProviderConfiguration { + + @Bean + ReactiveDatabaseSelectionProvider databaseNameProvider() { + return () -> Mono.just(DatabaseSelection.byName("custom")); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesAutoConfigurationTests.java new file mode 100644 index 0000000000..05584cfc7d --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesAutoConfigurationTests.java @@ -0,0 +1,112 @@ +/* + * 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.neo4j; + +import org.junit.jupiter.api.Test; + +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; +import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; +import org.springframework.boot.autoconfigure.data.neo4j.city.City; +import org.springframework.boot.autoconfigure.data.neo4j.city.CityRepository; +import org.springframework.boot.autoconfigure.data.neo4j.city.ReactiveCityRepository; +import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository; +import org.springframework.boot.autoconfigure.data.neo4j.country.ReactiveCountryRepository; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; +import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests for {@link Neo4jReactiveRepositoriesAutoConfiguration}. + * + * @author Stephane Nicoll + * @author Michael J. Simons + */ +public class Neo4jReactiveRepositoriesAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withUserConfiguration(MockedDriverConfiguration.class) + .withConfiguration(AutoConfigurations.of(Neo4jDataAutoConfiguration.class, + Neo4jReactiveDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class, + Neo4jReactiveRepositoriesAutoConfiguration.class)); + + @Test + void configurationWithDefaultRepositories() { + this.contextRunner.withUserConfiguration(TestConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(ReactiveCityRepository.class)); + } + + @Test + void configurationWithNoRepositories() { + this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> assertThat(context) + .hasSingleBean(ReactiveNeo4jTransactionManager.class).doesNotHaveBean(ReactiveNeo4jRepository.class)); + } + + @Test + void configurationWithDisabledRepositories() { + this.contextRunner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.data.neo4j.repositories.type=none") + .run((context) -> assertThat(context).doesNotHaveBean(ReactiveNeo4jRepository.class)); + } + + @Test + void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() { + this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class) + .run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jTransactionManager.class) + .doesNotHaveBean(ReactiveNeo4jRepository.class)); + } + + @Test + void shouldRespectAtEnableReactiveNeo4jRepositories() { + this.contextRunner + .withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomReactiveRepositoryScan.class) + .withPropertyValues("spring.data.neo4j.repositories.type=reactive") + .run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class) + .doesNotHaveBean(ReactiveCityRepository.class).doesNotHaveBean(CountryRepository.class) + .hasSingleBean(ReactiveCountryRepository.class)); + } + + @Configuration(proxyBeanMethods = false) + @TestAutoConfigurationPackage(City.class) + static class TestConfiguration { + + } + + @Configuration(proxyBeanMethods = false) + @TestAutoConfigurationPackage(EmptyDataPackage.class) + static class EmptyConfiguration { + + } + + @Configuration(proxyBeanMethods = false) + @EnableReactiveNeo4jRepositories("foo.bar") + @TestAutoConfigurationPackage(Neo4jReactiveRepositoriesAutoConfigurationTests.class) + static class SortOfInvalidCustomConfiguration { + + } + + @Configuration(proxyBeanMethods = false) + @EnableReactiveNeo4jRepositories(basePackageClasses = ReactiveCountryRepository.class) + static class WithCustomReactiveRepositoryScan { + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationIntegrationTests.java index f6a8592c15..c5f3a9cb53 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationIntegrationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationIntegrationTests.java @@ -17,6 +17,10 @@ package org.springframework.boot.autoconfigure.data.neo4j; import org.junit.jupiter.api.Test; +import org.testcontainers.containers.Neo4jContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.ImportAutoConfiguration; import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository; @@ -26,9 +30,6 @@ import org.springframework.context.annotation.Configuration; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; -import org.testcontainers.containers.Neo4jContainer; -import org.testcontainers.junit.jupiter.Container; -import org.testcontainers.junit.jupiter.Testcontainers; import static org.assertj.core.api.Assertions.assertThat; @@ -37,32 +38,26 @@ import static org.assertj.core.api.Assertions.assertThat; * * @author Michael J. Simons */ -@SpringBootTest(properties = "spring.data.neo4j.repositories.type=imperative") +@SpringBootTest @Testcontainers(disabledWithoutDocker = true) public class Neo4jRepositoriesAutoConfigurationIntegrationTests { @Container - private static Neo4jContainer neo4jServer = new Neo4jContainer<>("neo4j:4.0"); + private static final Neo4jContainer neo4jServer = new Neo4jContainer<>("neo4j:4.0"); @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { - registry.add("spring.neo4j.uri", neo4jServer::getBoltUrl); registry.add("spring.neo4j.authentication.username", () -> "neo4j"); registry.add("spring.neo4j.authentication.password", neo4jServer::getAdminPassword); } - private final CountryRepository countryRepository; - @Autowired - Neo4jRepositoriesAutoConfigurationIntegrationTests(CountryRepository countryRepository) { - this.countryRepository = countryRepository; - } + private CountryRepository countryRepository; @Test void ensureRepositoryIsReady() { - - assertThat(countryRepository.count()).isEqualTo(0); + assertThat(this.countryRepository.count()).isEqualTo(0); } @Configuration diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java index c8e0ac302d..708b4372be 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.data.neo4j; import org.junit.jupiter.api.Test; import org.mockito.Mockito; + import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; @@ -26,19 +27,13 @@ import org.springframework.boot.autoconfigure.data.neo4j.city.CityRepository; import org.springframework.boot.autoconfigure.data.neo4j.city.ReactiveCityRepository; import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository; import org.springframework.boot.autoconfigure.data.neo4j.country.ReactiveCountryRepository; -import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.core.Neo4jClient; -import org.springframework.data.neo4j.core.ReactiveNeo4jClient; import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; import org.springframework.data.neo4j.repository.Neo4jRepository; -import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; -import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; import org.springframework.data.neo4j.repository.support.ReactiveNeo4jRepositoryFactoryBean; -import reactor.core.publisher.Flux; import static org.assertj.core.api.Assertions.assertThat; @@ -55,75 +50,49 @@ import static org.assertj.core.api.Assertions.assertThat; class Neo4jRepositoriesAutoConfigurationTests { private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withUserConfiguration(MockedDriverConfiguration.class) - .withConfiguration(AutoConfigurations.of(Neo4jRepositoriesAutoConfigurationTests.class, - Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class)); + .withUserConfiguration(MockedDriverConfiguration.class).withConfiguration( + AutoConfigurations.of(Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class)); @Test - void defaultRepositoryConfigurationShouldWork() { + void configurationWithDefaultRepositories() { this.contextRunner.withUserConfiguration(TestConfiguration.class) - .withPropertyValues("spring.data.neo4j.repositories.type=imperative") - .run(ctx -> assertThat(ctx).hasSingleBean(CityRepository.class)); + .run((context) -> assertThat(context).hasSingleBean(CityRepository.class)); } @Test - void repositoryConfigurationShouldNotCreateArbitraryRepos() { - this.contextRunner.withUserConfiguration(EmptyConfiguration.class) - .withPropertyValues("spring.data.neo4j.repositories.type=imperative").run(ctx -> assertThat(ctx) - .hasSingleBean(Neo4jTransactionManager.class).doesNotHaveBean(Neo4jRepository.class)); + void configurationWithNoRepositories() { + this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> assertThat(context) + .hasSingleBean(Neo4jTransactionManager.class).doesNotHaveBean(Neo4jRepository.class)); } @Test - void configurationOfRepositoryTypeShouldWork() { - this.contextRunner.withPropertyValues("spring.data.neo4j.repositories.type=none") - .withUserConfiguration(TestConfiguration.class).withClassLoader(new FilteredClassLoader(Flux.class)) - .run(ctx -> assertThat(ctx).doesNotHaveBean(Neo4jTransactionManager.class) - .doesNotHaveBean(ReactiveNeo4jClient.class).doesNotHaveBean(Neo4jRepository.class)); - - this.contextRunner.withPropertyValues("spring.data.neo4j.repositories.type=imperative") - .withUserConfiguration(TestConfiguration.class) - .run(ctx -> assertThat(ctx).hasSingleBean(Neo4jTransactionManager.class) - .hasSingleBean(Neo4jClient.class).doesNotHaveBean(ReactiveNeo4jRepository.class)); + void configurationWithDisabledRepositories() { + this.contextRunner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.data.neo4j.repositories.type=none") + .run((context) -> assertThat(context).doesNotHaveBean(Neo4jRepository.class)); } @Test void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() { this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class) - .withPropertyValues("spring.data.neo4j.repositories.type=imperative").run(ctx -> assertThat(ctx) - .hasSingleBean(Neo4jTransactionManager.class).doesNotHaveBean(Neo4jRepository.class)); + .run((context) -> assertThat(context).hasSingleBean(Neo4jTransactionManager.class) + .doesNotHaveBean(Neo4jRepository.class)); } @Test void shouldRespectAtEnableNeo4jRepositories() { this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomRepositoryScan.class) - .withPropertyValues("spring.data.neo4j.repositories.type=imperative") - .run(ctx -> assertThat(ctx).doesNotHaveBean(CityRepository.class) + .run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class) .doesNotHaveBean(ReactiveCityRepository.class).hasSingleBean(CountryRepository.class) .doesNotHaveBean(ReactiveCountryRepository.class)); } - @Test - void shouldRespectAtEnableReactiveNeo4jRepositories() { - this.contextRunner - .withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomReactiveRepositoryScan.class) - .withPropertyValues("spring.data.neo4j.repositories.type=reactive") - .run(ctx -> assertThat(ctx).doesNotHaveBean(CityRepository.class) - .doesNotHaveBean(ReactiveCityRepository.class).doesNotHaveBean(CountryRepository.class) - .hasSingleBean(ReactiveCountryRepository.class)); - } - @Configuration(proxyBeanMethods = false) @EnableNeo4jRepositories(basePackageClasses = CountryRepository.class) static class WithCustomRepositoryScan { } - @Configuration(proxyBeanMethods = false) - @EnableReactiveNeo4jRepositories(basePackageClasses = ReactiveCountryRepository.class) - static class WithCustomReactiveRepositoryScan { - - } - @Configuration(proxyBeanMethods = false) static class WithFakeEnabledReactiveNeo4jRepositories { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/ReactiveNeo4jDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/ReactiveNeo4jDataAutoConfigurationTests.java deleted file mode 100644 index dfdf47bd70..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/ReactiveNeo4jDataAutoConfigurationTests.java +++ /dev/null @@ -1,197 +0,0 @@ -/* - * 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.neo4j; - -import static org.assertj.core.api.Assertions.*; -import static org.mockito.Mockito.*; - -import reactor.core.publisher.Flux; -import reactor.core.publisher.Mono; -import reactor.test.StepVerifier; - -import org.junit.jupiter.api.Test; -import org.neo4j.driver.Driver; -import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; -import org.springframework.boot.test.context.FilteredClassLoader; -import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.core.DatabaseSelection; -import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; -import org.springframework.data.neo4j.core.ReactiveNeo4jClient; -import org.springframework.data.neo4j.core.ReactiveNeo4jOperations; -import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; -import org.springframework.data.neo4j.core.convert.Neo4jConversions; -import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; -import org.springframework.test.util.ReflectionTestUtils; -import org.springframework.transaction.ReactiveTransactionManager; - -/** - * @author Michael J. Simons - */ -class ReactiveNeo4jDataAutoConfigurationTests { - - private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() - .withPropertyValues("spring.data.neo4j.repositories.type=reactive") - .withUserConfiguration(MockedDriverConfiguration.class) - .withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class)); - - @Test - void shouldProvideConversions() { - contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jConversions.class)); - } - - @Test - void shouldProvideDefaultDatabaseNameProvider() { - contextRunner.run(ctx -> { - assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class); - ReactiveDatabaseSelectionProvider databaseNameProvider = ctx - .getBean(ReactiveDatabaseSelectionProvider.class); - assertThat(databaseNameProvider).isSameAs(ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider()); - }); - } - - @Test - void shouldProvideStaticDatabaseNameProviderIfConfigured() { - contextRunner.withPropertyValues("spring.data.neo4j.database=foobar").run(ctx -> { - assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class); - ReactiveDatabaseSelectionProvider databaseNameProvider = ctx - .getBean(ReactiveDatabaseSelectionProvider.class); - StepVerifier.create(databaseNameProvider.getDatabaseSelection().map(DatabaseSelection::getValue)) - .expectNext("foobar").expectComplete(); - }); - } - - @Test - void shouldRespectExistingDatabaseNameProvider() { - contextRunner.withPropertyValues("spring.data.neo4j.database=foobar") - .withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class).run(ctx -> { - assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class); - ReactiveDatabaseSelectionProvider databaseNameProvider = ctx - .getBean(ReactiveDatabaseSelectionProvider.class); - StepVerifier.create(databaseNameProvider.getDatabaseSelection().map(DatabaseSelection::getValue)) - .expectNext("whatever").expectComplete(); - }); - } - - @Test - void shouldRequireAllNeededClasses() { - contextRunner - .withClassLoader(new FilteredClassLoader(ReactiveNeo4jTransactionManager.class, - ReactiveTransactionManager.class, Flux.class)) - .run(ctx -> assertThat(ctx).doesNotHaveBean(ReactiveNeo4jClient.class) - .doesNotHaveBean(ReactiveNeo4jTemplate.class) - .doesNotHaveBean(ReactiveNeo4jTransactionManager.class)); - } - - @Test - void shouldCreateNewReactiveNeo4jClient() { - contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(ReactiveNeo4jClient.class)); - } - - @Test - void shouldNotReplaceExistingReactiveNeo4jClient() { - contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveClient.class) - .run(ctx -> assertThat(ctx).hasSingleBean(ReactiveNeo4jClient.class).hasBean("myCustomReactiveClient")); - } - - @Test - void shouldCreateNewNeo4jTemplate() { - contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class) - .run(ctx -> { - assertThat(ctx).hasSingleBean(ReactiveNeo4jTemplate.class); - - // Verify that the template uses the provided database name - // provider - ReactiveNeo4jTemplate template = ctx.getBean(ReactiveNeo4jTemplate.class); - ReactiveDatabaseSelectionProvider provider = (ReactiveDatabaseSelectionProvider) ReflectionTestUtils - .getField(template, "databaseSelectionProvider"); - assertThat(provider).isSameAs(ctx.getBean(ReactiveDatabaseSelectionProvider.class)); - }); - } - - @Test - void shouldNotReplaceExistingNeo4jTemplate() { - contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveTemplate.class).run(ctx -> assertThat(ctx) - .hasSingleBean(ReactiveNeo4jOperations.class).hasBean("myCustomReactiveOperations")); - } - - @Test - void shouldCreateNewTransactionManager() { - contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class) - .run(ctx -> { - assertThat(ctx).hasSingleBean(ReactiveNeo4jTransactionManager.class); - - // Verify that the transaction manager uses the provided - // database name provider - ReactiveNeo4jTransactionManager transactionManager = ctx - .getBean(ReactiveNeo4jTransactionManager.class); - ReactiveDatabaseSelectionProvider provider = (ReactiveDatabaseSelectionProvider) ReflectionTestUtils - .getField(transactionManager, "databaseSelectionProvider"); - assertThat(provider).isSameAs(ctx.getBean(ReactiveDatabaseSelectionProvider.class)); - }); - } - - @Test - void shouldHonourExistingTransactionManager() { - contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveTransactionManager.class) - .run(ctx -> assertThat(ctx).hasSingleBean(ReactiveTransactionManager.class) - .hasBean("myCustomReactiveTransactionManager")); - } - - @Configuration - static class ConfigurationWithExistingReactiveClient { - - @Bean("myCustomReactiveClient") - ReactiveNeo4jClient neo4jClient(Driver driver) { - return ReactiveNeo4jClient.create(driver); - } - - } - - @Configuration - static class ConfigurationWithExistingReactiveTemplate { - - @Bean("myCustomReactiveOperations") - ReactiveNeo4jOperations neo4jOperations() { - return mock(ReactiveNeo4jOperations.class); - } - - } - - @Configuration - static class ConfigurationWithExistingReactiveTransactionManager { - - @Bean("myCustomReactiveTransactionManager") - ReactiveTransactionManager transactionManager() { - return mock(ReactiveTransactionManager.class); - } - - } - - @Configuration - static class ConfigurationWithExistingReactiveDatabaseSelectionProvider { - - @Bean - ReactiveDatabaseSelectionProvider databaseNameProvider() { - return () -> Mono.just(DatabaseSelection.byName("whatever")); - } - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/City.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/City.java index 27f1db193f..29e84bdca3 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/City.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/City.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/ReactiveCityRepository.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/ReactiveCityRepository.java index 215d9f1716..8b88301d5a 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/ReactiveCityRepository.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/ReactiveCityRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -16,9 +16,6 @@ package org.springframework.boot.autoconfigure.data.neo4j.city; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.neo4j.repository.Neo4jRepository; import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; public interface ReactiveCityRepository extends ReactiveNeo4jRepository { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/Country.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/Country.java index 34c504c098..2ab5a42671 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/Country.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/Country.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -16,12 +16,12 @@ package org.springframework.boot.autoconfigure.data.neo4j.country; +import java.io.Serializable; + import org.springframework.data.neo4j.core.schema.GeneratedValue; import org.springframework.data.neo4j.core.schema.Id; import org.springframework.data.neo4j.core.schema.Node; -import java.io.Serializable; - @Node public class Country implements Serializable { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/ReactiveCountryRepository.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/ReactiveCountryRepository.java index 790aa84d94..c97759cadc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/ReactiveCountryRepository.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/ReactiveCountryRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc index 415e09ade8..12d189b868 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/howto.adoc @@ -2978,7 +2978,7 @@ class ExampleIntegrationTests { @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { - registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl); + registry.add("spring.neo4j.uri", neo4j::getBoltUrl); } } diff --git a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc index 0d34edd13a..4c2e987eae 100644 --- a/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc +++ b/spring-boot-project/spring-boot-docs/src/docs/asciidoc/spring-boot-features.adoc @@ -4532,47 +4532,6 @@ Each will be called in order with the `ConfigBuilder` that is used to build the -[[boot-features-connecting-to-neo4j-embedded]] -==== Using the Embedded Mode -If you add `org.neo4j:neo4j-ogm-embedded-driver` to the dependencies of your application, Spring Boot automatically configures an in-process embedded instance of Neo4j that does not persist any data when your application shuts down. - -NOTE: As the embedded Neo4j OGM driver does not provide the Neo4j kernel itself, you have to declare `org.neo4j:neo4j` as dependency yourself. -Refer to https://neo4j.com/docs/ogm-manual/current/reference/#reference:getting-started[the Neo4j OGM documentation] for a list of compatible versions. - -The embedded driver takes precedence over the other drivers when there are multiple drivers on the classpath. -You can explicitly disable the embedded mode by setting `spring.data.neo4j.embedded.enabled=false`. - -<> automatically make use of an embedded Neo4j instance if the embedded driver and Neo4j kernel are on the classpath as described above. - -NOTE: You can enable persistence for the embedded mode by providing a path to a database file in your configuration, e.g. `spring.data.neo4j.uri=file://var/tmp/graph.db`. - - - -[[boot-features-neo4j-ogm-native-types]] -==== Using Native Types -Neo4j-OGM can map some types, like those in `java.time.*`, to `String`-based properties or to one of the native types that Neo4j provides. -For backwards compatibility reasons the default for Neo4j-OGM is to use a `String`-based representation. -To use native types, add a dependency on either `org.neo4j:neo4j-ogm-bolt-native-types` or `org.neo4j:neo4j-ogm-embedded-native-types`, and configure the configprop:spring.data.neo4j.use-native-types[] property as shown in the following example: - -[source,properties,indent=0,configprops] ----- - spring.data.neo4j.use-native-types=true ----- - - - -[[boot-features-neo4j-ogm-session]] -==== Neo4jSession -By default, if you are running a web application, the session is bound to the thread for the entire processing of the request (that is, it uses the "Open Session in View" pattern). -If you do not want this behavior, add the following line to your `application.properties` file: - -[source,properties,indent=0,configprops] ----- - spring.data.neo4j.open-in-view=false ----- - - - [[boot-features-spring-data-neo4j-repositories]] ==== Spring Data Neo4j Repositories Spring Data includes repository support for Neo4j. diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories index b8e2f1e646..9034663f25 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/main/resources/META-INF/spring.factories @@ -42,7 +42,10 @@ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration # AutoConfigureDataNeo4j auto-configuration imports org.springframework.boot.test.autoconfigure.data.neo4j.AutoConfigureDataNeo4j=\ +org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveDataAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestIntegrationTests.java index c10b33a03c..b806684d18 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestIntegrationTests.java @@ -19,8 +19,6 @@ package org.springframework.boot.test.autoconfigure.data.neo4j; import java.time.Duration; import org.junit.jupiter.api.Test; - -import org.springframework.data.neo4j.core.Neo4jTemplate; import org.testcontainers.containers.Neo4jContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -28,6 +26,7 @@ import org.testcontainers.junit.jupiter.Testcontainers; import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; +import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.test.context.DynamicPropertyRegistry; import org.springframework.test.context.DynamicPropertySource; @@ -49,6 +48,11 @@ class DataNeo4jTestIntegrationTests { static final Neo4jContainer neo4j = new Neo4jContainer<>().withoutAuthentication() .withStartupTimeout(Duration.ofMinutes(10)); + @DynamicPropertySource + static void neo4jProperties(DynamicPropertyRegistry registry) { + registry.add("spring.neo4j.uri", neo4j::getBoltUrl); + } + @Autowired private Neo4jTemplate neo4jTemplate; @@ -58,11 +62,6 @@ class DataNeo4jTestIntegrationTests { @Autowired private ApplicationContext applicationContext; - @DynamicPropertySource - static void neo4jProperties(DynamicPropertyRegistry registry) { - registry.add("spring.neo4j.uri", neo4j::getBoltUrl); - } - @Test void testRepository() { ExampleGraph exampleGraph = new ExampleGraph("Look, new @DataNeo4jTest!"); diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java index b4efc9eac0..f7f7368500 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java @@ -44,14 +44,14 @@ class DataNeo4jTestPropertiesIntegrationTests { static final Neo4jContainer neo4j = new Neo4jContainer<>().withoutAuthentication() .withStartupTimeout(Duration.ofMinutes(10)); - @Autowired - private Environment environment; - @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { registry.add("spring.neo4j.uri", neo4j::getBoltUrl); } + @Autowired + private Environment environment; + @Test void environmentWithNewProfile() { assertThat(this.environment.getActiveProfiles()).containsExactly("test"); diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ReactiveDataNeo4jIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestReactiveIntegrationTests.java similarity index 67% rename from spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ReactiveDataNeo4jIntegrationTests.java rename to spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestReactiveIntegrationTests.java index c85a900c4b..570f484917 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ReactiveDataNeo4jIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestReactiveIntegrationTests.java @@ -16,30 +16,22 @@ package org.springframework.boot.test.autoconfigure.data.neo4j; +import java.time.Duration; + import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; -import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; -import org.springframework.test.context.DynamicPropertyRegistry; -import org.springframework.test.context.DynamicPropertySource; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.transaction.ReactiveTransactionManager; import org.testcontainers.containers.Neo4jContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; import reactor.core.publisher.Mono; import reactor.test.StepVerifier; -import java.time.Duration; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; -import org.neo4j.driver.AccessMode; -import org.neo4j.driver.Driver; -import org.neo4j.driver.Session; -import org.neo4j.driver.SessionConfig; - -import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** @@ -50,7 +42,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; */ @DataNeo4jTest @Testcontainers(disabledWithoutDocker = true) -class ReactiveDataNeo4jIntegrationTests { +class DataNeo4jTestReactiveIntegrationTests { @Container static final Neo4jContainer neo4j = new Neo4jContainer<>("neo4j:4.0").withoutAuthentication() @@ -62,24 +54,19 @@ class ReactiveDataNeo4jIntegrationTests { } @Autowired - private Driver driver; + private ReactiveNeo4jTemplate neo4jTemplate; @Autowired - private ReactiveNeo4jTemplate neo4jTemplate; + private ExampleReactiveRepository exampleRepository; @Autowired private ApplicationContext applicationContext; @Test - void testTemplate() { - - Mono.just(new ExampleGraph("Look, new @DataNeo4jTest with reactive!")).flatMap(neo4jTemplate::save) + void testRepository() { + Mono.just(new ExampleGraph("Look, new @DataNeo4jTest with reactive!")).flatMap(this.exampleRepository::save) .as(StepVerifier::create).expectNextCount(1).verifyComplete(); - - try (Session session = driver.session(SessionConfig.builder().withDefaultAccessMode(AccessMode.READ).build())) { - long cnt = session.run("MATCH (n:ExampleGraph) RETURN count(n) as cnt").single().get("cnt").asLong(); - assertThat(cnt).isEqualTo(1L); - } + StepVerifier.create(this.neo4jTemplate.count(ExampleGraph.class)).expectNext(1L).verifyComplete(); } @Test @@ -88,13 +75,4 @@ class ReactiveDataNeo4jIntegrationTests { .isThrownBy(() -> this.applicationContext.getBean(ExampleService.class)); } - @Test - void didProvideOnlyReactiveTransactionManager() { - - assertThat(this.applicationContext.getBean(ReactiveTransactionManager.class)) - .isInstanceOf(ReactiveNeo4jTransactionManager.class); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.applicationContext.getBean(PlatformTransactionManager.class)); - } - } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestWithIncludeFilterIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestWithIncludeFilterIntegrationTests.java index a8812f06cf..f4f56b8ba5 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestWithIncludeFilterIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestWithIncludeFilterIntegrationTests.java @@ -45,14 +45,14 @@ class DataNeo4jTestWithIncludeFilterIntegrationTests { static final Neo4jContainer neo4j = new Neo4jContainer<>().withoutAuthentication() .withStartupTimeout(Duration.ofMinutes(10)); - @Autowired - private ExampleService service; - @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { registry.add("spring.neo4j.uri", neo4j::getBoltUrl); } + @Autowired + private ExampleService service; + @Test void testService() { assertThat(this.service.hasNode(ExampleGraph.class)).isFalse(); diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTypeExcludeFilterTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTypeExcludeFilterTests.java deleted file mode 100644 index dda71f1dd4..0000000000 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTypeExcludeFilterTests.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (c) 2019-2020 "Neo4j," - * Neo4j Sweden AB [https://neo4j.com] - * - * This file is part of Neo4j. - * - * 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.test.autoconfigure.data.neo4j; - -import org.junit.jupiter.api.Test; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.FilterType; -import org.springframework.core.type.classreading.MetadataReader; -import org.springframework.core.type.classreading.MetadataReaderFactory; -import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; - -import java.io.IOException; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * @author Michael J. Simons - */ -class DataNeo4jTypeExcludeFilterTests { - - private MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); - - @Test - void matchWithExcludeFilter() throws Exception { - DataNeo4jTypeExcludeFilter filter = new DataNeo4jTypeExcludeFilter(WithExcludeFilter.class); - assertThat(excludes(filter, ExampleService.class)).isTrue(); - assertThat(excludes(filter, ExampleRepository.class)).isTrue(); - } - - @Test - void matchWithoutExcludeFilter() throws Exception { - DataNeo4jTypeExcludeFilter filter = new DataNeo4jTypeExcludeFilter(WithoutExcludeFilter.class); - assertThat(excludes(filter, ExampleService.class)).isTrue(); - assertThat(excludes(filter, ExampleRepository.class)).isFalse(); - } - - @DataNeo4jTest( - excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ExampleRepository.class)) - static class WithExcludeFilter { - - } - - @DataNeo4jTest - static class WithoutExcludeFilter { - - } - - private boolean excludes(DataNeo4jTypeExcludeFilter filter, Class type) throws IOException { - MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(type.getName()); - return filter.match(metadataReader, this.metadataReaderFactory); - } - -} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleGraph.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleGraph.java index 4c3736a2d4..7012498130 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleGraph.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleGraph.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 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. @@ -25,7 +25,6 @@ import org.springframework.data.neo4j.core.schema.Property; * Example graph used with {@link DataNeo4jTest @DataNeo4jTest} tests. * * @author Eddú Meléndez - * @author Michael J. Simons */ @Node public class ExampleGraph { diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleReactiveRepository.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleReactiveRepository.java new file mode 100644 index 0000000000..8fd588fdb4 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleReactiveRepository.java @@ -0,0 +1,28 @@ +/* + * 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.test.autoconfigure.data.neo4j; + +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; + +/** + * Example reactive repository used with {@link DataNeo4jTest @DataNeo4jTest} tests. + * + * @author Stephane Nicoll + */ +interface ExampleReactiveRepository extends ReactiveNeo4jRepository { + +} diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-neo4j/src/main/resources/application.properties b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-neo4j/src/main/resources/application.properties index 6dabd65d3e..e69de29bb2 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-neo4j/src/main/resources/application.properties +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-neo4j/src/main/resources/application.properties @@ -1 +0,0 @@ -# spring.data.neo4j.open-in-view=true