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/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..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 @@ -16,32 +16,37 @@ 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.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.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.autoconfigure.domain.EntityScanPackages; +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.transaction.Neo4jTransactionManager; -import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor; +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; -import org.springframework.util.StringUtils; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; /** * {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j. @@ -51,76 +56,62 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; * @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) +@ConditionalOnClass({ Driver.class, Neo4jTransactionManager.class, PlatformTransactionManager.class }) +@EnableConfigurationProperties(Neo4jDataProperties.class) +@ConditionalOnBean(Driver.class) +@AutoConfigureBefore(TransactionAutoConfiguration.class) +@AutoConfigureAfter(Neo4jAutoConfiguration.class) +@Import(Neo4jDefaultCallbacksRegistrar.class) public class Neo4jDataAutoConfiguration { @Bean + @ConditionalOnMissingBean + public Neo4jConversions neo4jConversions() { + return new Neo4jConversions(); + } + + @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; + } + + @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(SessionFactory sessionFactory, - ObjectProvider transactionManagerCustomizers) { - Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(sessionFactory); - transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager)); + public Neo4jTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider, + ObjectProvider optionalCustomizers) { + Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(driver, databaseNameProvider); + optionalCustomizers.ifAvailable((customizer) -> customizer.customize(transactionManager)); return transactionManager; } - @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); - } - - }; - } - - } - } 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..ea1c190524 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataProperties.java @@ -0,0 +1,43 @@ +/* + * 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; + +/** + * Configuration properties for Spring Data Neo4j. + * + * @author Michael J. Simons + * @since 2.4.0 + */ +@ConfigurationProperties(prefix = "spring.data.neo4j") +public class Neo4jDataProperties { + + /** + * Database name to use. By default, the server decides 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/Neo4jReactiveDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataAutoConfiguration.java new file mode 100644 index 0000000000..58bcb406d2 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataAutoConfiguration.java @@ -0,0 +1,84 @@ +/* + * 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.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.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +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; + +/** + * {@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({ Driver.class, ReactiveNeo4jTransactionManager.class, ReactiveTransactionManager.class, + Flux.class }) +@ConditionalOnBean(Driver.class) +@AutoConfigureAfter(Neo4jDataAutoConfiguration.class) +@Import(Neo4jDefaultReactiveCallbacksRegistrar.class) +public class Neo4jReactiveDataAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + 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 + public ReactiveNeo4jClient reactiveNeo4jClient(Driver driver) { + return ReactiveNeo4jClient.create(driver); + } + + @Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME) + @ConditionalOnMissingBean(ReactiveNeo4jOperations.class) + 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) + 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/Neo4jReactiveRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesAutoConfiguration.java new file mode 100644 index 0000000000..27cb2ee200 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesAutoConfiguration.java @@ -0,0 +1,51 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data.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; +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; + +/** + * {@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({ Driver.class, ReactiveNeo4jRepository.class, Flux.class }) +@ConditionalOnMissingBean({ ReactiveNeo4jRepositoryFactoryBean.class, + ReactiveNeo4jRepositoryConfigurationExtension.class }) +@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.REACTIVE) +@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/Neo4jReactiveRepositoriesRegistrar.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesRegistrar.java new file mode 100644 index 0000000000..e52749df55 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesRegistrar.java @@ -0,0 +1,55 @@ +/* + * 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.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 Spring Data Neo4j reactive + * Repositories. + * + * @author Michael J. Simons + */ +class Neo4jReactiveRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport { + + @Override + protected Class getAnnotation() { + return EnableReactiveNeo4jRepositories.class; + } + + @Override + protected Class getConfiguration() { + return EnableReactiveNeo4jRepositoriesConfiguration.class; + } + + @Override + protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() { + return new ReactiveNeo4jRepositoryConfigurationExtension(); + } + + @EnableReactiveNeo4jRepositories + 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 54de8aaa2f..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 @@ -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,13 +16,14 @@ 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.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; @@ -34,10 +35,10 @@ import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryB * {@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}. + * 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. @@ -45,14 +46,14 @@ import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryB * @author Dave Syer * @author Oliver Gierke * @author Josh Long + * @author Michael J. Simons * @since 1.4.0 * @see EnableNeo4jRepositories */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ Neo4jSession.class, Neo4jRepository.class }) +@ConditionalOnClass({ Driver.class, Neo4jRepository.class }) @ConditionalOnMissingBean({ Neo4jRepositoryFactoryBean.class, Neo4jRepositoryConfigurationExtension.class }) -@ConditionalOnProperty(prefix = "spring.data.neo4j.repositories", name = "enabled", havingValue = "true", - matchIfMissing = true) +@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.IMPERATIVE) @Import(Neo4jRepositoriesRegistrar.class) @AutoConfigureAfter(Neo4jDataAutoConfiguration.class) public class Neo4jRepositoriesAutoConfiguration { 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/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/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..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 @@ -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 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 419c940790..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,7 +19,10 @@ 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.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; @@ -31,11 +34,12 @@ 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 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,12 +99,12 @@ 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, JpaRepositoriesAutoConfiguration.class, Neo4jDataAutoConfiguration.class, - Neo4jRepositoriesAutoConfiguration.class); + Neo4jReactiveDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class, + Neo4jReactiveRepositoriesAutoConfiguration.class); context.refresh(); this.context = context; } @@ -108,7 +113,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 +129,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..4740cf67dc --- /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-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.mockito.Mockito; +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; + +/** + * 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); + 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 1f523d026e..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 @@ -16,257 +16,124 @@ 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 org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.boot.autoconfigure.AutoConfigurationPackages; 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.test.context.FilteredClassLoader; +import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; 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 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.transaction.PlatformTransactionManager; 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; /** - * Tests for {@link Neo4jDataAutoConfiguration}. Tests should not use the embedded driver - * as it requires the complete Neo4j-Kernel and server to function properly. + * Tests for {@link Neo4jDataAutoConfiguration}. * * @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() + .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); + void shouldProvideConversions() { + this.contextRunner.run((context) -> assertThat(context).hasSingleBean(Neo4jConversions.class)); + } + + @Test + void shouldProvideDefaultDatabaseNameProvider() { + this.contextRunner.run((context) -> { + assertThat(context).hasSingleBean(DatabaseSelectionProvider.class); + assertThat(context.getBean(DatabaseSelectionProvider.class)) + .isSameAs(DatabaseSelectionProvider.getDefaultSelectionProvider()); + }); + } + + @Test + 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 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 shouldProvideNeo4jClient() { + this.contextRunner.run((context) -> assertThat(context).hasSingleBean(Neo4jClient.class)); + } + + @Test + void shouldReuseExistingNeo4jClient() { + this.contextRunner.withBean("myCustomClient", Neo4jClient.class, () -> mock(Neo4jClient.class)) + .run((context) -> assertThat(context).hasSingleBean(Neo4jClient.class).hasBean("myCustomClient")); + } + + @Test + 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 shouldReuseExistingNeo4jTemplate() { + this.contextRunner.withBean("myCustomOperations", Neo4jOperations.class, () -> mock(Neo4jOperations.class)).run( + (context) -> assertThat(context).hasSingleBean(Neo4jOperations.class).hasBean("myCustomOperations")); + } + + @Test + void shouldProvideTransactionManager() { + this.contextRunner.withUserConfiguration(CustomDatabaseSelectionProviderConfiguration.class).run((context) -> { assertThat(context).hasSingleBean(Neo4jTransactionManager.class); - assertThat(context).doesNotHaveBean(OpenSessionInViewInterceptor.class); - assertThat(context).doesNotHaveBean(BookmarkManager.class); + assertThat(context.getBean(Neo4jTransactionManager.class)).extracting("databaseSelectionProvider") + .isSameAs(context.getBean(DatabaseSelectionProvider.class)); }); } @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(); - }); - } - - @Test - void customSessionFactory() { - this.contextRunner.withUserConfiguration(CustomSessionFactory.class).run((context) -> { - assertThat(context).doesNotHaveBean(org.neo4j.ogm.config.Configuration.class); - assertThat(context).hasSingleBean(SessionFactory.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); - }); - } - - @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); - }); - } - - @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); - } - finally { - context.close(); - } - } - - @Test - void openSessionInViewInterceptorCanBeEnabled() { - this.contextRunner.withPropertyValues("spring.data.neo4j.open-in-view:true") - .run((context) -> assertThat(context).hasSingleBean(OpenSessionInViewInterceptor.class)); - } - - @Test - void shouldBeAbleToUseNativeTypesWithBolt() { + void shouldReuseExistingTransactionManager() { 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(); - } + .withBean("myCustomTransactionManager", PlatformTransactionManager.class, + () -> mock(PlatformTransactionManager.class)) + .run((context) -> assertThat(context).hasSingleBean(PlatformTransactionManager.class) + .hasBean("myCustomTransactionManager")); } @Configuration(proxyBeanMethods = false) - @EntityScan(basePackageClasses = Country.class) - static class TestConfiguration { - - } - - @Configuration(proxyBeanMethods = false) - static class CustomSessionFactory { + static class CustomDatabaseSelectionProviderConfiguration { @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("custom"); } } 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/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 new file mode 100644 index 0000000000..c5f3a9cb53 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationIntegrationTests.java @@ -0,0 +1,71 @@ +/* + * 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.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; +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 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 +@Testcontainers(disabledWithoutDocker = true) +public class Neo4jRepositoriesAutoConfigurationIntegrationTests { + + @Container + 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); + } + + @Autowired + private CountryRepository countryRepository; + + @Test + void ensureRepositoryIsReady() { + assertThat(this.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..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. @@ -16,25 +16,26 @@ 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.mockito.Mockito; -import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.autoconfigure.data.alt.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.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.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.Neo4jRepository; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.repository.support.ReactiveNeo4jRepositoryFactoryBean; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** * Tests for {@link Neo4jRepositoriesAutoConfiguration}. @@ -44,50 +45,62 @@ 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(Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class)); - @AfterEach - void close() { - this.context.close(); + @Test + void configurationWithDefaultRepositories() { + this.contextRunner.withUserConfiguration(TestConfiguration.class) + .run((context) -> assertThat(context).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 configurationWithNoRepositories() { + this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> assertThat(context) + .hasSingleBean(Neo4jTransactionManager.class).doesNotHaveBean(Neo4jRepository.class)); } @Test - void testNoRepositoryConfiguration() { - prepareApplicationContext(EmptyConfiguration.class); - assertThat(this.context.getBean(SessionFactory.class)).isNotNull(); - } - - @Test - void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { - prepareApplicationContext(CustomizedConfiguration.class); - assertThat(this.context.getBean(CityNeo4jRepository.class)).isNotNull(); + void configurationWithDisabledRepositories() { + this.contextRunner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.data.neo4j.repositories.type=none") + .run((context) -> assertThat(context).doesNotHaveBean(Neo4jRepository.class)); } @Test void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() { - prepareApplicationContext(SortOfInvalidCustomConfiguration.class); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.context.getBean(CityRepository.class)); + this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class) + .run((context) -> assertThat(context).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) + .run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class) + .doesNotHaveBean(ReactiveCityRepository.class).hasSingleBean(CountryRepository.class) + .doesNotHaveBean(ReactiveCountryRepository.class)); + } + + @Configuration(proxyBeanMethods = false) + @EnableNeo4jRepositories(basePackageClasses = CountryRepository.class) + static class WithCustomRepositoryScan { + + } + + @Configuration(proxyBeanMethods = false) + static class WithFakeEnabledReactiveNeo4jRepositories { + + @Bean + ReactiveNeo4jRepositoryFactoryBean reactiveNeo4jRepositoryFactoryBean() { + return Mockito.mock(ReactiveNeo4jRepositoryFactoryBean.class); + } + } @Configuration(proxyBeanMethods = false) @@ -103,14 +116,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/city/City.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/City.java index 1ae1b828c0..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. @@ -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..8b88301d5a --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/ReactiveCityRepository.java @@ -0,0 +1,23 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data.neo4j.city; + +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..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. @@ -18,11 +18,11 @@ package org.springframework.boot.autoconfigure.data.neo4j.country; 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.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 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..c97759cadc --- /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-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.country; + +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; + +public interface ReactiveCountryRepository extends ReactiveNeo4jRepository { + +} 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..a79f8abba8 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" @@ -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 = [ @@ -1563,7 +1550,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" 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 90f06dc040..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,7 +19,6 @@ 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.testcontainers.containers.Neo4jContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -27,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; @@ -48,8 +48,13 @@ 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 Session session; + private Neo4jTemplate neo4jTemplate; @Autowired private ExampleRepository exampleRepository; @@ -57,19 +62,13 @@ class DataNeo4jTestIntegrationTests { @Autowired private ApplicationContext applicationContext; - @DynamicPropertySource - static void neo4jProperties(DynamicPropertyRegistry registry) { - registry.add("spring.data.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..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.data.neo4j.uri", neo4j::getBoltUrl); + 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/DataNeo4jTestReactiveIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestReactiveIntegrationTests.java new file mode 100644 index 0000000000..570f484917 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestReactiveIntegrationTests.java @@ -0,0 +1,78 @@ +/* + * 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 java.time.Duration; + +import org.junit.jupiter.api.Test; +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 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 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 DataNeo4jTestReactiveIntegrationTests { + + @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 ReactiveNeo4jTemplate neo4jTemplate; + + @Autowired + private ExampleReactiveRepository exampleRepository; + + @Autowired + private ApplicationContext applicationContext; + + @Test + void testRepository() { + Mono.just(new ExampleGraph("Look, new @DataNeo4jTest with reactive!")).flatMap(this.exampleRepository::save) + .as(StepVerifier::create).expectNextCount(1).verifyComplete(); + StepVerifier.create(this.neo4jTemplate.count(ExampleGraph.class)).expectNext(1L).verifyComplete(); + } + + @Test + void didNotInjectExampleService() { + assertThatExceptionOfType(NoSuchBeanDefinitionException.class) + .isThrownBy(() -> this.applicationContext.getBean(ExampleService.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 7533e60b52..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.data.neo4j.uri", neo4j::getBoltUrl); + 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/ExampleGraph.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleGraph.java index 41d3fb2aa2..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. @@ -16,17 +16,17 @@ 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 */ -@NodeEntity +@Node public class ExampleGraph { @Id @@ -36,6 +36,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/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-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-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 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