Polish "Upgrade to Spring Data Neo4j 6"

See gh-22299
pull/22681/head
Stephane Nicoll 4 years ago
parent 15cd343737
commit 9bc71fe44f

@ -20,42 +20,52 @@ import java.util.Set;
import org.neo4j.driver.Driver;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.domain.EntityScanner;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.neo4j.config.Neo4jDefaultCallbacksRegistrar;
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.Neo4jOperations;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.data.neo4j.core.convert.Neo4jConversions;
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.core.schema.Node;
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;
import org.springframework.transaction.PlatformTransactionManager;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j. Automatic
* configuration of base infrastructure that imports configuration for both imperative and
* reactive Neo4j repositories.
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j.
*
* @author Michael Hunger
* @author Josh Long
* @author Vince Bickers
* @author Stephane Nicoll
* @author Kazuki Shimizu
* @author Michael J Simons
* @author Michael J. Simons
* @since 1.4.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnBean(Driver.class)
@ConditionalOnClass({ Driver.class, Neo4jTransactionManager.class, PlatformTransactionManager.class })
@EnableConfigurationProperties(Neo4jDataProperties.class)
@AutoConfigureAfter(Neo4jAutoConfiguration.class)
@ConditionalOnBean(Driver.class)
@AutoConfigureBefore(TransactionAutoConfiguration.class)
@Import({ Neo4jDataConfiguration.class, Neo4jReactiveDataConfiguration.class })
@AutoConfigureAfter(Neo4jAutoConfiguration.class)
@Import(Neo4jDefaultCallbacksRegistrar.class)
public class Neo4jDataAutoConfiguration {
@Bean
@ -74,4 +84,34 @@ public class Neo4jDataAutoConfiguration {
return context;
}
@Bean
@ConditionalOnMissingBean
public DatabaseSelectionProvider databaseSelectionProvider(Neo4jDataProperties properties) {
String database = properties.getDatabase();
return (database != null) ? DatabaseSelectionProvider.createStaticDatabaseSelectionProvider(database)
: DatabaseSelectionProvider.getDefaultSelectionProvider();
}
@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME)
@ConditionalOnMissingBean
public Neo4jClient neo4jClient(Driver driver) {
return Neo4jClient.create(driver);
}
@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME)
@ConditionalOnMissingBean(Neo4jOperations.class)
public Neo4jTemplate neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext,
DatabaseSelectionProvider databaseNameProvider) {
return new Neo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider);
}
@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME)
@ConditionalOnMissingBean(PlatformTransactionManager.class)
public Neo4jTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider,
ObjectProvider<TransactionManagerCustomizers> optionalCustomizers) {
Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(driver, databaseNameProvider);
optionalCustomizers.ifAvailable((customizer) -> customizer.customize(transactionManager));
return transactionManager;
}
}

@ -1,88 +0,0 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.neo4j;
import org.neo4j.driver.Driver;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;
import org.springframework.boot.autoconfigure.data.RepositoryType;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.env.Environment;
import org.springframework.data.neo4j.config.Neo4jDefaultCallbacksRegistrar;
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.Neo4jOperations;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.data.neo4j.core.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;
import org.springframework.transaction.PlatformTransactionManager;
/**
* Internal configuration of Neo4j client and transaction manager.
*
* @author Michael J. Simons
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Neo4jTransactionManager.class, PlatformTransactionManager.class })
@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.IMPERATIVE)
@AutoConfigureAfter(Neo4jAutoConfiguration.class)
@AutoConfigureBefore(Neo4jRepositoriesConfiguration.class)
@Import(Neo4jDefaultCallbacksRegistrar.class)
class Neo4jDataConfiguration {
@Bean("databaseSelectionProvider")
@ConditionalOnMissingBean
DatabaseSelectionProvider defaultSelectionProvider(Environment environment) {
String database = environment.getProperty("spring.data.neo4j.database");
if (database != null) {
return DatabaseSelectionProvider.createStaticDatabaseSelectionProvider(database);
}
return DatabaseSelectionProvider.getDefaultSelectionProvider();
}
@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME)
@ConditionalOnMissingBean
Neo4jClient neo4jClient(Driver driver) {
return Neo4jClient.create(driver);
}
@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME)
@ConditionalOnMissingBean(Neo4jOperations.class)
Neo4jTemplate neo4jTemplate(Neo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext,
DatabaseSelectionProvider databaseNameProvider) {
return new Neo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider);
}
@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME)
@ConditionalOnMissingBean(PlatformTransactionManager.class)
Neo4jTransactionManager transactionManager(Driver driver, DatabaseSelectionProvider databaseNameProvider,
ObjectProvider<TransactionManagerCustomizers> optionalCustomizers) {
Neo4jTransactionManager transactionManager = new Neo4jTransactionManager(driver, databaseNameProvider);
optionalCustomizers.ifAvailable((customizer) -> customizer.customize(transactionManager));
return transactionManager;
}
}

@ -17,7 +17,6 @@
package org.springframework.boot.autoconfigure.data.neo4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
/**
* Configuration properties for Spring Data Neo4j.
@ -29,10 +28,7 @@ import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
public class Neo4jDataProperties {
/**
* A statically configured database. This property is only applicable when connecting
* against a 4.0 cluster or server and will lead to errors if used with a prior
* version of Neo4j. Leave this null (the default) to indicate that you like the
* server to decide the default database to use.
* Database name to use. By default, the server decides the default database to use.
*/
private String database;

