Polish "Upgrade to Spring Data Neo4j 6"

See gh-22299
This commit is contained in:
Stephane Nicoll
2020-07-29 10:54:02 +02:00
parent 15cd343737
commit 9bc71fe44f
35 changed files with 593 additions and 732 deletions

View File

@@ -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;
}
}

View File

@@ -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;
}
}

View File

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

View File

@@ -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);
}

View File

@@ -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 {
}

View File

@@ -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 {
}

View File

@@ -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 {
}

View File

@@ -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 {
}

View File

@@ -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 {
}

View File

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

View File

@@ -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",

View File

@@ -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,\

View File

@@ -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;
}

View File

@@ -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;
}

View File

@@ -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");
}
}

View File

@@ -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"));
}
}
}

View File

@@ -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 {
}
}

View File

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

View File

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

View File

@@ -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"));
}
}
}

View File

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

View File

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

View File

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

View File

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