diff --git a/spring-boot-project/spring-boot-autoconfigure/build.gradle b/spring-boot-project/spring-boot-autoconfigure/build.gradle index b982361e7a..58265433bc 100644 --- a/spring-boot-project/spring-boot-autoconfigure/build.gradle +++ b/spring-boot-project/spring-boot-autoconfigure/build.gradle @@ -171,9 +171,6 @@ dependencies { testImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") testImplementation("org.junit.jupiter:junit-jupiter") testImplementation("org.mockito:mockito-core") - testImplementation("org.neo4j:neo4j-ogm-bolt-native-types") - testImplementation("org.neo4j:neo4j-ogm-http-driver") - testImplementation("org.neo4j:neo4j-ogm-embedded-driver") testImplementation("org.springframework:spring-test") testImplementation("org.springframework.kafka:spring-kafka-test") testImplementation("org.springframework.security:spring-security-test") diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jBookmarkManagementConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jBookmarkManagementConfiguration.java deleted file mode 100644 index 0d71fb6866..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jBookmarkManagementConfiguration.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.autoconfigure.data.neo4j; - -import com.github.benmanes.caffeine.cache.Caffeine; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.cache.caffeine.CaffeineCacheManager; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Scope; -import org.springframework.context.annotation.ScopedProxyMode; -import org.springframework.data.neo4j.bookmark.BeanFactoryBookmarkOperationAdvisor; -import org.springframework.data.neo4j.bookmark.BookmarkInterceptor; -import org.springframework.data.neo4j.bookmark.BookmarkManager; -import org.springframework.data.neo4j.bookmark.CaffeineBookmarkManager; -import org.springframework.web.context.WebApplicationContext; - -/** - * Provides a {@link BookmarkManager} for Neo4j's bookmark support based on Caffeine if - * available. Depending on the application's type (web or not) the bookmark manager will - * be bound to the application or the request, as recommend by Spring Data Neo4j. - * - * @author Michael Simons - */ -@Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ Caffeine.class, CaffeineCacheManager.class }) -@ConditionalOnMissingBean(BookmarkManager.class) -@ConditionalOnBean({ BeanFactoryBookmarkOperationAdvisor.class, BookmarkInterceptor.class }) -class Neo4jBookmarkManagementConfiguration { - - private static final String BOOKMARK_MANAGER_BEAN_NAME = "bookmarkManager"; - - @Bean(BOOKMARK_MANAGER_BEAN_NAME) - @ConditionalOnWebApplication - @Scope(value = WebApplicationContext.SCOPE_REQUEST, proxyMode = ScopedProxyMode.INTERFACES) - BookmarkManager requestScopedBookmarkManager() { - return new CaffeineBookmarkManager(); - } - - @Bean(BOOKMARK_MANAGER_BEAN_NAME) - @ConditionalOnNotWebApplication - BookmarkManager singletonScopedBookmarkManager() { - return new CaffeineBookmarkManager(); - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java index bc02c39ce4..f50ecd55a0 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java @@ -16,111 +16,62 @@ package org.springframework.boot.autoconfigure.data.neo4j; -import java.util.List; +import java.util.Set; -import org.neo4j.ogm.session.SessionFactory; -import org.neo4j.ogm.session.event.EventListener; +import org.neo4j.driver.Driver; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.boot.autoconfigure.AutoConfigurationPackages; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; -import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type; -import org.springframework.boot.autoconfigure.domain.EntityScanPackages; -import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; +import org.springframework.boot.autoconfigure.domain.EntityScanner; +import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.data.neo4j.transaction.Neo4jTransactionManager; -import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor; -import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.util.StringUtils; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.data.neo4j.core.convert.Neo4jConversions; +import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext; +import org.springframework.data.neo4j.core.schema.Node; /** - * {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j. + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j. Automatic + * configuration of base infrastructure that imports configuration for both imperative and + * reactive Neo4j repositories. * * @author Michael Hunger * @author Josh Long * @author Vince Bickers * @author Stephane Nicoll * @author Kazuki Shimizu - * @author Michael Simons + * @author Michael J Simons * @since 1.4.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ SessionFactory.class, Neo4jTransactionManager.class, PlatformTransactionManager.class }) -@EnableConfigurationProperties(Neo4jProperties.class) -@Import(Neo4jBookmarkManagementConfiguration.class) +@ConditionalOnBean(Driver.class) +@EnableConfigurationProperties(Neo4jDataProperties.class) +@AutoConfigureAfter(Neo4jAutoConfiguration.class) +@AutoConfigureBefore(TransactionAutoConfiguration.class) +@Import({ Neo4jDataConfiguration.class, Neo4jReactiveDataConfiguration.class }) public class Neo4jDataAutoConfiguration { @Bean - @ConditionalOnMissingBean(PlatformTransactionManager.class) - public Neo4jTransactionManager transactionManager(SessionFactory sessionFactory, - ObjectProvider transactionManagerCustomizers) { - Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(sessionFactory); - transactionManagerCustomizers.ifAvailable((customizers) -> customizers.customize(transactionManager)); - return transactionManager; + @ConditionalOnMissingBean + public Neo4jConversions neo4jConversions() { + return new Neo4jConversions(); } - @Configuration(proxyBeanMethods = false) - @ConditionalOnMissingBean(SessionFactory.class) - static class Neo4jOgmSessionFactoryConfiguration { - - @Bean - @ConditionalOnMissingBean - org.neo4j.ogm.config.Configuration configuration(Neo4jProperties properties) { - return properties.createConfiguration(); - } - - @Bean - SessionFactory sessionFactory(org.neo4j.ogm.config.Configuration configuration, BeanFactory beanFactory, - ObjectProvider eventListeners) { - SessionFactory sessionFactory = new SessionFactory(configuration, getPackagesToScan(beanFactory)); - eventListeners.orderedStream().forEach(sessionFactory::register); - return sessionFactory; - } - - private String[] getPackagesToScan(BeanFactory beanFactory) { - List packages = EntityScanPackages.get(beanFactory).getPackageNames(); - if (packages.isEmpty() && AutoConfigurationPackages.has(beanFactory)) { - packages = AutoConfigurationPackages.get(beanFactory); - } - return StringUtils.toStringArray(packages); - } - - } - - @Configuration(proxyBeanMethods = false) - @ConditionalOnWebApplication(type = Type.SERVLET) - @ConditionalOnClass({ WebMvcConfigurer.class, OpenSessionInViewInterceptor.class }) - @ConditionalOnMissingBean(OpenSessionInViewInterceptor.class) - @ConditionalOnProperty(prefix = "spring.data.neo4j", name = "open-in-view", havingValue = "true") - static class Neo4jWebConfiguration { - - @Bean - OpenSessionInViewInterceptor neo4jOpenSessionInViewInterceptor() { - return new OpenSessionInViewInterceptor(); - } - - @Bean - WebMvcConfigurer neo4jOpenSessionInViewInterceptorConfigurer(OpenSessionInViewInterceptor interceptor) { - return new WebMvcConfigurer() { - - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addWebRequestInterceptor(interceptor); - } - - }; - } - + @Bean + @ConditionalOnMissingBean + public Neo4jMappingContext neo4jMappingContext(ApplicationContext applicationContext, + Neo4jConversions neo4jConversions) throws ClassNotFoundException { + Set> initialEntityClasses = new EntityScanner(applicationContext).scan(Node.class); + Neo4jMappingContext context = new Neo4jMappingContext(neo4jConversions); + context.setInitialEntitySet(initialEntityClasses); + return context; } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataConfiguration.java new file mode 100644 index 0000000000..070ab1471c --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataConfiguration.java @@ -0,0 +1,88 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data.neo4j; + +import org.neo4j.driver.Driver; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType; +import org.springframework.boot.autoconfigure.data.RepositoryType; +import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.env.Environment; +import org.springframework.data.neo4j.config.Neo4jDefaultCallbacksRegistrar; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.Neo4jClient; +import org.springframework.data.neo4j.core.Neo4jOperations; +import org.springframework.data.neo4j.core.Neo4jTemplate; +import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; +import org.springframework.transaction.PlatformTransactionManager; + +/** + * Internal configuration of Neo4j client and transaction manager. + * + * @author Michael J. Simons + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({ Neo4jTransactionManager.class, PlatformTransactionManager.class }) +@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.IMPERATIVE) +@AutoConfigureAfter(Neo4jAutoConfiguration.class) +@AutoConfigureBefore(Neo4jRepositoriesConfiguration.class) +@Import(Neo4jDefaultCallbacksRegistrar.class) +class Neo4jDataConfiguration { + + @Bean("databaseSelectionProvider") + @ConditionalOnMissingBean + DatabaseSelectionProvider defaultSelectionProvider(Environment environment) { + String database = environment.getProperty("spring.data.neo4j.database"); + if (database != null) { + return DatabaseSelectionProvider.createStaticDatabaseSelectionProvider(database); + } + return DatabaseSelectionProvider.getDefaultSelectionProvider(); + } + + @Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME) + @ConditionalOnMissingBean + Neo4jClient neo4jClient(Driver driver) { + return Neo4jClient.create(driver); + } + + @Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME) + @ConditionalOnMissingBean(Neo4jOperations.class) + Neo4jTemplate neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext, + DatabaseSelectionProvider databaseNameProvider) { + return new Neo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider); + } + + @Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME) + @ConditionalOnMissingBean(PlatformTransactionManager.class) + Neo4jTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider, + ObjectProvider optionalCustomizers) { + Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(driver, databaseNameProvider); + optionalCustomizers.ifAvailable((customizer) -> customizer.customize(transactionManager)); + return transactionManager; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataProperties.java new file mode 100644 index 0000000000..dad06eca71 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataProperties.java @@ -0,0 +1,47 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data.neo4j; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; + +/** + * Configuration properties for Spring Data Neo4j. + * + * @author Michael J. Simons + * @since 2.4.0 + */ +@ConfigurationProperties(prefix = "spring.data.neo4j") +public class Neo4jDataProperties { + + /** + * A statically configured database. This property is only applicable when connecting + * against a 4.0 cluster or server and will lead to errors if used with a prior + * version of Neo4j. Leave this null (the default) to indicate that you like the + * server to decide the default database to use. + */ + private String database; + + public String getDatabase() { + return this.database; + } + + public void setDatabase(String database) { + this.database = database; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jProperties.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jProperties.java deleted file mode 100644 index 57bf0660d4..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jProperties.java +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2012-2020 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.autoconfigure.data.neo4j; - -import org.neo4j.ogm.config.AutoIndexMode; -import org.neo4j.ogm.config.Configuration; -import org.neo4j.ogm.config.Configuration.Builder; - -import org.springframework.beans.BeansException; -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.context.ApplicationContext; -import org.springframework.context.ApplicationContextAware; -import org.springframework.util.ClassUtils; - -/** - * Configuration properties for Neo4j. - * - * @author Stephane Nicoll - * @author Michael Hunger - * @author Vince Bickers - * @author Aurélien Leboulanger - * @author Michael Simons - * @since 1.4.0 - */ -@ConfigurationProperties(prefix = "spring.data.neo4j") -public class Neo4jProperties implements ApplicationContextAware { - - static final String EMBEDDED_DRIVER = "org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver"; - - static final String HTTP_DRIVER = "org.neo4j.ogm.drivers.http.driver.HttpDriver"; - - static final String DEFAULT_BOLT_URI = "bolt://localhost:7687"; - - static final String BOLT_DRIVER = "org.neo4j.ogm.drivers.bolt.driver.BoltDriver"; - - /** - * URI used by the driver. Auto-detected by default. - */ - private String uri; - - /** - * Login user of the server. - */ - private String username; - - /** - * Login password of the server. - */ - private String password; - - /** - * Auto index mode. - */ - private AutoIndexMode autoIndex = AutoIndexMode.NONE; - - /** - * Whether to use Neo4j native types wherever possible. - */ - private boolean useNativeTypes = false; - - private final Embedded embedded = new Embedded(); - - private ClassLoader classLoader = Neo4jProperties.class.getClassLoader(); - - public String getUri() { - return this.uri; - } - - public void setUri(String uri) { - this.uri = uri; - } - - public String getUsername() { - return this.username; - } - - public void setUsername(String username) { - this.username = username; - } - - public String getPassword() { - return this.password; - } - - public void setPassword(String password) { - this.password = password; - } - - public AutoIndexMode getAutoIndex() { - return this.autoIndex; - } - - public void setAutoIndex(AutoIndexMode autoIndex) { - this.autoIndex = autoIndex; - } - - public boolean isUseNativeTypes() { - return this.useNativeTypes; - } - - public void setUseNativeTypes(boolean useNativeTypes) { - this.useNativeTypes = useNativeTypes; - } - - public Embedded getEmbedded() { - return this.embedded; - } - - @Override - public void setApplicationContext(ApplicationContext ctx) throws BeansException { - this.classLoader = ctx.getClassLoader(); - } - - /** - * Create a {@link Configuration} based on the state of this instance. - * @return a configuration - */ - public Configuration createConfiguration() { - Builder builder = new Builder(); - configure(builder); - return builder.build(); - } - - private void configure(Builder builder) { - if (this.uri != null) { - builder.uri(this.uri); - } - else { - configureUriWithDefaults(builder); - } - if (this.username != null && this.password != null) { - builder.credentials(this.username, this.password); - } - builder.autoIndex(getAutoIndex().getName()); - if (this.useNativeTypes) { - builder.useNativeTypes(); - } - } - - private void configureUriWithDefaults(Builder builder) { - if (!getEmbedded().isEnabled() || !ClassUtils.isPresent(EMBEDDED_DRIVER, this.classLoader)) { - builder.uri(DEFAULT_BOLT_URI); - } - } - - public static class Embedded { - - /** - * Whether to enable embedded mode if the embedded driver is available. - */ - private boolean enabled = true; - - public boolean isEnabled() { - return this.enabled; - } - - public void setEnabled(boolean enabled) { - this.enabled = enabled; - } - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataConfiguration.java new file mode 100644 index 0000000000..c43fb455eb --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveDataConfiguration.java @@ -0,0 +1,92 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data.neo4j; + +import org.neo4j.driver.Driver; +import reactor.core.publisher.Flux; + +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.AutoConfigureBefore; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType; +import org.springframework.boot.autoconfigure.data.RepositoryType; +import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.core.annotation.Order; +import org.springframework.data.neo4j.config.Neo4jDefaultReactiveCallbacksRegistrar; +import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; +import org.springframework.data.neo4j.core.ReactiveNeo4jClient; +import org.springframework.data.neo4j.core.ReactiveNeo4jOperations; +import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; +import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext; +import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; +import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension; +import org.springframework.transaction.ReactiveTransactionManager; + +/** + * Internal configuration for the reactive Neo4j client. + * + * @author Michael J. Simons + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({ ReactiveNeo4jTransactionManager.class, ReactiveTransactionManager.class, Flux.class }) +@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.REACTIVE) +@AutoConfigureAfter(Neo4jAutoConfiguration.class) +@AutoConfigureBefore(Neo4jReactiveRepositoriesConfiguration.class) +@Import(Neo4jDefaultReactiveCallbacksRegistrar.class) +class Neo4jReactiveDataConfiguration { + + @Bean("reactiveDatabaseSelectionProvider") + @ConditionalOnProperty(prefix = "spring.data.neo4j", name = "database") + @ConditionalOnMissingBean + @Order(-30) + ReactiveDatabaseSelectionProvider staticDatabaseSelectionProvider(Neo4jDataProperties dataProperties) { + return ReactiveDatabaseSelectionProvider.createStaticDatabaseSelectionProvider(dataProperties.getDatabase()); + } + + @Bean("reactiveDatabaseSelectionProvider") + @ConditionalOnMissingBean + @Order(-20) + ReactiveDatabaseSelectionProvider defaultSelectionProvider() { + return ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider(); + } + + @Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME) + @ConditionalOnMissingBean + ReactiveNeo4jClient neo4jClient(Driver driver) { + return ReactiveNeo4jClient.create(driver); + } + + @Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME) + @ConditionalOnMissingBean(ReactiveNeo4jOperations.class) + ReactiveNeo4jTemplate neo4jTemplate(ReactiveNeo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext, + ReactiveDatabaseSelectionProvider databaseNameProvider) { + return new ReactiveNeo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider); + } + + @Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME) + @ConditionalOnMissingBean(ReactiveTransactionManager.class) + ReactiveTransactionManager transactionManager(Driver driver, + ReactiveDatabaseSelectionProvider databaseNameProvider) { + return new ReactiveNeo4jTransactionManager(driver, databaseNameProvider); + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfiguration.java new file mode 100644 index 0000000000..281ba5ce4e --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfiguration.java @@ -0,0 +1,44 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data.neo4j; + +import reactor.core.publisher.Flux; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType; +import org.springframework.boot.autoconfigure.data.RepositoryType; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; +import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension; +import org.springframework.data.neo4j.repository.support.ReactiveNeo4jRepositoryFactoryBean; + +/** + * Imports the registrar for reactive Neo4j repositories. + * + * @author Michael J. Simons + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass({ Flux.class, ReactiveNeo4jRepository.class }) +@ConditionalOnMissingBean({ ReactiveNeo4jRepositoryFactoryBean.class, + ReactiveNeo4jRepositoryConfigurationExtension.class }) +@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.REACTIVE) +@Import(Neo4jReactiveRepositoriesConfigureRegistrar.class) +final class Neo4jReactiveRepositoriesConfiguration { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfigureRegistrar.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfigureRegistrar.java new file mode 100644 index 0000000000..5561bc9e44 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jReactiveRepositoriesConfigureRegistrar.java @@ -0,0 +1,54 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data.neo4j; + +import java.lang.annotation.Annotation; + +import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport; +import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; +import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension; +import org.springframework.data.repository.config.RepositoryConfigurationExtension; + +/** + * {@link ImportBeanDefinitionRegistrar} used to auto-configure reactive Spring Data Neo4j + * Repositories. + * + * @author Michael J. Simons + */ +final class Neo4jReactiveRepositoriesConfigureRegistrar extends AbstractRepositoryConfigurationSourceSupport { + + @Override + protected Class getAnnotation() { + return EnableReactiveNeo4jRepositories.class; + } + + @Override + protected Class getConfiguration() { + return SpringDataNeo4jConfiguration.class; + } + + @Override + protected RepositoryConfigurationExtension getRepositoryConfigurationExtension() { + return new ReactiveNeo4jRepositoryConfigurationExtension(); + } + + @EnableReactiveNeo4jRepositories + private static class SpringDataNeo4jConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java index 54de8aaa2f..c611ad42c5 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,45 +16,29 @@ package org.springframework.boot.autoconfigure.data.neo4j; -import org.neo4j.ogm.session.Neo4jSession; +import org.neo4j.driver.Driver; import org.springframework.boot.autoconfigure.AutoConfigureAfter; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; -import org.springframework.data.neo4j.repository.Neo4jRepository; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; -import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; -import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean; /** - * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Neo4j - * Repositories. - *

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

- * Once in effect, the auto-configuration is the equivalent of enabling Neo4j repositories - * using the {@link EnableNeo4jRepositories @EnableNeo4jRepositories} annotation. + * Shared entry point for the configuration of Spring Data Neo4j repositories in their + * imperative and reactive forms. * * @author Dave Syer * @author Oliver Gierke * @author Josh Long - * @since 1.4.0 + * @author Michael J. Simons * @see EnableNeo4jRepositories + * @since 1.4.0 */ @Configuration(proxyBeanMethods = false) -@ConditionalOnClass({ Neo4jSession.class, Neo4jRepository.class }) -@ConditionalOnMissingBean({ Neo4jRepositoryFactoryBean.class, Neo4jRepositoryConfigurationExtension.class }) -@ConditionalOnProperty(prefix = "spring.data.neo4j.repositories", name = "enabled", havingValue = "true", - matchIfMissing = true) -@Import(Neo4jRepositoriesRegistrar.class) +@ConditionalOnClass(Driver.class) @AutoConfigureAfter(Neo4jDataAutoConfiguration.class) +@Import({ Neo4jRepositoriesConfiguration.class, Neo4jReactiveRepositoriesConfiguration.class }) public class Neo4jRepositoriesAutoConfiguration { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfiguration.java new file mode 100644 index 0000000000..7a190c6822 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfiguration.java @@ -0,0 +1,41 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data.neo4j; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType; +import org.springframework.boot.autoconfigure.data.RepositoryType; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; +import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean; + +/** + * Imports the registrar for imperative Neo4j repositories. + * + * @author Michael J. Simons + */ +@Configuration(proxyBeanMethods = false) +@ConditionalOnClass(Neo4jRepository.class) +@ConditionalOnMissingBean({ Neo4jRepositoryFactoryBean.class, Neo4jRepositoryConfigurationExtension.class }) +@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.IMPERATIVE) +@Import(Neo4jRepositoriesConfigureRegistrar.class) +class Neo4jRepositoriesConfiguration { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesRegistrar.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfigureRegistrar.java similarity index 81% rename from spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesRegistrar.java rename to spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfigureRegistrar.java index 976581095e..268dff593b 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesRegistrar.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesConfigureRegistrar.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ package org.springframework.boot.autoconfigure.data.neo4j; import java.lang.annotation.Annotation; import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport; -import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension; import org.springframework.data.repository.config.RepositoryConfigurationExtension; @@ -29,8 +28,9 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi * Repositories. * * @author Michael Hunger + * @author Michael J. Simons */ -class Neo4jRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport { +class Neo4jRepositoriesConfigureRegistrar extends AbstractRepositoryConfigurationSourceSupport { @Override protected Class getAnnotation() { @@ -39,7 +39,7 @@ class Neo4jRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSu @Override protected Class getConfiguration() { - return EnableNeo4jRepositoriesConfiguration.class; + return SpringDataNeo4jConfiguration.class; } @Override @@ -48,7 +48,7 @@ class Neo4jRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSu } @EnableNeo4jRepositories - private static class EnableNeo4jRepositoriesConfiguration { + private static class SpringDataNeo4jConfiguration { } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/package-info.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/package-info.java index 38b1e038a4..4a6a7a12db 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/package-info.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/package-info.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScan.java b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScan.java index c8fc7da791..fd1b388ae8 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScan.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScan.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -34,12 +34,11 @@ import org.springframework.core.annotation.AliasFor; *

  • Set the * {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#setPackagesToScan(String...) * packages scanned} for JPA entities.
  • - *
  • Set the packages used with Neo4J's {@link org.neo4j.ogm.session.SessionFactory - * SessionFactory}.
  • *
  • Set the * {@link org.springframework.data.mapping.context.AbstractMappingContext#setInitialEntitySet(java.util.Set) * initial entity set} used with Spring Data * {@link org.springframework.data.mongodb.core.mapping.MongoMappingContext MongoDB}, + * {@link org.springframework.data.neo4j.core.mapping.Neo4jMappingContext Neo4j}, * {@link org.springframework.data.cassandra.core.mapping.CassandraMappingContext * Cassandra} and * {@link org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext @@ -52,6 +51,7 @@ import org.springframework.core.annotation.AliasFor; * annotation. * * @author Phillip Webb + * @author Michael J. Simons * @since 1.4.0 * @see EntityScanPackages */ diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java index 419c940790..e9d160029f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java @@ -19,8 +19,6 @@ package org.springframework.boot.autoconfigure.data.neo4j; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; -import org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver; - import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration; import org.springframework.boot.autoconfigure.data.jpa.city.City; @@ -31,13 +29,19 @@ import org.springframework.boot.autoconfigure.data.neo4j.empty.EmptyMarker; import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; -import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.util.TestPropertyValues; import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import org.springframework.data.neo4j.config.AbstractNeo4jConfig; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.neo4j.driver.Config; +import org.neo4j.driver.Driver; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.internal.logging.Slf4jLogging; + import static org.assertj.core.api.Assertions.assertThat; /** @@ -48,6 +52,7 @@ import static org.assertj.core.api.Assertions.assertThat; * @author Michael Hunger * @author Vince Bickers * @author Stephane Nicoll + * @author Michael J. Simons */ class MixedNeo4jRepositoriesAutoConfigurationTests { @@ -94,7 +99,6 @@ class MixedNeo4jRepositoriesAutoConfigurationTests { private void load(Class config, String... environment) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.setClassLoader(new FilteredClassLoader(EmbeddedDriver.class)); TestPropertyValues.of(environment).and("spring.datasource.initialization-mode=never").applyTo(context); context.register(config); context.register(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, @@ -108,7 +112,14 @@ class MixedNeo4jRepositoriesAutoConfigurationTests { @TestAutoConfigurationPackage(EmptyMarker.class) // Not this package or its parent @EnableNeo4jRepositories(basePackageClasses = Country.class) - static class TestConfiguration { + static class TestConfiguration extends AbstractNeo4jConfig { + + @Override + @Bean + public Driver driver() { + return GraphDatabase.driver("bolt://neo4j.test:7687", + Config.builder().withLogging(new Slf4jLogging()).build()); + } } @@ -117,7 +128,14 @@ class MixedNeo4jRepositoriesAutoConfigurationTests { @EnableNeo4jRepositories(basePackageClasses = Country.class) @EntityScan(basePackageClasses = City.class) @EnableJpaRepositories(basePackageClasses = CityRepository.class) - static class MixedConfiguration { + static class MixedConfiguration extends AbstractNeo4jConfig { + + @Override + @Bean + public Driver driver() { + return GraphDatabase.driver("bolt://neo4j.test:7687", + Config.builder().withLogging(new Slf4jLogging()).build()); + } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MockedDriverConfiguration.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MockedDriverConfiguration.java new file mode 100644 index 0000000000..8c2a3a4277 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MockedDriverConfiguration.java @@ -0,0 +1,49 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.boot.autoconfigure.data.neo4j; + +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.neo4j.driver.SessionConfig; +import org.neo4j.driver.types.TypeSystem; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +/** + * Driver configuration mocked to avoid instantiation of a real driver with connection + * creation. + * + * @author Michael J. Simons + */ +@Configuration(proxyBeanMethods = false) +class MockedDriverConfiguration { + + @Bean + Driver driver() { + Driver driver = mock(Driver.class); + TypeSystem typeSystem = mock(TypeSystem.class); + Session session = mock(Session.class); + when(driver.defaultTypeSystem()).thenReturn(typeSystem); + when(driver.session(Mockito.any(SessionConfig.class))).thenReturn(session); + return driver; + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java index 1f523d026e..d678521498 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,257 +16,168 @@ package org.springframework.boot.autoconfigure.data.neo4j; -import com.github.benmanes.caffeine.cache.Caffeine; -import org.junit.jupiter.api.Test; -import org.neo4j.ogm.driver.NativeTypesNotAvailableException; -import org.neo4j.ogm.driver.NativeTypesNotSupportedException; -import org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver; -import org.neo4j.ogm.session.Session; -import org.neo4j.ogm.session.SessionFactory; -import org.neo4j.ogm.session.event.Event; -import org.neo4j.ogm.session.event.EventListener; -import org.neo4j.ogm.session.event.PersistenceEvent; +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.boot.autoconfigure.AutoConfigurationPackages; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.autoconfigure.data.neo4j.city.City; -import org.springframework.boot.autoconfigure.data.neo4j.country.Country; -import org.springframework.boot.autoconfigure.domain.EntityScan; -import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; +import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import org.springframework.boot.test.context.runner.WebApplicationContextRunner; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.annotation.EnableBookmarkManagement; -import org.springframework.data.neo4j.bookmark.BookmarkManager; -import org.springframework.data.neo4j.mapping.Neo4jMappingContext; -import org.springframework.data.neo4j.transaction.Neo4jTransactionManager; -import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor; -import org.springframework.web.context.WebApplicationContext; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; +import org.springframework.data.neo4j.core.DatabaseSelection; +import org.springframework.data.neo4j.core.DatabaseSelectionProvider; +import org.springframework.data.neo4j.core.Neo4jClient; +import org.springframework.data.neo4j.core.Neo4jOperations; +import org.springframework.data.neo4j.core.Neo4jTemplate; +import org.springframework.data.neo4j.core.convert.Neo4jConversions; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.transaction.PlatformTransactionManager; /** - * Tests for {@link Neo4jDataAutoConfiguration}. Tests should not use the embedded driver - * as it requires the complete Neo4j-Kernel and server to function properly. - * - * @author Stephane Nicoll - * @author Michael Hunger - * @author Vince Bickers - * @author Andy Wilkinson - * @author Kazuki Shimizu - * @author Michael Simons + * @author Michael J. Simons */ class Neo4jDataAutoConfigurationTests { - private WebApplicationContextRunner contextRunner = new WebApplicationContextRunner() - .withClassLoader(new FilteredClassLoader(EmbeddedDriver.class)) - .withUserConfiguration(TestConfiguration.class).withConfiguration( - AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class)); + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.data.neo4j.repositories.type=imperative") + .withUserConfiguration(MockedDriverConfiguration.class) + .withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class)); @Test - void defaultConfiguration() { - this.contextRunner.withPropertyValues("spring.data.neo4j.uri=http://localhost:8989").run((context) -> { - assertThat(context).hasSingleBean(org.neo4j.ogm.config.Configuration.class); - assertThat(context).hasSingleBean(SessionFactory.class); - assertThat(context).hasSingleBean(Neo4jTransactionManager.class); - assertThat(context).doesNotHaveBean(OpenSessionInViewInterceptor.class); - assertThat(context).doesNotHaveBean(BookmarkManager.class); + void shouldProvideConversions() { + contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jConversions.class)); + } + + @Test + void shouldProvideDefaultDatabaseNameProvider() { + contextRunner.run(ctx -> { + assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class); + DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class); + assertThat(databaseNameProvider).isSameAs(DatabaseSelectionProvider.getDefaultSelectionProvider()); }); } @Test - void customNeo4jTransactionManagerUsingProperties() { - this.contextRunner.withPropertyValues("spring.transaction.default-timeout=30", - "spring.transaction.rollback-on-commit-failure:true").run((context) -> { - Neo4jTransactionManager transactionManager = context.getBean(Neo4jTransactionManager.class); - assertThat(transactionManager.getDefaultTimeout()).isEqualTo(30); - assertThat(transactionManager.isRollbackOnCommitFailure()).isTrue(); + void shouldProvideStaticDatabaseNameProviderIfConfigured() { + contextRunner.withPropertyValues("spring.data.neo4j.database=foobar").run(ctx -> { + assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class); + DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class); + assertThat(databaseNameProvider.getDatabaseSelection()).isEqualTo(DatabaseSelection.byName("foobar")); + }); + } + + @Test + void shouldRespectExistingDatabaseNameProvider() { + contextRunner.withPropertyValues("spring.data.neo4j.database=foobar") + .withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> { + assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class); + DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class); + assertThat(databaseNameProvider.getDatabaseSelection()) + .isEqualTo(DatabaseSelection.byName("whatever")); }); } @Test - void customSessionFactory() { - this.contextRunner.withUserConfiguration(CustomSessionFactory.class).run((context) -> { - assertThat(context).doesNotHaveBean(org.neo4j.ogm.config.Configuration.class); - assertThat(context).hasSingleBean(SessionFactory.class); + void shouldRequireAllNeededClasses() { + contextRunner + .withClassLoader( + new FilteredClassLoader(Neo4jTransactionManager.class, PlatformTransactionManager.class)) + .run(ctx -> assertThat(ctx).doesNotHaveBean(Neo4jClient.class).doesNotHaveBean(Neo4jTemplate.class) + .doesNotHaveBean(Neo4jTransactionManager.class)); + } + + @Test + void shouldCreateNewNeo4jClient() { + contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jClient.class)); + } + + @Test + void shouldNotReplaceExistingNeo4jClient() { + contextRunner.withUserConfiguration(ConfigurationWithExistingClient.class) + .run(ctx -> assertThat(ctx).hasSingleBean(Neo4jClient.class).hasBean("myCustomClient")); + } + + @Test + void shouldCreateNewNeo4jTemplate() { + contextRunner.withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> { + assertThat(ctx).hasSingleBean(Neo4jTemplate.class); + + // Verify that the template uses the provided database name + // provider + Neo4jTemplate template = ctx.getBean(Neo4jTemplate.class); + DatabaseSelectionProvider provider = (DatabaseSelectionProvider) ReflectionTestUtils.getField(template, + "databaseSelectionProvider"); + assertThat(provider).isSameAs(ctx.getBean(DatabaseSelectionProvider.class)); }); } @Test - void customSessionFactoryShouldNotDisableOtherDefaults() { - this.contextRunner.withUserConfiguration(CustomSessionFactory.class).run((context) -> { - assertThat(context).hasSingleBean(SessionFactory.class); - assertThat(context.getBean(SessionFactory.class)).isSameAs(context.getBean("customSessionFactory")); - assertThat(context).hasSingleBean(Neo4jTransactionManager.class); - assertThat(context).doesNotHaveBean(OpenSessionInViewInterceptor.class); + void shouldNotReplaceExistingNeo4jTemplate() { + contextRunner.withUserConfiguration(ConfigurationWithExistingTemplate.class) + .run(ctx -> assertThat(ctx).hasSingleBean(Neo4jOperations.class).hasBean("myCustomOperations")); + } + + @Test + void shouldCreateNewTransactionManager() { + contextRunner.withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> { + assertThat(ctx).hasSingleBean(Neo4jTransactionManager.class); + + // Verify that the transaction manager uses the provided + // database name provider + Neo4jTransactionManager transactionManager = ctx.getBean(Neo4jTransactionManager.class); + DatabaseSelectionProvider provider = (DatabaseSelectionProvider) ReflectionTestUtils + .getField(transactionManager, "databaseSelectionProvider"); + assertThat(provider).isSameAs(ctx.getBean(DatabaseSelectionProvider.class)); }); } @Test - void customConfiguration() { - this.contextRunner.withUserConfiguration(CustomConfiguration.class).run((context) -> { - assertThat(context.getBean(org.neo4j.ogm.config.Configuration.class)) - .isSameAs(context.getBean("myConfiguration")); - assertThat(context).hasSingleBean(SessionFactory.class); - assertThat(context).hasSingleBean(org.neo4j.ogm.config.Configuration.class); - }); + void shouldHonourExistingTransactionManager() { + contextRunner.withUserConfiguration(ConfigurationWithExistingTransactionManager.class) + .run(ctx -> assertThat(ctx).hasSingleBean(PlatformTransactionManager.class) + .hasBean("myCustomTransactionManager")); } - @Test - void usesAutoConfigurationPackageToPickUpDomainTypes() { - AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); - context.setClassLoader(new FilteredClassLoader(EmbeddedDriver.class)); - String cityPackage = City.class.getPackage().getName(); - AutoConfigurationPackages.register(context, cityPackage); - context.register(Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class); - try { - context.refresh(); - assertDomainTypesDiscovered(context.getBean(Neo4jMappingContext.class), City.class); + @Configuration + static class ConfigurationWithExistingClient { + + @Bean("myCustomClient") + Neo4jClient neo4jClient(Driver driver) { + return Neo4jClient.create(driver); } - finally { - context.close(); + + } + + @Configuration + static class ConfigurationWithExistingTemplate { + + @Bean("myCustomOperations") + Neo4jOperations neo4jOperations() { + return mock(Neo4jOperations.class); } + } - @Test - void openSessionInViewInterceptorCanBeEnabled() { - this.contextRunner.withPropertyValues("spring.data.neo4j.open-in-view:true") - .run((context) -> assertThat(context).hasSingleBean(OpenSessionInViewInterceptor.class)); - } + @Configuration + static class ConfigurationWithExistingTransactionManager { - @Test - void shouldBeAbleToUseNativeTypesWithBolt() { - this.contextRunner - .withPropertyValues("spring.data.neo4j.uri=bolt://localhost:7687", - "spring.data.neo4j.use-native-types:true") - .withConfiguration( - AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class)) - .run((context) -> assertThat(context).getBean(org.neo4j.ogm.config.Configuration.class) - .hasFieldOrPropertyWithValue("useNativeTypes", true)); - } - - @Test - void shouldFailWhenNativeTypesAreNotAvailable() { - this.contextRunner.withClassLoader(new FilteredClassLoader("org.neo4j.ogm.drivers.bolt.types")) - .withPropertyValues("spring.data.neo4j.uri=bolt://localhost:7687", - "spring.data.neo4j.use-native-types:true") - .withConfiguration( - AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class)) - .run((context) -> { - assertThat(context).hasFailed(); - assertThat(context.getStartupFailure()) - .hasRootCauseInstanceOf(NativeTypesNotAvailableException.class); - }); - } - - @Test - void shouldFailWhenNativeTypesAreNotSupported() { - this.contextRunner - .withPropertyValues("spring.data.neo4j.uri=http://localhost:7474", - "spring.data.neo4j.use-native-types:true") - .withConfiguration( - AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class)) - .run((context) -> { - assertThat(context).hasFailed(); - assertThat(context.getStartupFailure()) - .hasRootCauseInstanceOf(NativeTypesNotSupportedException.class); - }); - } - - @Test - void eventListenersAreAutoRegistered() { - this.contextRunner.withUserConfiguration(EventListenerConfiguration.class).run((context) -> { - Session session = context.getBean(SessionFactory.class).openSession(); - session.notifyListeners(new PersistenceEvent(null, Event.TYPE.PRE_SAVE)); - verify(context.getBean("eventListenerOne", EventListener.class)).onPreSave(any(Event.class)); - verify(context.getBean("eventListenerTwo", EventListener.class)).onPreSave(any(Event.class)); - }); - } - - @Test - void providesARequestScopedBookmarkManagerIfNecessaryAndPossible() { - this.contextRunner.withUserConfiguration(BookmarkManagementEnabledConfiguration.class).run((context) -> { - BeanDefinition bookmarkManagerBean = context.getBeanFactory() - .getBeanDefinition("scopedTarget.bookmarkManager"); - assertThat(bookmarkManagerBean.getScope()).isEqualTo(WebApplicationContext.SCOPE_REQUEST); - }); - } - - @Test - void providesASingletonScopedBookmarkManagerIfNecessaryAndPossible() { - new ApplicationContextRunner().withClassLoader(new FilteredClassLoader(EmbeddedDriver.class)) - .withUserConfiguration(TestConfiguration.class, BookmarkManagementEnabledConfiguration.class) - .withConfiguration( - AutoConfigurations.of(Neo4jDataAutoConfiguration.class, TransactionAutoConfiguration.class)) - .run((context) -> { - assertThat(context).hasSingleBean(BookmarkManager.class); - assertThat(context.getBeanDefinitionNames()).doesNotContain("scopedTarget.bookmarkManager"); - }); - } - - @Test - void doesNotProvideABookmarkManagerIfNotPossible() { - this.contextRunner.withClassLoader(new FilteredClassLoader(Caffeine.class, EmbeddedDriver.class)) - .withUserConfiguration(BookmarkManagementEnabledConfiguration.class) - .run((context) -> assertThat(context).doesNotHaveBean(BookmarkManager.class)); - } - - private static void assertDomainTypesDiscovered(Neo4jMappingContext mappingContext, Class... types) { - for (Class type : types) { - assertThat(mappingContext.getPersistentEntity(type)).isNotNull(); + @Bean("myCustomTransactionManager") + PlatformTransactionManager transactionManager() { + return mock(PlatformTransactionManager.class); } - } - - @Configuration(proxyBeanMethods = false) - @EntityScan(basePackageClasses = Country.class) - static class TestConfiguration { } - @Configuration(proxyBeanMethods = false) - static class CustomSessionFactory { + @Configuration + static class ConfigurationWithExistingDatabaseSelectionProvider { @Bean - SessionFactory customSessionFactory() { - return mock(SessionFactory.class); - } - - } - - @Configuration(proxyBeanMethods = false) - static class CustomConfiguration { - - @Bean - org.neo4j.ogm.config.Configuration myConfiguration() { - return new org.neo4j.ogm.config.Configuration.Builder().uri("http://localhost:12345").build(); - } - - } - - @Configuration(proxyBeanMethods = false) - @EnableBookmarkManagement - static class BookmarkManagementEnabledConfiguration { - - } - - @Configuration(proxyBeanMethods = false) - static class EventListenerConfiguration { - - @Bean - EventListener eventListenerOne() { - return mock(EventListener.class); - } - - @Bean - EventListener eventListenerTwo() { - return mock(EventListener.class); + DatabaseSelectionProvider databaseSelectionProvider() { + return () -> DatabaseSelection.byName("whatever"); } } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jPropertiesTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jPropertiesTests.java deleted file mode 100644 index afbad5cce2..0000000000 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jPropertiesTests.java +++ /dev/null @@ -1,191 +0,0 @@ -/* - * Copyright 2012-2019 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * https://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.autoconfigure.data.neo4j; - -import java.util.Base64; - -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.Test; -import org.neo4j.ogm.config.AutoIndexMode; -import org.neo4j.ogm.config.Configuration; -import org.neo4j.ogm.config.Credentials; -import org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver; - -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.test.context.FilteredClassLoader; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Tests for {@link Neo4jProperties}. - * - * @author Stephane Nicoll - * @author Michael Simons - */ -class Neo4jPropertiesTests { - - private AnnotationConfigApplicationContext context; - - @AfterEach - void close() { - if (this.context != null) { - this.context.close(); - } - } - - @Test - void defaultUseEmbeddedInMemoryIfAvailable() { - Neo4jProperties properties = load(true); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.EMBEDDED_DRIVER, null); - } - - @Test - void defaultUseBoltDriverIfEmbeddedDriverIsNotAvailable() { - Neo4jProperties properties = load(false); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.BOLT_DRIVER, Neo4jProperties.DEFAULT_BOLT_URI); - } - - @Test - void httpUriUseHttpDriver() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=http://localhost:7474"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.HTTP_DRIVER, "http://localhost:7474"); - } - - @Test - void httpsUriUseHttpDriver() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=https://localhost:7474"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.HTTP_DRIVER, "https://localhost:7474"); - } - - @Test - void boltUriUseBoltDriver() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=bolt://localhost:7687"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.BOLT_DRIVER, "bolt://localhost:7687"); - } - - @Test - void fileUriUseEmbeddedServer() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=file://var/tmp/graph.db"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.EMBEDDED_DRIVER, "file://var/tmp/graph.db"); - } - - @Test - void credentialsAreSet() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=http://localhost:7474", - "spring.data.neo4j.username=user", "spring.data.neo4j.password=secret"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.HTTP_DRIVER, "http://localhost:7474"); - assertCredentials(configuration, "user", "secret"); - } - - @Test - void credentialsAreSetFromUri() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=https://user:secret@my-server:7474"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.HTTP_DRIVER, "https://my-server:7474"); - assertCredentials(configuration, "user", "secret"); - } - - @Test - void autoIndexNoneByDefault() { - Neo4jProperties properties = load(true); - Configuration configuration = properties.createConfiguration(); - assertThat(configuration.getAutoIndex()).isEqualTo(AutoIndexMode.NONE); - } - - @Test - void autoIndexCanBeConfigured() { - Neo4jProperties properties = load(true, "spring.data.neo4j.auto-index=validate"); - Configuration configuration = properties.createConfiguration(); - assertThat(configuration.getAutoIndex()).isEqualTo(AutoIndexMode.VALIDATE); - } - - @Test - void embeddedModeDisabledUseBoltUri() { - Neo4jProperties properties = load(true, "spring.data.neo4j.embedded.enabled=false"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.BOLT_DRIVER, Neo4jProperties.DEFAULT_BOLT_URI); - } - - @Test - void embeddedModeWithRelativeLocation() { - Neo4jProperties properties = load(true, "spring.data.neo4j.uri=file:relative/path/to/my.db"); - Configuration configuration = properties.createConfiguration(); - assertDriver(configuration, Neo4jProperties.EMBEDDED_DRIVER, "file:relative/path/to/my.db"); - } - - @Test - void nativeTypesAreSetToFalseByDefault() { - Neo4jProperties properties = load(true); - Configuration configuration = properties.createConfiguration(); - assertThat(configuration.getUseNativeTypes()).isFalse(); - } - - @Test - void nativeTypesCanBeConfigured() { - Neo4jProperties properties = load(true, "spring.data.neo4j.use-native-types=true"); - Configuration configuration = properties.createConfiguration(); - assertThat(configuration.getUseNativeTypes()).isTrue(); - } - - private static void assertDriver(Configuration actual, String driver, String uri) { - assertThat(actual).isNotNull(); - assertThat(actual.getDriverClassName()).isEqualTo(driver); - assertThat(actual.getURI()).isEqualTo(uri); - } - - private static void assertCredentials(Configuration actual, String username, String password) { - Credentials credentials = actual.getCredentials(); - if (username == null && password == null) { - assertThat(credentials).isNull(); - } - else { - assertThat(credentials).isNotNull(); - Object content = credentials.credentials(); - assertThat(content).isInstanceOf(String.class); - String[] auth = new String(Base64.getDecoder().decode((String) content)).split(":"); - assertThat(auth).containsExactly(username, password); - } - } - - Neo4jProperties load(boolean embeddedAvailable, String... environment) { - AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); - if (!embeddedAvailable) { - ctx.setClassLoader(new FilteredClassLoader(EmbeddedDriver.class)); - } - TestPropertyValues.of(environment).applyTo(ctx); - ctx.register(TestConfiguration.class); - ctx.refresh(); - this.context = ctx; - return this.context.getBean(Neo4jProperties.class); - } - - @org.springframework.context.annotation.Configuration(proxyBeanMethods = false) - @EnableConfigurationProperties(Neo4jProperties.class) - static class TestConfiguration { - - } - -} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationIntegrationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationIntegrationTests.java new file mode 100644 index 0000000000..f6a8592c15 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationIntegrationTests.java @@ -0,0 +1,76 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data.neo4j; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.ImportAutoConfiguration; +import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository; +import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.testcontainers.containers.Neo4jContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Test to ensure that the properties get read and applied during the auto-configuration. + * + * @author Michael J. Simons + */ +@SpringBootTest(properties = "spring.data.neo4j.repositories.type=imperative") +@Testcontainers(disabledWithoutDocker = true) +public class Neo4jRepositoriesAutoConfigurationIntegrationTests { + + @Container + private static Neo4jContainer neo4jServer = new Neo4jContainer<>("neo4j:4.0"); + + @DynamicPropertySource + static void neo4jProperties(DynamicPropertyRegistry registry) { + + registry.add("spring.neo4j.uri", neo4jServer::getBoltUrl); + registry.add("spring.neo4j.authentication.username", () -> "neo4j"); + registry.add("spring.neo4j.authentication.password", neo4jServer::getAdminPassword); + } + + private final CountryRepository countryRepository; + + @Autowired + Neo4jRepositoriesAutoConfigurationIntegrationTests(CountryRepository countryRepository) { + this.countryRepository = countryRepository; + } + + @Test + void ensureRepositoryIsReady() { + + assertThat(countryRepository.count()).isEqualTo(0); + } + + @Configuration + @EnableNeo4jRepositories(basePackageClasses = CountryRepository.class) + @ImportAutoConfiguration({ Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class, + Neo4jRepositoriesAutoConfiguration.class }) + static class TestConfiguration { + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java index c1539936da..c8e0ac302d 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java @@ -16,25 +16,31 @@ package org.springframework.boot.autoconfigure.data.neo4j; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; -import org.neo4j.ogm.session.SessionFactory; - -import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.mockito.Mockito; +import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; -import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; -import org.springframework.boot.autoconfigure.data.alt.neo4j.CityNeo4jRepository; import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; import org.springframework.boot.autoconfigure.data.neo4j.city.City; import org.springframework.boot.autoconfigure.data.neo4j.city.CityRepository; -import org.springframework.boot.test.util.TestPropertyValues; -import org.springframework.context.annotation.AnnotationConfigApplicationContext; +import org.springframework.boot.autoconfigure.data.neo4j.city.ReactiveCityRepository; +import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository; +import org.springframework.boot.autoconfigure.data.neo4j.country.ReactiveCountryRepository; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.data.neo4j.mapping.Neo4jMappingContext; +import org.springframework.data.neo4j.core.Neo4jClient; +import org.springframework.data.neo4j.core.ReactiveNeo4jClient; +import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories; +import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories; +import org.springframework.data.neo4j.repository.support.ReactiveNeo4jRepositoryFactoryBean; +import reactor.core.publisher.Flux; import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatExceptionOfType; /** * Tests for {@link Neo4jRepositoriesAutoConfiguration}. @@ -44,50 +50,88 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType; * @author Michael Hunger * @author Vince Bickers * @author Stephane Nicoll + * @author Michael J. Simons */ class Neo4jRepositoriesAutoConfigurationTests { - private AnnotationConfigApplicationContext context; + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withUserConfiguration(MockedDriverConfiguration.class) + .withConfiguration(AutoConfigurations.of(Neo4jRepositoriesAutoConfigurationTests.class, + Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class)); - @AfterEach - void close() { - this.context.close(); + @Test + void defaultRepositoryConfigurationShouldWork() { + this.contextRunner.withUserConfiguration(TestConfiguration.class) + .withPropertyValues("spring.data.neo4j.repositories.type=imperative") + .run(ctx -> assertThat(ctx).hasSingleBean(CityRepository.class)); } @Test - void testDefaultRepositoryConfiguration() { - prepareApplicationContext(TestConfiguration.class); - assertThat(this.context.getBean(CityRepository.class)).isNotNull(); - Neo4jMappingContext mappingContext = this.context.getBean(Neo4jMappingContext.class); - assertThat(mappingContext.getPersistentEntity(City.class)).isNotNull(); + void repositoryConfigurationShouldNotCreateArbitraryRepos() { + this.contextRunner.withUserConfiguration(EmptyConfiguration.class) + .withPropertyValues("spring.data.neo4j.repositories.type=imperative").run(ctx -> assertThat(ctx) + .hasSingleBean(Neo4jTransactionManager.class).doesNotHaveBean(Neo4jRepository.class)); } @Test - void testNoRepositoryConfiguration() { - prepareApplicationContext(EmptyConfiguration.class); - assertThat(this.context.getBean(SessionFactory.class)).isNotNull(); - } + void configurationOfRepositoryTypeShouldWork() { + this.contextRunner.withPropertyValues("spring.data.neo4j.repositories.type=none") + .withUserConfiguration(TestConfiguration.class).withClassLoader(new FilteredClassLoader(Flux.class)) + .run(ctx -> assertThat(ctx).doesNotHaveBean(Neo4jTransactionManager.class) + .doesNotHaveBean(ReactiveNeo4jClient.class).doesNotHaveBean(Neo4jRepository.class)); - @Test - void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { - prepareApplicationContext(CustomizedConfiguration.class); - assertThat(this.context.getBean(CityNeo4jRepository.class)).isNotNull(); + this.contextRunner.withPropertyValues("spring.data.neo4j.repositories.type=imperative") + .withUserConfiguration(TestConfiguration.class) + .run(ctx -> assertThat(ctx).hasSingleBean(Neo4jTransactionManager.class) + .hasSingleBean(Neo4jClient.class).doesNotHaveBean(ReactiveNeo4jRepository.class)); } @Test void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() { - prepareApplicationContext(SortOfInvalidCustomConfiguration.class); - assertThatExceptionOfType(NoSuchBeanDefinitionException.class) - .isThrownBy(() -> this.context.getBean(CityRepository.class)); + this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class) + .withPropertyValues("spring.data.neo4j.repositories.type=imperative").run(ctx -> assertThat(ctx) + .hasSingleBean(Neo4jTransactionManager.class).doesNotHaveBean(Neo4jRepository.class)); } - private void prepareApplicationContext(Class... configurationClasses) { - this.context = new AnnotationConfigApplicationContext(); - TestPropertyValues.of("spring.data.neo4j.uri=http://localhost:9797").applyTo(this.context); - this.context.register(configurationClasses); - this.context.register(Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class, - PropertyPlaceholderAutoConfiguration.class); - this.context.refresh(); + @Test + void shouldRespectAtEnableNeo4jRepositories() { + this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomRepositoryScan.class) + .withPropertyValues("spring.data.neo4j.repositories.type=imperative") + .run(ctx -> assertThat(ctx).doesNotHaveBean(CityRepository.class) + .doesNotHaveBean(ReactiveCityRepository.class).hasSingleBean(CountryRepository.class) + .doesNotHaveBean(ReactiveCountryRepository.class)); + } + + @Test + void shouldRespectAtEnableReactiveNeo4jRepositories() { + this.contextRunner + .withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomReactiveRepositoryScan.class) + .withPropertyValues("spring.data.neo4j.repositories.type=reactive") + .run(ctx -> assertThat(ctx).doesNotHaveBean(CityRepository.class) + .doesNotHaveBean(ReactiveCityRepository.class).doesNotHaveBean(CountryRepository.class) + .hasSingleBean(ReactiveCountryRepository.class)); + } + + @Configuration(proxyBeanMethods = false) + @EnableNeo4jRepositories(basePackageClasses = CountryRepository.class) + static class WithCustomRepositoryScan { + + } + + @Configuration(proxyBeanMethods = false) + @EnableReactiveNeo4jRepositories(basePackageClasses = ReactiveCountryRepository.class) + static class WithCustomReactiveRepositoryScan { + + } + + @Configuration(proxyBeanMethods = false) + static class WithFakeEnabledReactiveNeo4jRepositories { + + @Bean + ReactiveNeo4jRepositoryFactoryBean reactiveNeo4jRepositoryFactoryBean() { + return Mockito.mock(ReactiveNeo4jRepositoryFactoryBean.class); + } + } @Configuration(proxyBeanMethods = false) @@ -103,14 +147,6 @@ class Neo4jRepositoriesAutoConfigurationTests { } @Configuration(proxyBeanMethods = false) - @TestAutoConfigurationPackage(Neo4jRepositoriesAutoConfigurationTests.class) - @EnableNeo4jRepositories(basePackageClasses = CityNeo4jRepository.class) - static class CustomizedConfiguration { - - } - - @Configuration(proxyBeanMethods = false) - // To not find any repositories @EnableNeo4jRepositories("foo.bar") @TestAutoConfigurationPackage(Neo4jRepositoriesAutoConfigurationTests.class) static class SortOfInvalidCustomConfiguration { diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/ReactiveNeo4jDataAutoConfigurationTests.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/ReactiveNeo4jDataAutoConfigurationTests.java new file mode 100644 index 0000000000..dfdf47bd70 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/ReactiveNeo4jDataAutoConfigurationTests.java @@ -0,0 +1,197 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data.neo4j; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; +import org.springframework.boot.test.context.FilteredClassLoader; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.neo4j.core.DatabaseSelection; +import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider; +import org.springframework.data.neo4j.core.ReactiveNeo4jClient; +import org.springframework.data.neo4j.core.ReactiveNeo4jOperations; +import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; +import org.springframework.data.neo4j.core.convert.Neo4jConversions; +import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.transaction.ReactiveTransactionManager; + +/** + * @author Michael J. Simons + */ +class ReactiveNeo4jDataAutoConfigurationTests { + + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.data.neo4j.repositories.type=reactive") + .withUserConfiguration(MockedDriverConfiguration.class) + .withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class)); + + @Test + void shouldProvideConversions() { + contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jConversions.class)); + } + + @Test + void shouldProvideDefaultDatabaseNameProvider() { + contextRunner.run(ctx -> { + assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class); + ReactiveDatabaseSelectionProvider databaseNameProvider = ctx + .getBean(ReactiveDatabaseSelectionProvider.class); + assertThat(databaseNameProvider).isSameAs(ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider()); + }); + } + + @Test + void shouldProvideStaticDatabaseNameProviderIfConfigured() { + contextRunner.withPropertyValues("spring.data.neo4j.database=foobar").run(ctx -> { + assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class); + ReactiveDatabaseSelectionProvider databaseNameProvider = ctx + .getBean(ReactiveDatabaseSelectionProvider.class); + StepVerifier.create(databaseNameProvider.getDatabaseSelection().map(DatabaseSelection::getValue)) + .expectNext("foobar").expectComplete(); + }); + } + + @Test + void shouldRespectExistingDatabaseNameProvider() { + contextRunner.withPropertyValues("spring.data.neo4j.database=foobar") + .withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class).run(ctx -> { + assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class); + ReactiveDatabaseSelectionProvider databaseNameProvider = ctx + .getBean(ReactiveDatabaseSelectionProvider.class); + StepVerifier.create(databaseNameProvider.getDatabaseSelection().map(DatabaseSelection::getValue)) + .expectNext("whatever").expectComplete(); + }); + } + + @Test + void shouldRequireAllNeededClasses() { + contextRunner + .withClassLoader(new FilteredClassLoader(ReactiveNeo4jTransactionManager.class, + ReactiveTransactionManager.class, Flux.class)) + .run(ctx -> assertThat(ctx).doesNotHaveBean(ReactiveNeo4jClient.class) + .doesNotHaveBean(ReactiveNeo4jTemplate.class) + .doesNotHaveBean(ReactiveNeo4jTransactionManager.class)); + } + + @Test + void shouldCreateNewReactiveNeo4jClient() { + contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(ReactiveNeo4jClient.class)); + } + + @Test + void shouldNotReplaceExistingReactiveNeo4jClient() { + contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveClient.class) + .run(ctx -> assertThat(ctx).hasSingleBean(ReactiveNeo4jClient.class).hasBean("myCustomReactiveClient")); + } + + @Test + void shouldCreateNewNeo4jTemplate() { + contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class) + .run(ctx -> { + assertThat(ctx).hasSingleBean(ReactiveNeo4jTemplate.class); + + // Verify that the template uses the provided database name + // provider + ReactiveNeo4jTemplate template = ctx.getBean(ReactiveNeo4jTemplate.class); + ReactiveDatabaseSelectionProvider provider = (ReactiveDatabaseSelectionProvider) ReflectionTestUtils + .getField(template, "databaseSelectionProvider"); + assertThat(provider).isSameAs(ctx.getBean(ReactiveDatabaseSelectionProvider.class)); + }); + } + + @Test + void shouldNotReplaceExistingNeo4jTemplate() { + contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveTemplate.class).run(ctx -> assertThat(ctx) + .hasSingleBean(ReactiveNeo4jOperations.class).hasBean("myCustomReactiveOperations")); + } + + @Test + void shouldCreateNewTransactionManager() { + contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class) + .run(ctx -> { + assertThat(ctx).hasSingleBean(ReactiveNeo4jTransactionManager.class); + + // Verify that the transaction manager uses the provided + // database name provider + ReactiveNeo4jTransactionManager transactionManager = ctx + .getBean(ReactiveNeo4jTransactionManager.class); + ReactiveDatabaseSelectionProvider provider = (ReactiveDatabaseSelectionProvider) ReflectionTestUtils + .getField(transactionManager, "databaseSelectionProvider"); + assertThat(provider).isSameAs(ctx.getBean(ReactiveDatabaseSelectionProvider.class)); + }); + } + + @Test + void shouldHonourExistingTransactionManager() { + contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveTransactionManager.class) + .run(ctx -> assertThat(ctx).hasSingleBean(ReactiveTransactionManager.class) + .hasBean("myCustomReactiveTransactionManager")); + } + + @Configuration + static class ConfigurationWithExistingReactiveClient { + + @Bean("myCustomReactiveClient") + ReactiveNeo4jClient neo4jClient(Driver driver) { + return ReactiveNeo4jClient.create(driver); + } + + } + + @Configuration + static class ConfigurationWithExistingReactiveTemplate { + + @Bean("myCustomReactiveOperations") + ReactiveNeo4jOperations neo4jOperations() { + return mock(ReactiveNeo4jOperations.class); + } + + } + + @Configuration + static class ConfigurationWithExistingReactiveTransactionManager { + + @Bean("myCustomReactiveTransactionManager") + ReactiveTransactionManager transactionManager() { + return mock(ReactiveTransactionManager.class); + } + + } + + @Configuration + static class ConfigurationWithExistingReactiveDatabaseSelectionProvider { + + @Bean + ReactiveDatabaseSelectionProvider databaseNameProvider() { + return () -> Mono.just(DatabaseSelection.byName("whatever")); + } + + } + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/City.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/City.java index 1ae1b828c0..27f1db193f 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/City.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/City.java @@ -18,13 +18,12 @@ package org.springframework.boot.autoconfigure.data.neo4j.city; import java.io.Serializable; -import org.neo4j.ogm.annotation.GeneratedValue; -import org.neo4j.ogm.annotation.Id; -import org.neo4j.ogm.annotation.NodeEntity; - import org.springframework.boot.autoconfigure.data.neo4j.country.Country; +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; -@NodeEntity +@Node public class City implements Serializable { private static final long serialVersionUID = 1L; @@ -41,9 +40,6 @@ public class City implements Serializable { private String map; - public City() { - } - public City(String name, Country country) { this.name = name; this.country = country; diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/ReactiveCityRepository.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/ReactiveCityRepository.java new file mode 100644 index 0000000000..215d9f1716 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/city/ReactiveCityRepository.java @@ -0,0 +1,26 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data.neo4j.city; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.neo4j.repository.Neo4jRepository; +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; + +public interface ReactiveCityRepository extends ReactiveNeo4jRepository { + +} diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/Country.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/Country.java index d1e2631891..34c504c098 100644 --- a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/Country.java +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/Country.java @@ -16,13 +16,13 @@ package org.springframework.boot.autoconfigure.data.neo4j.country; +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; + import java.io.Serializable; -import org.neo4j.ogm.annotation.GeneratedValue; -import org.neo4j.ogm.annotation.Id; -import org.neo4j.ogm.annotation.NodeEntity; - -@NodeEntity +@Node public class Country implements Serializable { private static final long serialVersionUID = 1L; @@ -33,9 +33,6 @@ public class Country implements Serializable { private String name; - public Country() { - } - public Country(String name) { this.name = name; } diff --git a/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/ReactiveCountryRepository.java b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/ReactiveCountryRepository.java new file mode 100644 index 0000000000..790aa84d94 --- /dev/null +++ b/spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/country/ReactiveCountryRepository.java @@ -0,0 +1,23 @@ +/* + * Copyright 2012-2019 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.autoconfigure.data.neo4j.country; + +import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository; + +public interface ReactiveCountryRepository extends ReactiveNeo4jRepository { + +} diff --git a/spring-boot-project/spring-boot-dependencies/build.gradle b/spring-boot-project/spring-boot-dependencies/build.gradle index 489ddb4d00..a79f8abba8 100644 --- a/spring-boot-project/spring-boot-dependencies/build.gradle +++ b/spring-boot-project/spring-boot-dependencies/build.gradle @@ -1177,19 +1177,6 @@ bom { ] } } - library("Neo4j OGM", "3.2.12") { - group("org.neo4j") { - modules = [ - "neo4j-ogm-api", - "neo4j-ogm-bolt-driver", - "neo4j-ogm-bolt-native-types", - "neo4j-ogm-core", - "neo4j-ogm-embedded-driver", - "neo4j-ogm-embedded-native-types", - "neo4j-ogm-http-driver" - ] - } - } library("Netty", "4.1.50.Final") { group("io.netty") { imports = [ diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestIntegrationTests.java index 90f06dc040..c10b33a03c 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestIntegrationTests.java @@ -19,7 +19,8 @@ package org.springframework.boot.test.autoconfigure.data.neo4j; import java.time.Duration; import org.junit.jupiter.api.Test; -import org.neo4j.ogm.session.Session; + +import org.springframework.data.neo4j.core.Neo4jTemplate; import org.testcontainers.containers.Neo4jContainer; import org.testcontainers.junit.jupiter.Container; import org.testcontainers.junit.jupiter.Testcontainers; @@ -49,7 +50,7 @@ class DataNeo4jTestIntegrationTests { .withStartupTimeout(Duration.ofMinutes(10)); @Autowired - private Session session; + private Neo4jTemplate neo4jTemplate; @Autowired private ExampleRepository exampleRepository; @@ -59,17 +60,16 @@ class DataNeo4jTestIntegrationTests { @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { - registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl); + registry.add("spring.neo4j.uri", neo4j::getBoltUrl); } @Test void testRepository() { - ExampleGraph exampleGraph = new ExampleGraph(); - exampleGraph.setDescription("Look, new @DataNeo4jTest!"); + ExampleGraph exampleGraph = new ExampleGraph("Look, new @DataNeo4jTest!"); assertThat(exampleGraph.getId()).isNull(); ExampleGraph savedGraph = this.exampleRepository.save(exampleGraph); assertThat(savedGraph.getId()).isNotNull(); - assertThat(this.session.countEntitiesOfType(ExampleGraph.class)).isEqualTo(1); + assertThat(this.neo4jTemplate.count(ExampleGraph.class)).isEqualTo(1); } @Test diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java index cd9c80a3b8..b4efc9eac0 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestPropertiesIntegrationTests.java @@ -49,7 +49,7 @@ class DataNeo4jTestPropertiesIntegrationTests { @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { - registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl); + registry.add("spring.neo4j.uri", neo4j::getBoltUrl); } @Test diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestWithIncludeFilterIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestWithIncludeFilterIntegrationTests.java index 7533e60b52..a8812f06cf 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestWithIncludeFilterIntegrationTests.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTestWithIncludeFilterIntegrationTests.java @@ -50,7 +50,7 @@ class DataNeo4jTestWithIncludeFilterIntegrationTests { @DynamicPropertySource static void neo4jProperties(DynamicPropertyRegistry registry) { - registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl); + registry.add("spring.neo4j.uri", neo4j::getBoltUrl); } @Test diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTypeExcludeFilterTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTypeExcludeFilterTests.java new file mode 100644 index 0000000000..dda71f1dd4 --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/DataNeo4jTypeExcludeFilterTests.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2019-2020 "Neo4j," + * Neo4j Sweden AB [https://neo4j.com] + * + * This file is part of Neo4j. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.boot.test.autoconfigure.data.neo4j; + +import org.junit.jupiter.api.Test; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.FilterType; +import org.springframework.core.type.classreading.MetadataReader; +import org.springframework.core.type.classreading.MetadataReaderFactory; +import org.springframework.core.type.classreading.SimpleMetadataReaderFactory; + +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Michael J. Simons + */ +class DataNeo4jTypeExcludeFilterTests { + + private MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); + + @Test + void matchWithExcludeFilter() throws Exception { + DataNeo4jTypeExcludeFilter filter = new DataNeo4jTypeExcludeFilter(WithExcludeFilter.class); + assertThat(excludes(filter, ExampleService.class)).isTrue(); + assertThat(excludes(filter, ExampleRepository.class)).isTrue(); + } + + @Test + void matchWithoutExcludeFilter() throws Exception { + DataNeo4jTypeExcludeFilter filter = new DataNeo4jTypeExcludeFilter(WithoutExcludeFilter.class); + assertThat(excludes(filter, ExampleService.class)).isTrue(); + assertThat(excludes(filter, ExampleRepository.class)).isFalse(); + } + + @DataNeo4jTest( + excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ExampleRepository.class)) + static class WithExcludeFilter { + + } + + @DataNeo4jTest + static class WithoutExcludeFilter { + + } + + private boolean excludes(DataNeo4jTypeExcludeFilter filter, Class type) throws IOException { + MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(type.getName()); + return filter.match(metadataReader, this.metadataReaderFactory); + } + +} diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleGraph.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleGraph.java index 41d3fb2aa2..4c3736a2d4 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleGraph.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleGraph.java @@ -16,17 +16,18 @@ package org.springframework.boot.test.autoconfigure.data.neo4j; -import org.neo4j.ogm.annotation.GeneratedValue; -import org.neo4j.ogm.annotation.Id; -import org.neo4j.ogm.annotation.NodeEntity; -import org.neo4j.ogm.annotation.Property; +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; +import org.springframework.data.neo4j.core.schema.Property; /** * Example graph used with {@link DataNeo4jTest @DataNeo4jTest} tests. * * @author Eddú Meléndez + * @author Michael J. Simons */ -@NodeEntity +@Node public class ExampleGraph { @Id @@ -36,6 +37,10 @@ public class ExampleGraph { @Property private String description; + public ExampleGraph(String description) { + this.description = description; + } + public Long getId() { return this.id; } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleService.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleService.java index 58e1493848..619299a77b 100644 --- a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleService.java +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ExampleService.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,26 +16,26 @@ package org.springframework.boot.test.autoconfigure.data.neo4j; -import org.neo4j.ogm.session.Session; - +import org.springframework.data.neo4j.core.Neo4jTemplate; import org.springframework.stereotype.Service; /** * Example service used with {@link DataNeo4jTest @DataNeo4jTest} tests. * * @author Eddú Meléndez + * @author Michael J. Simons */ @Service public class ExampleService { - private final Session session; + private final Neo4jTemplate neo4jTemplate; - public ExampleService(Session session) { - this.session = session; + public ExampleService(Neo4jTemplate neo4jTemplate) { + this.neo4jTemplate = neo4jTemplate; } public boolean hasNode(Class clazz) { - return this.session.countEntitiesOfType(clazz) == 1; + return this.neo4jTemplate.count(clazz) == 1; } } diff --git a/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ReactiveDataNeo4jIntegrationTests.java b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ReactiveDataNeo4jIntegrationTests.java new file mode 100644 index 0000000000..c85a900c4b --- /dev/null +++ b/spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/data/neo4j/ReactiveDataNeo4jIntegrationTests.java @@ -0,0 +1,100 @@ +/* + * Copyright 2012-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.boot.test.autoconfigure.data.neo4j; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.NoSuchBeanDefinitionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate; +import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager; +import org.springframework.test.context.DynamicPropertyRegistry; +import org.springframework.test.context.DynamicPropertySource; +import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.transaction.ReactiveTransactionManager; +import org.testcontainers.containers.Neo4jContainer; +import org.testcontainers.junit.jupiter.Container; +import org.testcontainers.junit.jupiter.Testcontainers; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.time.Duration; + +import org.neo4j.driver.AccessMode; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Session; +import org.neo4j.driver.SessionConfig; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatExceptionOfType; + +/** + * Integration tests for the reactive SDN/RX Neo4j test slice. + * + * @author Michael J. Simons + * @since 2.4.0 + */ +@DataNeo4jTest +@Testcontainers(disabledWithoutDocker = true) +class ReactiveDataNeo4jIntegrationTests { + + @Container + static final Neo4jContainer neo4j = new Neo4jContainer<>("neo4j:4.0").withoutAuthentication() + .withStartupTimeout(Duration.ofMinutes(10)); + + @DynamicPropertySource + static void neo4jProperties(DynamicPropertyRegistry registry) { + registry.add("spring.neo4j.uri", neo4j::getBoltUrl); + } + + @Autowired + private Driver driver; + + @Autowired + private ReactiveNeo4jTemplate neo4jTemplate; + + @Autowired + private ApplicationContext applicationContext; + + @Test + void testTemplate() { + + Mono.just(new ExampleGraph("Look, new @DataNeo4jTest with reactive!")).flatMap(neo4jTemplate::save) + .as(StepVerifier::create).expectNextCount(1).verifyComplete(); + + try (Session session = driver.session(SessionConfig.builder().withDefaultAccessMode(AccessMode.READ).build())) { + long cnt = session.run("MATCH (n:ExampleGraph) RETURN count(n) as cnt").single().get("cnt").asLong(); + assertThat(cnt).isEqualTo(1L); + } + } + + @Test + void didNotInjectExampleService() { + assertThatExceptionOfType(NoSuchBeanDefinitionException.class) + .isThrownBy(() -> this.applicationContext.getBean(ExampleService.class)); + } + + @Test + void didProvideOnlyReactiveTransactionManager() { + + assertThat(this.applicationContext.getBean(ReactiveTransactionManager.class)) + .isInstanceOf(ReactiveNeo4jTransactionManager.class); + assertThatExceptionOfType(NoSuchBeanDefinitionException.class) + .isThrownBy(() -> this.applicationContext.getBean(PlatformTransactionManager.class)); + } + +} diff --git a/spring-boot-project/spring-boot-tools/spring-boot-test-support/build.gradle b/spring-boot-project/spring-boot-tools/spring-boot-test-support/build.gradle index 7985225b9b..9c282c20d2 100644 --- a/spring-boot-project/spring-boot-tools/spring-boot-test-support/build.gradle +++ b/spring-boot-project/spring-boot-tools/spring-boot-test-support/build.gradle @@ -14,7 +14,6 @@ dependencies { compileOnly("org.junit.jupiter:junit-jupiter") compileOnly("org.junit.platform:junit-platform-engine") compileOnly("org.mockito:mockito-core") - compileOnly("org.neo4j:neo4j-ogm-core") compileOnly("org.springframework:spring-context") compileOnly("org.springframework.data:spring-data-redis") compileOnly("org.testcontainers:testcontainers") diff --git a/spring-boot-project/spring-boot/build.gradle b/spring-boot-project/spring-boot/build.gradle index cf1be0543a..06f8f6d07c 100644 --- a/spring-boot-project/spring-boot/build.gradle +++ b/spring-boot-project/spring-boot/build.gradle @@ -56,7 +56,6 @@ dependencies { optional("org.hibernate.validator:hibernate-validator") optional("org.jboss:jboss-transaction-spi") optional("org.liquibase:liquibase-core") - optional("org.neo4j:neo4j-ogm-core") optional("org.slf4j:jul-to-slf4j") optional("org.slf4j:slf4j-api") optional("org.springframework:spring-messaging") diff --git a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-neo4j/src/main/java/smoketest/data/neo4j/Customer.java b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-neo4j/src/main/java/smoketest/data/neo4j/Customer.java index 52b6d59f32..b9663eece4 100644 --- a/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-neo4j/src/main/java/smoketest/data/neo4j/Customer.java +++ b/spring-boot-tests/spring-boot-smoke-tests/spring-boot-smoke-test-data-neo4j/src/main/java/smoketest/data/neo4j/Customer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2019 the original author or authors. + * Copyright 2012-2020 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,11 +16,11 @@ package smoketest.data.neo4j; -import org.neo4j.ogm.annotation.GeneratedValue; -import org.neo4j.ogm.annotation.Id; -import org.neo4j.ogm.annotation.NodeEntity; +import org.springframework.data.neo4j.core.schema.GeneratedValue; +import org.springframework.data.neo4j.core.schema.Id; +import org.springframework.data.neo4j.core.schema.Node; -@NodeEntity +@Node public class Customer { @Id