@ -20,17 +20,13 @@ import org.neo4j.driver.Driver;
import reactor.core.publisher.Flux;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;
import org.springframework.boot.autoconfigure.data.RepositoryType;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;
import org.springframework.data.neo4j.config.Neo4jDefaultReactiveCallbacksRegistrar;
import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider;
import org.springframework.data.neo4j.core.ReactiveNeo4jClient;
@ -42,49 +38,45 @@ import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryC
import org.springframework.transaction.ReactiveTransactionManager;
/**
* Internal configuration for the reactive Neo4j client.
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's reactive Neo4j
* support.
*
* @author Michael J. Simons
* @author Stephane Nicoll
* @since 2.4.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ ReactiveNeo4jTransactionManager.class, ReactiveTransactionManager.class, Flux.class })
@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.REACTIVE)
@AutoConfigureAfter(Neo4jAutoConfiguration.class)
@AutoConfigureBefore(Neo4jReactiveRepositoriesConfiguration.class)
@ConditionalOnClass({ Driver.class, ReactiveNeo4jTransactionManager.class, ReactiveTransactionManager.class,
Flux.class })
@ConditionalOnBean(Driver.class)
@AutoConfigureAfter(Neo4jDataAutoConfiguration.class)
@Import(Neo4jDefaultReactiveCallbacksRegistrar.class)
class Neo4jReactiveDataConfiguration {
public class Neo4jReactiveDataAutoConfiguration {
@Bean("reactiveDatabaseSelectionProvider")
@ConditionalOnProperty(prefix = "spring.data.neo4j", name = "database")
@Bean
@ConditionalOnMissingBean
@Order(-30)
ReactiveDatabaseSelectionProvider staticDatabaseSelectionProvider(Neo4jDataProperties dataProperties) {
return ReactiveDatabaseSelectionProvider.createStaticDatabaseSelectionProvider(dataProperties.getDatabase());
}
@Bean("reactiveDatabaseSelectionProvider")
@ConditionalOnMissingBean
@Order(-20)
ReactiveDatabaseSelectionProvider defaultSelectionProvider() {
return ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider();
public ReactiveDatabaseSelectionProvider reactiveDatabaseSelectionProvider(Neo4jDataProperties dataProperties) {
String database = dataProperties.getDatabase();
return (database != null) ? ReactiveDatabaseSelectionProvider.createStaticDatabaseSelectionProvider(database)
: ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider();
}
@Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_CLIENT_BEAN_NAME)
@ConditionalOnMissingBean
ReactiveNeo4jClient neo4jClient(Driver driver) {
public ReactiveNeo4jClient reactiveNeo4jClient(Driver driver) {
return ReactiveNeo4jClient.create(driver);
}
@Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME)
@ConditionalOnMissingBean(ReactiveNeo4jOperations.class)
ReactiveNeo4jTemplate neo4jTemplate(ReactiveNeo4jClient neo4jClient, Neo4jMappingContext neo4jMappingContext,
ReactiveDatabaseSelectionProvider databaseNameProvider) {
public ReactiveNeo4jTemplate reactiveNeo4jTemplate(ReactiveNeo4jClient neo4jClient,
Neo4jMappingContext neo4jMappingContext, ReactiveDatabaseSelectionProvider databaseNameProvider) {
return new ReactiveNeo4jTemplate(neo4jClient, neo4jMappingContext, databaseNameProvider);
}
@Bean(ReactiveNeo4jRepositoryConfigurationExtension.DEFAULT_TRANSACTION_MANAGER_BEAN_NAME)
@ConditionalOnMissingBean(ReactiveTransactionManager.class)
ReactiveTransactionManager transactionManager(Driver driver,
public ReactiveTransactionManager reactiveTransactionManager(Driver driver,
ReactiveDatabaseSelectionProvider databaseNameProvider) {
return new ReactiveNeo4jTransactionManager(driver, databaseNameProvider);
}

@ -16,8 +16,11 @@
package org.springframework.boot.autoconfigure.data.neo4j;
import org.neo4j.driver.Driver;
import reactor.core.publisher.Flux;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;
@ -29,16 +32,20 @@ import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryC
import org.springframework.data.neo4j.repository.support.ReactiveNeo4jRepositoryFactoryBean;
/**
* Imports the registrar for reactive Neo4j repositories.
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Neo4j Reactive
* Repositories.
*
* @author Michael J. Simons
* @author Stephane Nicoll
* @since 2.4.0
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass({ Flux.class, ReactiveNeo4jRepository.class })
@ConditionalOnClass({ Driver.class, ReactiveNeo4jRepository.class, Flux.class })
@ConditionalOnMissingBean({ ReactiveNeo4jRepositoryFactoryBean.class,
ReactiveNeo4jRepositoryConfigurationExtension.class })
@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.REACTIVE)
@Import(Neo4jReactiveRepositoriesConfigureRegistrar.class)
final class Neo4jReactiveRepositoriesConfiguration {
@Import(Neo4jReactiveRepositoriesRegistrar.class)
@AutoConfigureAfter(Neo4jReactiveDataAutoConfiguration.class)
public class Neo4jReactiveRepositoriesAutoConfiguration {
}

@ -19,17 +19,18 @@ package org.springframework.boot.autoconfigure.data.neo4j;
import java.lang.annotation.Annotation;
import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories;
import org.springframework.data.neo4j.repository.config.ReactiveNeo4jRepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
/**
* {@link ImportBeanDefinitionRegistrar} used to auto-configure reactive Spring Data Neo4j
* {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Neo4j reactive
* Repositories.
*
* @author Michael J. Simons
*/
final class Neo4jReactiveRepositoriesConfigureRegistrar extends AbstractRepositoryConfigurationSourceSupport {
class Neo4jReactiveRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {
@Override
protected Class<? extends Annotation> getAnnotation() {
@ -38,7 +39,7 @@ final class Neo4jReactiveRepositoriesConfigureRegistrar extends AbstractReposito
@Override
protected Class<?> getConfiguration() {
return SpringDataNeo4jConfiguration.class;
return EnableReactiveNeo4jRepositoriesConfiguration.class;
}
@Override
@ -47,7 +48,7 @@ final class Neo4jReactiveRepositoriesConfigureRegistrar extends AbstractReposito
}
@EnableReactiveNeo4jRepositories
private static class SpringDataNeo4jConfiguration {
private static class EnableReactiveNeo4jRepositoriesConfiguration {
}

@ -19,26 +19,43 @@ package org.springframework.boot.autoconfigure.data.neo4j;
import org.neo4j.driver.Driver;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;
import org.springframework.boot.autoconfigure.data.RepositoryType;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;
import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean;
/**
* Shared entry point for the configuration of Spring Data Neo4j repositories in their
* imperative and reactive forms.
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Neo4j
* Repositories.
* <p>
* Activates when there is no bean of type {@link Neo4jRepositoryFactoryBean} or
* {@link Neo4jRepositoryConfigurationExtension} configured in the context, the Spring
* Data Neo4j {@link Neo4jRepository} type is on the classpath, the Neo4j client driver
* API is on the classpath, and there is no other configured {@link Neo4jRepository}.
* <p>
* Once in effect, the auto-configuration is the equivalent of enabling Neo4j repositories
* using the {@link EnableNeo4jRepositories @EnableNeo4jRepositories} annotation.
*
* @author Dave Syer
* @author Oliver Gierke
* @author Josh Long
* @author Michael J. Simons
* @see EnableNeo4jRepositories
* @since 1.4.0
* @see EnableNeo4jRepositories
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Driver.class)
@ConditionalOnClass({ Driver.class, Neo4jRepository.class })
@ConditionalOnMissingBean({ Neo4jRepositoryFactoryBean.class, Neo4jRepositoryConfigurationExtension.class })
@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.IMPERATIVE)
@Import(Neo4jRepositoriesRegistrar.class)
@AutoConfigureAfter(Neo4jDataAutoConfiguration.class)
@Import({ Neo4jRepositoriesConfiguration.class, Neo4jReactiveRepositoriesConfiguration.class })
public class Neo4jRepositoriesAutoConfiguration {
}

@ -1,41 +0,0 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.neo4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.ConditionalOnRepositoryType;
import org.springframework.boot.autoconfigure.data.RepositoryType;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;
import org.springframework.data.neo4j.repository.support.Neo4jRepositoryFactoryBean;
/**
* Imports the registrar for imperative Neo4j repositories.
*
* @author Michael J. Simons
*/
@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(Neo4jRepository.class)
@ConditionalOnMissingBean({ Neo4jRepositoryFactoryBean.class, Neo4jRepositoryConfigurationExtension.class })
@ConditionalOnRepositoryType(store = "neo4j", type = RepositoryType.IMPERATIVE)
@Import(Neo4jRepositoriesConfigureRegistrar.class)
class Neo4jRepositoriesConfiguration {
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2020 the original author or authors.
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,6 +19,7 @@ package org.springframework.boot.autoconfigure.data.neo4j;
import java.lang.annotation.Annotation;
import org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
@ -28,9 +29,8 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
* Repositories.
*
* @author Michael Hunger
* @author Michael J. Simons
*/
class Neo4jRepositoriesConfigureRegistrar extends AbstractRepositoryConfigurationSourceSupport {
class Neo4jRepositoriesRegistrar extends AbstractRepositoryConfigurationSourceSupport {
@Override
protected Class<? extends Annotation> getAnnotation() {
@ -39,7 +39,7 @@ class Neo4jRepositoriesConfigureRegistrar extends AbstractRepositoryConfiguratio
@Override
protected Class<?> getConfiguration() {
return SpringDataNeo4jConfiguration.class;
return EnableNeo4jRepositoriesConfiguration.class;
}
@Override
@ -48,7 +48,7 @@ class Neo4jRepositoriesConfigureRegistrar extends AbstractRepositoryConfiguratio
}
@EnableNeo4jRepositories
private static class SpringDataNeo4jConfiguration {
private static class EnableNeo4jRepositoriesConfiguration {
}

@ -51,7 +51,6 @@ import org.springframework.core.annotation.AliasFor;
* annotation.
*
* @author Phillip Webb
* @author Michael J. Simons
* @since 1.4.0
* @see EntityScanPackages
*/

@ -651,19 +651,81 @@
},
{
"name": "spring.data.neo4j.auto-index",
"defaultValue": "none"
"description": "Auto index mode.",
"defaultValue": "none",
"deprecation": {
"reason": "Automatic index creation is no longer supported.",
"level": "error"
}
},
{
"name": "spring.data.neo4j.embedded.enabled",
"type": "java.lang.Boolean",
"description": "Whether to enable embedded mode if the embedded driver is available.",
"deprecation": {
"reason": "Embedded mode is no longer supported, please use Testcontainers instead.",
"level": "error"
}
},
{
"name": "spring.data.neo4j.open-in-view",
"type": "java.lang.Boolean",
"description": "Register OpenSessionInViewInterceptor that binds a Neo4j Session to the thread for the entire processing of the request.",
"defaultValue": false
"deprecation": {
"level": "error"
}
},
{
"name": "spring.data.neo4j.password",
"type": "java.lang.String",
"description": "Login password of the server.",
"deprecation": {
"replacement": "spring.neo4j.authentication.password",
"level": "error"
}
},
{
"name": "spring.data.neo4j.repositories.enabled",
"type": "java.lang.Boolean",
"description": "Whether to enable Neo4j repositories.",
"defaultValue": true
"defaultValue": true,
"deprecation": {
"replacement": "spring.data.neo4j.repositories.type",
"level": "error"
}
},
{
"name": "spring.data.neo4j.repositories.type",
"type": "org.springframework.boot.autoconfigure.data.RepositoryType",
"description": "Type of Neo4j repositories to enable.",
"defaultValue": "auto"
},
{
"name": "spring.data.neo4j.uri",
"type": "java.lang.String",
"description": "URI used by the driver. Auto-detected by default.",
"deprecation": {
"replacement": "spring.neo4j.uri",
"level": "error"
}
},
{
"name": "spring.data.neo4j.use-native-types",
"type": "java.lang.Boolean",
"description": "Whether to use Neo4j native types wherever possible.",
"deprecation": {
"reason": "Native type support is now built-in.",
"level": "error"
}
},
{
"name": "spring.data.neo4j.username",
"type": "java.lang.String",
"description": "Login user of the server.",
"deprecation": {
"replacement": "spring.neo4j.authentication.password",
"level": "error"
}
},
{
"name": "spring.data.r2dbc.repositories.enabled",

@ -51,6 +51,8 @@ org.springframework.boot.autoconfigure.data.mongo.MongoReactiveDataAutoConfigura
org.springframework.boot.autoconfigure.data.mongo.MongoReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.r2dbc.R2dbcDataAutoConfiguration,\

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,6 +19,11 @@ package org.springframework.boot.autoconfigure.data.neo4j;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.neo4j.driver.Config;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.internal.logging.Slf4jLogging;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.data.jpa.city.City;
@ -37,11 +42,6 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.neo4j.config.AbstractNeo4jConfig;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.neo4j.driver.Config;
import org.neo4j.driver.Driver;
import org.neo4j.driver.GraphDatabase;
import org.neo4j.driver.internal.logging.Slf4jLogging;
import static org.assertj.core.api.Assertions.assertThat;
/**
@ -103,7 +103,8 @@ class MixedNeo4jRepositoriesAutoConfigurationTests {
context.register(config);
context.register(DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class, Neo4jDataAutoConfiguration.class,
Neo4jRepositoriesAutoConfiguration.class);
Neo4jReactiveDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class,
Neo4jReactiveRepositoriesAutoConfiguration.class);
context.refresh();
this.context = context;
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,16 +16,16 @@
package org.springframework.boot.autoconfigure.data.neo4j;
import org.mockito.Mockito;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.neo4j.driver.Driver;
import org.neo4j.driver.Session;
import org.neo4j.driver.SessionConfig;
import org.neo4j.driver.types.TypeSystem;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
/**
* Driver configuration mocked to avoid instantiation of a real driver with connection
@ -41,8 +41,8 @@ class MockedDriverConfiguration {
Driver driver = mock(Driver.class);
TypeSystem typeSystem = mock(TypeSystem.class);
Session session = mock(Session.class);
when(driver.defaultTypeSystem()).thenReturn(typeSystem);
when(driver.session(Mockito.any(SessionConfig.class))).thenReturn(session);
given(driver.defaultTypeSystem()).willReturn(typeSystem);
given(driver.session(Mockito.any(SessionConfig.class))).willReturn(session);
return driver;
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,14 +16,10 @@
package org.springframework.boot.autoconfigure.data.neo4j;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import org.junit.jupiter.api.Test;
import org.neo4j.driver.Driver;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@ -34,150 +30,110 @@ import org.springframework.data.neo4j.core.Neo4jOperations;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.data.neo4j.core.convert.Neo4jConversions;
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.transaction.PlatformTransactionManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link Neo4jDataAutoConfiguration}.
*
* @author Stephane Nicoll
* @author Michael Hunger
* @author Vince Bickers
* @author Andy Wilkinson
* @author Kazuki Shimizu
* @author Michael J. Simons
*/
class Neo4jDataAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.data.neo4j.repositories.type=imperative")
.withUserConfiguration(MockedDriverConfiguration.class)
.withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class));
@Test
void shouldProvideConversions() {
contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jConversions.class));
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(Neo4jConversions.class));
}
@Test
void shouldProvideDefaultDatabaseNameProvider() {
contextRunner.run(ctx -> {
assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class);
DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class);
assertThat(databaseNameProvider).isSameAs(DatabaseSelectionProvider.getDefaultSelectionProvider());
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(DatabaseSelectionProvider.class);
assertThat(context.getBean(DatabaseSelectionProvider.class))
.isSameAs(DatabaseSelectionProvider.getDefaultSelectionProvider());
});
}
@Test
void shouldProvideStaticDatabaseNameProviderIfConfigured() {
contextRunner.withPropertyValues("spring.data.neo4j.database=foobar").run(ctx -> {
assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class);
DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class);
assertThat(databaseNameProvider.getDatabaseSelection()).isEqualTo(DatabaseSelection.byName("foobar"));
void shouldUseDatabaseNameIfSet() {
this.contextRunner.withPropertyValues("spring.data.neo4j.database=test").run((context) -> {
assertThat(context).hasSingleBean(DatabaseSelectionProvider.class);
assertThat(context.getBean(DatabaseSelectionProvider.class).getDatabaseSelection())
.isEqualTo(DatabaseSelection.byName("test"));
});
}
@Test
void shouldRespectExistingDatabaseNameProvider() {
contextRunner.withPropertyValues("spring.data.neo4j.database=foobar")
.withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> {
assertThat(ctx).hasSingleBean(DatabaseSelectionProvider.class);
DatabaseSelectionProvider databaseNameProvider = ctx.getBean(DatabaseSelectionProvider.class);
assertThat(databaseNameProvider.getDatabaseSelection())
.isEqualTo(DatabaseSelection.byName("whatever"));
void shouldReuseExistingDatabaseNameProvider() {
this.contextRunner.withPropertyValues("spring.data.neo4j.database=ignored")
.withUserConfiguration(CustomDatabaseSelectionProviderConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(DatabaseSelectionProvider.class);
assertThat(context.getBean(DatabaseSelectionProvider.class).getDatabaseSelection())
.isEqualTo(DatabaseSelection.byName("custom"));
});
}
@Test
void shouldRequireAllNeededClasses() {
contextRunner
.withClassLoader(
new FilteredClassLoader(Neo4jTransactionManager.class, PlatformTransactionManager.class))
.run(ctx -> assertThat(ctx).doesNotHaveBean(Neo4jClient.class).doesNotHaveBean(Neo4jTemplate.class)
.doesNotHaveBean(Neo4jTransactionManager.class));
void shouldProvideNeo4jClient() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(Neo4jClient.class));
}
@Test
void shouldCreateNewNeo4jClient() {
contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jClient.class));
void shouldReuseExistingNeo4jClient() {
this.contextRunner.withBean("myCustomClient", Neo4jClient.class, () -> mock(Neo4jClient.class))
.run((context) -> assertThat(context).hasSingleBean(Neo4jClient.class).hasBean("myCustomClient"));
}
@Test
void shouldNotReplaceExistingNeo4jClient() {
contextRunner.withUserConfiguration(ConfigurationWithExistingClient.class)
.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jClient.class).hasBean("myCustomClient"));
}
@Test
void shouldCreateNewNeo4jTemplate() {
contextRunner.withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> {
assertThat(ctx).hasSingleBean(Neo4jTemplate.class);
// Verify that the template uses the provided database name
// provider
Neo4jTemplate template = ctx.getBean(Neo4jTemplate.class);
DatabaseSelectionProvider provider = (DatabaseSelectionProvider) ReflectionTestUtils.getField(template,
"databaseSelectionProvider");
assertThat(provider).isSameAs(ctx.getBean(DatabaseSelectionProvider.class));
void shouldProvideNeo4jTemplate() {
this.contextRunner.withUserConfiguration(CustomDatabaseSelectionProviderConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(Neo4jTemplate.class);
assertThat(context.getBean(Neo4jTemplate.class)).extracting("databaseSelectionProvider")
.isSameAs(context.getBean(DatabaseSelectionProvider.class));
});
}
@Test
void shouldNotReplaceExistingNeo4jTemplate() {
contextRunner.withUserConfiguration(ConfigurationWithExistingTemplate.class)
.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jOperations.class).hasBean("myCustomOperations"));
void shouldReuseExistingNeo4jTemplate() {
this.contextRunner.withBean("myCustomOperations", Neo4jOperations.class, () -> mock(Neo4jOperations.class)).run(
(context) -> assertThat(context).hasSingleBean(Neo4jOperations.class).hasBean("myCustomOperations"));
}
@Test
void shouldCreateNewTransactionManager() {
contextRunner.withUserConfiguration(ConfigurationWithExistingDatabaseSelectionProvider.class).run(ctx -> {
assertThat(ctx).hasSingleBean(Neo4jTransactionManager.class);
// Verify that the transaction manager uses the provided
// database name provider
Neo4jTransactionManager transactionManager = ctx.getBean(Neo4jTransactionManager.class);
DatabaseSelectionProvider provider = (DatabaseSelectionProvider) ReflectionTestUtils
.getField(transactionManager, "databaseSelectionProvider");
assertThat(provider).isSameAs(ctx.getBean(DatabaseSelectionProvider.class));
void shouldProvideTransactionManager() {
this.contextRunner.withUserConfiguration(CustomDatabaseSelectionProviderConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(Neo4jTransactionManager.class);
assertThat(context.getBean(Neo4jTransactionManager.class)).extracting("databaseSelectionProvider")
.isSameAs(context.getBean(DatabaseSelectionProvider.class));
});
}
@Test
void shouldHonourExistingTransactionManager() {
contextRunner.withUserConfiguration(ConfigurationWithExistingTransactionManager.class)
.run(ctx -> assertThat(ctx).hasSingleBean(PlatformTransactionManager.class)
void shouldReuseExistingTransactionManager() {
this.contextRunner
.withBean("myCustomTransactionManager", PlatformTransactionManager.class,
() -> mock(PlatformTransactionManager.class))
.run((context) -> assertThat(context).hasSingleBean(PlatformTransactionManager.class)
.hasBean("myCustomTransactionManager"));
}
@Configuration
static class ConfigurationWithExistingClient {
@Bean("myCustomClient")
Neo4jClient neo4jClient(Driver driver) {
return Neo4jClient.create(driver);
}
}
@Configuration
static class ConfigurationWithExistingTemplate {
@Bean("myCustomOperations")
Neo4jOperations neo4jOperations() {
return mock(Neo4jOperations.class);
}
}
@Configuration
static class ConfigurationWithExistingTransactionManager {
@Bean("myCustomTransactionManager")
PlatformTransactionManager transactionManager() {
return mock(PlatformTransactionManager.class);
}
}
@Configuration
static class ConfigurationWithExistingDatabaseSelectionProvider {
@Configuration(proxyBeanMethods = false)
static class CustomDatabaseSelectionProviderConfiguration {
@Bean
DatabaseSelectionProvider databaseSelectionProvider() {
return () -> DatabaseSelection.byName("whatever");
return () -> DatabaseSelection.byName("custom");
}
}

@ -0,0 +1,145 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.neo4j;
import org.junit.jupiter.api.Test;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.core.DatabaseSelection;
import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider;
import org.springframework.data.neo4j.core.ReactiveNeo4jClient;
import org.springframework.data.neo4j.core.ReactiveNeo4jOperations;
import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;
import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager;
import org.springframework.transaction.ReactiveTransactionManager;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link Neo4jReactiveDataAutoConfiguration}.
*
* @author Michael J. Simons
* @author Stephane Nicoll
*/
class Neo4jReactiveDataAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withUserConfiguration(MockedDriverConfiguration.class)
.withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class,
Neo4jReactiveDataAutoConfiguration.class));
@Test
void shouldProvideDefaultDatabaseNameProvider() {
this.contextRunner.run((context) -> {
assertThat(context).hasSingleBean(ReactiveDatabaseSelectionProvider.class);
assertThat(context.getBean(ReactiveDatabaseSelectionProvider.class))
.isSameAs(ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider());
});
}
@Test
void shouldUseDatabaseNameIfSet() {
this.contextRunner.withPropertyValues("spring.data.neo4j.database=test").run((context) -> {
assertThat(context).hasSingleBean(ReactiveDatabaseSelectionProvider.class);
StepVerifier.create(context.getBean(ReactiveDatabaseSelectionProvider.class).getDatabaseSelection())
.consumeNextWith((databaseSelection) -> assertThat(databaseSelection.getValue()).isEqualTo("test"))
.expectComplete();
});
}
@Test
void shouldReuseExistingDatabaseNameProvider() {
this.contextRunner.withPropertyValues("spring.data.neo4j.database=ignored")
.withUserConfiguration(CustomReactiveDatabaseSelectionProviderConfiguration.class).run((context) -> {
assertThat(context).hasSingleBean(ReactiveDatabaseSelectionProvider.class);
StepVerifier.create(context.getBean(ReactiveDatabaseSelectionProvider.class).getDatabaseSelection())
.consumeNextWith(
(databaseSelection) -> assertThat(databaseSelection.getValue()).isEqualTo("custom"))
.expectComplete();
});
}
@Test
void shouldProvideReactiveNeo4jClient() {
this.contextRunner.run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jClient.class));
}
@Test
void shouldReuseExistingReactiveNeo4jClient() {
this.contextRunner
.withBean("myCustomReactiveClient", ReactiveNeo4jClient.class, () -> mock(ReactiveNeo4jClient.class))
.run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jClient.class)
.hasBean("myCustomReactiveClient"));
}
@Test
void shouldProvideReactiveNeo4jTemplate() {
this.contextRunner.withUserConfiguration(CustomReactiveDatabaseSelectionProviderConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(ReactiveNeo4jTemplate.class);
assertThat(context.getBean(ReactiveNeo4jTemplate.class)).extracting("databaseSelectionProvider")
.isSameAs(context.getBean(ReactiveDatabaseSelectionProvider.class));
});
}
@Test
void shouldReuseExistingReactiveNeo4jTemplate() {
this.contextRunner
.withBean("myCustomReactiveOperations", ReactiveNeo4jOperations.class,
() -> mock(ReactiveNeo4jOperations.class))
.run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jOperations.class)
.hasBean("myCustomReactiveOperations"));
}
@Test
void shouldProvideReactiveTransactionManager() {
this.contextRunner.withUserConfiguration(CustomReactiveDatabaseSelectionProviderConfiguration.class)
.run((context) -> {
assertThat(context).hasSingleBean(ReactiveNeo4jTransactionManager.class);
assertThat(context.getBean(ReactiveNeo4jTransactionManager.class))
.extracting("databaseSelectionProvider")
.isSameAs(context.getBean(ReactiveDatabaseSelectionProvider.class));
});
}
@Test
void shouldReuseExistingReactiveTransactionManager() {
this.contextRunner
.withBean("myCustomReactiveTransactionManager", ReactiveTransactionManager.class,
() -> mock(ReactiveTransactionManager.class))
.run((context) -> assertThat(context).hasSingleBean(ReactiveTransactionManager.class)
.hasBean("myCustomReactiveTransactionManager"));
}
@Configuration(proxyBeanMethods = false)
static class CustomReactiveDatabaseSelectionProviderConfiguration {
@Bean
ReactiveDatabaseSelectionProvider databaseNameProvider() {
return () -> Mono.just(DatabaseSelection.byName("custom"));
}
}
}

@ -0,0 +1,112 @@
/*
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.neo4j;
import org.junit.jupiter.api.Test;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
import org.springframework.boot.autoconfigure.data.neo4j.city.City;
import org.springframework.boot.autoconfigure.data.neo4j.city.CityRepository;
import org.springframework.boot.autoconfigure.data.neo4j.city.ReactiveCityRepository;
import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository;
import org.springframework.boot.autoconfigure.data.neo4j.country.ReactiveCountryRepository;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link Neo4jReactiveRepositoriesAutoConfiguration}.
*
* @author Stephane Nicoll
* @author Michael J. Simons
*/
public class Neo4jReactiveRepositoriesAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withUserConfiguration(MockedDriverConfiguration.class)
.withConfiguration(AutoConfigurations.of(Neo4jDataAutoConfiguration.class,
Neo4jReactiveDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class,
Neo4jReactiveRepositoriesAutoConfiguration.class));
@Test
void configurationWithDefaultRepositories() {
this.contextRunner.withUserConfiguration(TestConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(ReactiveCityRepository.class));
}
@Test
void configurationWithNoRepositories() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> assertThat(context)
.hasSingleBean(ReactiveNeo4jTransactionManager.class).doesNotHaveBean(ReactiveNeo4jRepository.class));
}
@Test
void configurationWithDisabledRepositories() {
this.contextRunner.withUserConfiguration(TestConfiguration.class)
.withPropertyValues("spring.data.neo4j.repositories.type=none")
.run((context) -> assertThat(context).doesNotHaveBean(ReactiveNeo4jRepository.class));
}
@Test
void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() {
this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class)
.run((context) -> assertThat(context).hasSingleBean(ReactiveNeo4jTransactionManager.class)
.doesNotHaveBean(ReactiveNeo4jRepository.class));
}
@Test
void shouldRespectAtEnableReactiveNeo4jRepositories() {
this.contextRunner
.withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomReactiveRepositoryScan.class)
.withPropertyValues("spring.data.neo4j.repositories.type=reactive")
.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class)
.doesNotHaveBean(ReactiveCityRepository.class).doesNotHaveBean(CountryRepository.class)
.hasSingleBean(ReactiveCountryRepository.class));
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(City.class)
static class TestConfiguration {
}
@Configuration(proxyBeanMethods = false)
@TestAutoConfigurationPackage(EmptyDataPackage.class)
static class EmptyConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableReactiveNeo4jRepositories("foo.bar")
@TestAutoConfigurationPackage(Neo4jReactiveRepositoriesAutoConfigurationTests.class)
static class SortOfInvalidCustomConfiguration {
}
@Configuration(proxyBeanMethods = false)
@EnableReactiveNeo4jRepositories(basePackageClasses = ReactiveCountryRepository.class)
static class WithCustomReactiveRepositoryScan {
}
}

@ -17,6 +17,10 @@
package org.springframework.boot.autoconfigure.data.neo4j;
import org.junit.jupiter.api.Test;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository;
@ -26,9 +30,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import static org.assertj.core.api.Assertions.assertThat;
@ -37,32 +38,26 @@ import static org.assertj.core.api.Assertions.assertThat;
*
* @author Michael J. Simons
*/
@SpringBootTest(properties = "spring.data.neo4j.repositories.type=imperative")
@SpringBootTest
@Testcontainers(disabledWithoutDocker = true)
public class Neo4jRepositoriesAutoConfigurationIntegrationTests {
@Container
private static Neo4jContainer<?> neo4jServer = new Neo4jContainer<>("neo4j:4.0");
private static final Neo4jContainer<?> neo4jServer = new Neo4jContainer<>("neo4j:4.0");
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", neo4jServer::getBoltUrl);
registry.add("spring.neo4j.authentication.username", () -> "neo4j");
registry.add("spring.neo4j.authentication.password", neo4jServer::getAdminPassword);
}
private final CountryRepository countryRepository;
@Autowired
Neo4jRepositoriesAutoConfigurationIntegrationTests(CountryRepository countryRepository) {
this.countryRepository = countryRepository;
}
private CountryRepository countryRepository;
@Test
void ensureRepositoryIsReady() {
assertThat(countryRepository.count()).isEqualTo(0);
assertThat(this.countryRepository.count()).isEqualTo(0);
}
@Configuration

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -18,6 +18,7 @@ package org.springframework.boot.autoconfigure.data.neo4j;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage;
@ -26,19 +27,13 @@ import org.springframework.boot.autoconfigure.data.neo4j.city.CityRepository;
import org.springframework.boot.autoconfigure.data.neo4j.city.ReactiveCityRepository;
import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository;
import org.springframework.boot.autoconfigure.data.neo4j.country.ReactiveCountryRepository;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.core.Neo4jClient;
import org.springframework.data.neo4j.core.ReactiveNeo4jClient;
import org.springframework.data.neo4j.core.transaction.Neo4jTransactionManager;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories;
import org.springframework.data.neo4j.repository.support.ReactiveNeo4jRepositoryFactoryBean;
import reactor.core.publisher.Flux;
import static org.assertj.core.api.Assertions.assertThat;
@ -55,75 +50,49 @@ import static org.assertj.core.api.Assertions.assertThat;
class Neo4jRepositoriesAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withUserConfiguration(MockedDriverConfiguration.class)
.withConfiguration(AutoConfigurations.of(Neo4jRepositoriesAutoConfigurationTests.class,
Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class));
.withUserConfiguration(MockedDriverConfiguration.class).withConfiguration(
AutoConfigurations.of(Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class));
@Test
void defaultRepositoryConfigurationShouldWork() {
void configurationWithDefaultRepositories() {
this.contextRunner.withUserConfiguration(TestConfiguration.class)
.withPropertyValues("spring.data.neo4j.repositories.type=imperative")
.run(ctx -> assertThat(ctx).hasSingleBean(CityRepository.class));
.run((context) -> assertThat(context).hasSingleBean(CityRepository.class));
}
@Test
void repositoryConfigurationShouldNotCreateArbitraryRepos() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class)
.withPropertyValues("spring.data.neo4j.repositories.type=imperative").run(ctx -> assertThat(ctx)
.hasSingleBean(Neo4jTransactionManager.class).doesNotHaveBean(Neo4jRepository.class));
void configurationWithNoRepositories() {
this.contextRunner.withUserConfiguration(EmptyConfiguration.class).run((context) -> assertThat(context)
.hasSingleBean(Neo4jTransactionManager.class).doesNotHaveBean(Neo4jRepository.class));
}
@Test
void configurationOfRepositoryTypeShouldWork() {
this.contextRunner.withPropertyValues("spring.data.neo4j.repositories.type=none")
.withUserConfiguration(TestConfiguration.class).withClassLoader(new FilteredClassLoader(Flux.class))
.run(ctx -> assertThat(ctx).doesNotHaveBean(Neo4jTransactionManager.class)
.doesNotHaveBean(ReactiveNeo4jClient.class).doesNotHaveBean(Neo4jRepository.class));
this.contextRunner.withPropertyValues("spring.data.neo4j.repositories.type=imperative")
.withUserConfiguration(TestConfiguration.class)
.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jTransactionManager.class)
.hasSingleBean(Neo4jClient.class).doesNotHaveBean(ReactiveNeo4jRepository.class));
void configurationWithDisabledRepositories() {
this.contextRunner.withUserConfiguration(TestConfiguration.class)
.withPropertyValues("spring.data.neo4j.repositories.type=none")
.run((context) -> assertThat(context).doesNotHaveBean(Neo4jRepository.class));
}
@Test
void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() {
this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class)
.withPropertyValues("spring.data.neo4j.repositories.type=imperative").run(ctx -> assertThat(ctx)
.hasSingleBean(Neo4jTransactionManager.class).doesNotHaveBean(Neo4jRepository.class));
.run((context) -> assertThat(context).hasSingleBean(Neo4jTransactionManager.class)
.doesNotHaveBean(Neo4jRepository.class));
}
@Test
void shouldRespectAtEnableNeo4jRepositories() {
this.contextRunner.withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomRepositoryScan.class)
.withPropertyValues("spring.data.neo4j.repositories.type=imperative")
.run(ctx -> assertThat(ctx).doesNotHaveBean(CityRepository.class)
.run((context) -> assertThat(context).doesNotHaveBean(CityRepository.class)
.doesNotHaveBean(ReactiveCityRepository.class).hasSingleBean(CountryRepository.class)
.doesNotHaveBean(ReactiveCountryRepository.class));
}
@Test
void shouldRespectAtEnableReactiveNeo4jRepositories() {
this.contextRunner
.withUserConfiguration(SortOfInvalidCustomConfiguration.class, WithCustomReactiveRepositoryScan.class)
.withPropertyValues("spring.data.neo4j.repositories.type=reactive")
.run(ctx -> assertThat(ctx).doesNotHaveBean(CityRepository.class)
.doesNotHaveBean(ReactiveCityRepository.class).doesNotHaveBean(CountryRepository.class)
.hasSingleBean(ReactiveCountryRepository.class));
}
@Configuration(proxyBeanMethods = false)
@EnableNeo4jRepositories(basePackageClasses = CountryRepository.class)
static class WithCustomRepositoryScan {
}
@Configuration(proxyBeanMethods = false)
@EnableReactiveNeo4jRepositories(basePackageClasses = ReactiveCountryRepository.class)
static class WithCustomReactiveRepositoryScan {
}
@Configuration(proxyBeanMethods = false)
static class WithFakeEnabledReactiveNeo4jRepositories {

@ -1,197 +0,0 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.data.neo4j;
import static org.assertj.core.api.Assertions.*;
import static org.mockito.Mockito.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import org.junit.jupiter.api.Test;
import org.neo4j.driver.Driver;
import org.springframework.boot.autoconfigure.AutoConfigurations;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.core.DatabaseSelection;
import org.springframework.data.neo4j.core.ReactiveDatabaseSelectionProvider;
import org.springframework.data.neo4j.core.ReactiveNeo4jClient;
import org.springframework.data.neo4j.core.ReactiveNeo4jOperations;
import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;
import org.springframework.data.neo4j.core.convert.Neo4jConversions;
import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager;
import org.springframework.test.util.ReflectionTestUtils;
import org.springframework.transaction.ReactiveTransactionManager;
/**
* @author Michael J. Simons
*/
class ReactiveNeo4jDataAutoConfigurationTests {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withPropertyValues("spring.data.neo4j.repositories.type=reactive")
.withUserConfiguration(MockedDriverConfiguration.class)
.withConfiguration(AutoConfigurations.of(Neo4jAutoConfiguration.class, Neo4jDataAutoConfiguration.class));
@Test
void shouldProvideConversions() {
contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(Neo4jConversions.class));
}
@Test
void shouldProvideDefaultDatabaseNameProvider() {
contextRunner.run(ctx -> {
assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class);
ReactiveDatabaseSelectionProvider databaseNameProvider = ctx
.getBean(ReactiveDatabaseSelectionProvider.class);
assertThat(databaseNameProvider).isSameAs(ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider());
});
}
@Test
void shouldProvideStaticDatabaseNameProviderIfConfigured() {
contextRunner.withPropertyValues("spring.data.neo4j.database=foobar").run(ctx -> {
assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class);
ReactiveDatabaseSelectionProvider databaseNameProvider = ctx
.getBean(ReactiveDatabaseSelectionProvider.class);
StepVerifier.create(databaseNameProvider.getDatabaseSelection().map(DatabaseSelection::getValue))
.expectNext("foobar").expectComplete();
});
}
@Test
void shouldRespectExistingDatabaseNameProvider() {
contextRunner.withPropertyValues("spring.data.neo4j.database=foobar")
.withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class).run(ctx -> {
assertThat(ctx).hasSingleBean(ReactiveDatabaseSelectionProvider.class);
ReactiveDatabaseSelectionProvider databaseNameProvider = ctx
.getBean(ReactiveDatabaseSelectionProvider.class);
StepVerifier.create(databaseNameProvider.getDatabaseSelection().map(DatabaseSelection::getValue))
.expectNext("whatever").expectComplete();
});
}
@Test
void shouldRequireAllNeededClasses() {
contextRunner
.withClassLoader(new FilteredClassLoader(ReactiveNeo4jTransactionManager.class,
ReactiveTransactionManager.class, Flux.class))
.run(ctx -> assertThat(ctx).doesNotHaveBean(ReactiveNeo4jClient.class)
.doesNotHaveBean(ReactiveNeo4jTemplate.class)
.doesNotHaveBean(ReactiveNeo4jTransactionManager.class));
}
@Test
void shouldCreateNewReactiveNeo4jClient() {
contextRunner.run(ctx -> assertThat(ctx).hasSingleBean(ReactiveNeo4jClient.class));
}
@Test
void shouldNotReplaceExistingReactiveNeo4jClient() {
contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveClient.class)
.run(ctx -> assertThat(ctx).hasSingleBean(ReactiveNeo4jClient.class).hasBean("myCustomReactiveClient"));
}
@Test
void shouldCreateNewNeo4jTemplate() {
contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class)
.run(ctx -> {
assertThat(ctx).hasSingleBean(ReactiveNeo4jTemplate.class);
// Verify that the template uses the provided database name
// provider
ReactiveNeo4jTemplate template = ctx.getBean(ReactiveNeo4jTemplate.class);
ReactiveDatabaseSelectionProvider provider = (ReactiveDatabaseSelectionProvider) ReflectionTestUtils
.getField(template, "databaseSelectionProvider");
assertThat(provider).isSameAs(ctx.getBean(ReactiveDatabaseSelectionProvider.class));
});
}
@Test
void shouldNotReplaceExistingNeo4jTemplate() {
contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveTemplate.class).run(ctx -> assertThat(ctx)
.hasSingleBean(ReactiveNeo4jOperations.class).hasBean("myCustomReactiveOperations"));
}
@Test
void shouldCreateNewTransactionManager() {
contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveDatabaseSelectionProvider.class)
.run(ctx -> {
assertThat(ctx).hasSingleBean(ReactiveNeo4jTransactionManager.class);
// Verify that the transaction manager uses the provided
// database name provider
ReactiveNeo4jTransactionManager transactionManager = ctx
.getBean(ReactiveNeo4jTransactionManager.class);
ReactiveDatabaseSelectionProvider provider = (ReactiveDatabaseSelectionProvider) ReflectionTestUtils
.getField(transactionManager, "databaseSelectionProvider");
assertThat(provider).isSameAs(ctx.getBean(ReactiveDatabaseSelectionProvider.class));
});
}
@Test
void shouldHonourExistingTransactionManager() {
contextRunner.withUserConfiguration(ConfigurationWithExistingReactiveTransactionManager.class)
.run(ctx -> assertThat(ctx).hasSingleBean(ReactiveTransactionManager.class)
.hasBean("myCustomReactiveTransactionManager"));
}
@Configuration
static class ConfigurationWithExistingReactiveClient {
@Bean("myCustomReactiveClient")
ReactiveNeo4jClient neo4jClient(Driver driver) {
return ReactiveNeo4jClient.create(driver);
}
}
@Configuration
static class ConfigurationWithExistingReactiveTemplate {
@Bean("myCustomReactiveOperations")
ReactiveNeo4jOperations neo4jOperations() {
return mock(ReactiveNeo4jOperations.class);
}
}
@Configuration
static class ConfigurationWithExistingReactiveTransactionManager {
@Bean("myCustomReactiveTransactionManager")
ReactiveTransactionManager transactionManager() {
return mock(ReactiveTransactionManager.class);
}
}
@Configuration
static class ConfigurationWithExistingReactiveDatabaseSelectionProvider {
@Bean
ReactiveDatabaseSelectionProvider databaseNameProvider() {
return () -> Mono.just(DatabaseSelection.byName("whatever"));
}
}
}

@ -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.

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,9 +16,6 @@
package org.springframework.boot.autoconfigure.data.neo4j.city;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.neo4j.repository.Neo4jRepository;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
public interface ReactiveCityRepository extends ReactiveNeo4jRepository<City, Long> {

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -16,12 +16,12 @@
package org.springframework.boot.autoconfigure.data.neo4j.country;
import java.io.Serializable;
import org.springframework.data.neo4j.core.schema.GeneratedValue;
import org.springframework.data.neo4j.core.schema.Id;
import org.springframework.data.neo4j.core.schema.Node;
import java.io.Serializable;
@Node
public class Country implements Serializable {

@ -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.

@ -2978,7 +2978,7 @@ class ExampleIntegrationTests {
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.data.neo4j.uri", neo4j::getBoltUrl);
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
}
}

@ -4532,47 +4532,6 @@ Each will be called in order with the `ConfigBuilder` that is used to build the
[[boot-features-connecting-to-neo4j-embedded]]
==== Using the Embedded Mode
If you add `org.neo4j:neo4j-ogm-embedded-driver` to the dependencies of your application, Spring Boot automatically configures an in-process embedded instance of Neo4j that does not persist any data when your application shuts down.
NOTE: As the embedded Neo4j OGM driver does not provide the Neo4j kernel itself, you have to declare `org.neo4j:neo4j` as dependency yourself.
Refer to https://neo4j.com/docs/ogm-manual/current/reference/#reference:getting-started[the Neo4j OGM documentation] for a list of compatible versions.
The embedded driver takes precedence over the other drivers when there are multiple drivers on the classpath.
You can explicitly disable the embedded mode by setting `spring.data.neo4j.embedded.enabled=false`.
<<boot-features-testing-spring-boot-applications-testing-autoconfigured-neo4j-test,Data Neo4j Tests>> automatically make use of an embedded Neo4j instance if the embedded driver and Neo4j kernel are on the classpath as described above.
NOTE: You can enable persistence for the embedded mode by providing a path to a database file in your configuration, e.g. `spring.data.neo4j.uri=file://var/tmp/graph.db`.
[[boot-features-neo4j-ogm-native-types]]
==== Using Native Types
Neo4j-OGM can map some types, like those in `java.time.*`, to `String`-based properties or to one of the native types that Neo4j provides.
For backwards compatibility reasons the default for Neo4j-OGM is to use a `String`-based representation.
To use native types, add a dependency on either `org.neo4j:neo4j-ogm-bolt-native-types` or `org.neo4j:neo4j-ogm-embedded-native-types`, and configure the configprop:spring.data.neo4j.use-native-types[] property as shown in the following example:
[source,properties,indent=0,configprops]
----
spring.data.neo4j.use-native-types=true
----
[[boot-features-neo4j-ogm-session]]
==== Neo4jSession
By default, if you are running a web application, the session is bound to the thread for the entire processing of the request (that is, it uses the "Open Session in View" pattern).
If you do not want this behavior, add the following line to your `application.properties` file:
[source,properties,indent=0,configprops]
----
spring.data.neo4j.open-in-view=false
----
[[boot-features-spring-data-neo4j-repositories]]
==== Spring Data Neo4j Repositories
Spring Data includes repository support for Neo4j.

@ -42,7 +42,10 @@ org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
# AutoConfigureDataNeo4j auto-configuration imports
org.springframework.boot.test.autoconfigure.data.neo4j.AutoConfigureDataNeo4j=\
org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jReactiveRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration

@ -19,8 +19,6 @@ package org.springframework.boot.test.autoconfigure.data.neo4j;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
@ -28,6 +26,7 @@ import org.testcontainers.junit.jupiter.Testcontainers;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.neo4j.core.Neo4jTemplate;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
@ -49,6 +48,11 @@ class DataNeo4jTestIntegrationTests {
static final Neo4jContainer<?> neo4j = new Neo4jContainer<>().withoutAuthentication()
.withStartupTimeout(Duration.ofMinutes(10));
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
}
@Autowired
private Neo4jTemplate neo4jTemplate;
@ -58,11 +62,6 @@ class DataNeo4jTestIntegrationTests {
@Autowired
private ApplicationContext applicationContext;
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
}
@Test
void testRepository() {
ExampleGraph exampleGraph = new ExampleGraph("Look, new @DataNeo4jTest!");

@ -44,14 +44,14 @@ class DataNeo4jTestPropertiesIntegrationTests {
static final Neo4jContainer<?> neo4j = new Neo4jContainer<>().withoutAuthentication()
.withStartupTimeout(Duration.ofMinutes(10));
@Autowired
private Environment environment;
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
}
@Autowired
private Environment environment;
@Test
void environmentWithNewProfile() {
assertThat(this.environment.getActiveProfiles()).containsExactly("test");

@ -16,30 +16,22 @@
package org.springframework.boot.test.autoconfigure.data.neo4j;
import java.time.Duration;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;
import org.springframework.data.neo4j.core.transaction.ReactiveNeo4jTransactionManager;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.ReactiveTransactionManager;
import org.testcontainers.containers.Neo4jContainer;
import org.testcontainers.junit.jupiter.Container;
import org.testcontainers.junit.jupiter.Testcontainers;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;
import java.time.Duration;
import org.neo4j.driver.AccessMode;
import org.neo4j.driver.Driver;
import org.neo4j.driver.Session;
import org.neo4j.driver.SessionConfig;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.neo4j.core.ReactiveNeo4jTemplate;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
/**
@ -50,7 +42,7 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
*/
@DataNeo4jTest
@Testcontainers(disabledWithoutDocker = true)
class ReactiveDataNeo4jIntegrationTests {
class DataNeo4jTestReactiveIntegrationTests {
@Container
static final Neo4jContainer<?> neo4j = new Neo4jContainer<>("neo4j:4.0").withoutAuthentication()
@ -62,24 +54,19 @@ class ReactiveDataNeo4jIntegrationTests {
}
@Autowired
private Driver driver;
private ReactiveNeo4jTemplate neo4jTemplate;
@Autowired
private ReactiveNeo4jTemplate neo4jTemplate;
private ExampleReactiveRepository exampleRepository;
@Autowired
private ApplicationContext applicationContext;
@Test
void testTemplate() {
Mono.just(new ExampleGraph("Look, new @DataNeo4jTest with reactive!")).flatMap(neo4jTemplate::save)
void testRepository() {
Mono.just(new ExampleGraph("Look, new @DataNeo4jTest with reactive!")).flatMap(this.exampleRepository::save)
.as(StepVerifier::create).expectNextCount(1).verifyComplete();
try (Session session = driver.session(SessionConfig.builder().withDefaultAccessMode(AccessMode.READ).build())) {
long cnt = session.run("MATCH (n:ExampleGraph) RETURN count(n) as cnt").single().get("cnt").asLong();
assertThat(cnt).isEqualTo(1L);
}
StepVerifier.create(this.neo4jTemplate.count(ExampleGraph.class)).expectNext(1L).verifyComplete();
}
@Test
@ -88,13 +75,4 @@ class ReactiveDataNeo4jIntegrationTests {
.isThrownBy(() -> this.applicationContext.getBean(ExampleService.class));
}
@Test
void didProvideOnlyReactiveTransactionManager() {
assertThat(this.applicationContext.getBean(ReactiveTransactionManager.class))
.isInstanceOf(ReactiveNeo4jTransactionManager.class);
assertThatExceptionOfType(NoSuchBeanDefinitionException.class)
.isThrownBy(() -> this.applicationContext.getBean(PlatformTransactionManager.class));
}
}

@ -45,14 +45,14 @@ class DataNeo4jTestWithIncludeFilterIntegrationTests {
static final Neo4jContainer<?> neo4j = new Neo4jContainer<>().withoutAuthentication()
.withStartupTimeout(Duration.ofMinutes(10));
@Autowired
private ExampleService service;
@DynamicPropertySource
static void neo4jProperties(DynamicPropertyRegistry registry) {
registry.add("spring.neo4j.uri", neo4j::getBoltUrl);
}
@Autowired
private ExampleService service;
@Test
void testService() {
assertThat(this.service.hasNode(ExampleGraph.class)).isFalse();

@ -1,69 +0,0 @@
/*
* Copyright (c) 2019-2020 "Neo4j,"
* Neo4j Sweden AB [https://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.test.autoconfigure.data.neo4j;
import org.junit.jupiter.api.Test;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;
import java.io.IOException;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Michael J. Simons
*/
class DataNeo4jTypeExcludeFilterTests {
private MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
@Test
void matchWithExcludeFilter() throws Exception {
DataNeo4jTypeExcludeFilter filter = new DataNeo4jTypeExcludeFilter(WithExcludeFilter.class);
assertThat(excludes(filter, ExampleService.class)).isTrue();
assertThat(excludes(filter, ExampleRepository.class)).isTrue();
}
@Test
void matchWithoutExcludeFilter() throws Exception {
DataNeo4jTypeExcludeFilter filter = new DataNeo4jTypeExcludeFilter(WithoutExcludeFilter.class);
assertThat(excludes(filter, ExampleService.class)).isTrue();
assertThat(excludes(filter, ExampleRepository.class)).isFalse();
}
@DataNeo4jTest(
excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = ExampleRepository.class))
static class WithExcludeFilter {
}
@DataNeo4jTest
static class WithoutExcludeFilter {
}
private boolean excludes(DataNeo4jTypeExcludeFilter filter, Class<?> type) throws IOException {
MetadataReader metadataReader = this.metadataReaderFactory.getMetadataReader(type.getName());
return filter.match(metadataReader, this.metadataReaderFactory);
}
}

@ -1,5 +1,5 @@
/*
* Copyright 2012-2019 the original author or authors.
* Copyright 2012-2020 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -25,7 +25,6 @@ import org.springframework.data.neo4j.core.schema.Property;
* Example graph used with {@link DataNeo4jTest @DataNeo4jTest} tests.
*
* @author Eddú Meléndez
* @author Michael J. Simons
*/
@Node
public class ExampleGraph {

@ -0,0 +1,28 @@
/*
* Copyright 2012-2019 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.test.autoconfigure.data.neo4j;
import org.springframework.data.neo4j.repository.ReactiveNeo4jRepository;
/**
* Example reactive repository used with {@link DataNeo4jTest @DataNeo4jTest} tests.
*
* @author Stephane Nicoll
*/
interface ExampleReactiveRepository extends ReactiveNeo4jRepository<ExampleGraph, Long> {
}
Loading…
Cancel
Save