diff --git a/pom.xml b/pom.xml
index 38818da04..54c4641de 100644
--- a/pom.xml
+++ b/pom.xml
@@ -77,6 +77,7 @@
-SNAPSHOT8.292020.0.1
+ 2.0spring-data-neo4jSDNEO4J1.2.1
@@ -406,6 +407,20 @@
jackson-databindtest
+
+
+ javax.enterprise
+ cdi-api
+ ${cdi}
+ provided
+
+
+ org.jboss.weld.se
+ weld-se-core
+ 3.1.4.Final
+ test
+
+
@@ -641,7 +656,7 @@
htmlbookimg
- ${basedir}/docs
+ ${project.basedir}/src/main/asciidocindex.adoccoderay
diff --git a/src/main/asciidoc/faq/faq.adoc b/src/main/asciidoc/faq/faq.adoc
index 4ee7957f1..bd4c90cfe 100644
--- a/src/main/asciidoc/faq/faq.adoc
+++ b/src/main/asciidoc/faq/faq.adoc
@@ -3,6 +3,7 @@
Here are a couple of more frequently asked question in addition to the ones in the <>.
+[[faq.multidatabase]]
== Neo4j 4.0 supports multiple databases - How can I use them?
You can either statically configure the database name or run your own database name provider.
@@ -32,6 +33,15 @@ Here is a working example for an imperative application secured with Spring Secu
[[faq.databaseSelectionProvider]]
.Neo4jConfig.java
----
+import org.neo4j.springframework.data.core.DatabaseSelection;
+import org.neo4j.springframework.data.core.DatabaseSelectionProvider;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.User;
+
include::../../../../src/test/java/org/springframework/data/neo4j/documentation/Neo4jConfig.java[tags=faq.multidatabase]
----
@@ -208,3 +218,171 @@ movieExample = Example.of(
);
movies = this.movieRepository.findAll(movieExample);
----
+
+== Do I need Spring Boot to use Spring Data Neo4j?
+
+No, you don't.
+While the automatic configuration of many Spring aspects through Spring Boot takes away a lot of manual cruft and is the recommended approach for setting up new Spring projects, you don't need to have to use this.
+
+The following dependency is required for the solutions described above:
+
+[source,xml,subs="verbatim,attributes"]
+----
+
+ {springGroupId}
+ {artifactId}
+ {spring-data-neo4j-version}
+
+----
+
+The coordinates for a Gradle setup are the same.
+
+To select a different database - either statically or dynamically - you can add a Bean of type `DatabaseSelectionProvider` as explained in <>.
+For a reactive scenario, we provide `ReactiveDatabaseSelectionProvider`.
+
+=== Using Spring Data Neo4j inside a Spring context without Spring Boot
+
+We provide two abstract configuration classes to support you in bringing in the necessary beans: `AbstractNeo4jConfig` for imperative database access and `AbstractReactiveNeo4jConfig` for the reactive version.
+They are meant to be used with `@EnableNeo4jRepositories` and `@EnableReactiveNeo4jRepositories` respectively.
+See <> and <> for an example usage.
+Both classes require you to override `driver()` in which you are supposed to create the driver.
+
+To get the imperative version of the <>, the template and support for imperative repositories, use something similar as shown here:
+
+[source,java]
+[[bootless-imperative-configuration]]
+.Enabling Spring Data Neo4j infrastructure for imperative database access
+----
+import org.neo4j.driver.Driver;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+import org.springframework.data.neo4j.config.AbstractNeo4jConfig;
+import org.springframework.data.neo4j.core.DatabaseSelectionProvider;
+import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
+
+@Configuration
+@EnableNeo4jRepositories
+@EnableTransactionManagement
+class MyConfiguration extends AbstractNeo4jConfig {
+
+ @Override @Bean
+ public Driver driver() { // <.>
+ return GraphDatabase.driver("bolt://localhost:7687", AuthTokens.basic("neo4j", "secret"));
+ }
+
+ @Override
+ protected Collection getMappingBasePackages() {
+ return Collections.singletonList(Person.class.getPackage().getName());
+ }
+
+ @Override @Bean // <.>
+ protected DatabaseSelectionProvider databaseSelectionProvider() {
+
+ return DatabaseSelectionProvider.createStaticDatabaseSelectionProvider("yourDatabase");
+ }
+}
+----
+<.> The driver bean is required.
+<.> This statically selects a database named `yourDatabase` and is *optional*.
+
+The following listing provides the reactive Neo4j client and template, enables reactive transaction management and discovers Neo4j related repositories:
+
+[source,java]
+[[bootless-reactive-configuration]]
+.Enabling Spring Data Neo4j infrastructure for reactive database access
+----
+import org.neo4j.driver.Driver;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.neo4j.config.AbstractReactiveNeo4jConfig;
+import org.springframework.data.neo4j.repository.config.EnableReactiveNeo4jRepositories;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@Configuration
+@EnableReactiveNeo4jRepositories
+@EnableTransactionManagement
+class MyConfiguration extends AbstractReactiveNeo4jConfig {
+
+ @Bean
+ @Override
+ public Driver driver() {
+ return GraphDatabase.driver("bolt://localhost:7687", AuthTokens.basic("neo4j", "secret"));
+ }
+
+ @Override
+ protected Collection getMappingBasePackages() {
+ return Collections.singletonList(Person.class.getPackage().getName());
+ }
+}
+----
+
+=== Using Spring Data Neo4j in a CDI 2.0 environment
+
+For your convenience we provide a CDI extension with `Neo4jCdiExtension`.
+When run in a compatible CDI 2.0 container, it will be automatically be registered and loaded through https://docs.oracle.com/javase/tutorial/ext/basics/spi.html[Java's service loader SPI].
+
+The only thing you have to bring into your application is an annotated type that produces the Neo4j Java Driver:
+
+[source,java]
+[[cdi-driver-producer]]
+.A CDI producer for the Neo4j Java Driver
+----
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Disposes;
+import javax.enterprise.inject.Produces;
+
+import org.neo4j.driver.AuthTokens;
+import org.neo4j.driver.Driver;
+import org.neo4j.driver.GraphDatabase;
+
+public class Neo4jConfig {
+
+ @Produces @ApplicationScoped
+ public Driver driver() { // <.>
+ return GraphDatabase
+ .driver("bolt://localhost:7687", AuthTokens.basic("neo4j", "secret"));
+ }
+
+ public void close(@Disposes Driver driver) {
+ driver.close();
+ }
+
+ @Produces @Singleton
+ public DatabaseSelectionProvider getDatabaseSelectionProvider() { // <.>
+ return DatabaseSelectionProvider.createStaticDatabaseSelectionProvider("yourDatabase");
+ }
+}
+----
+<.> Same as with plain Spring in <>, but annotated with the corresponding CDI infrastructure.
+<.> This is *optional*. However, if you run a custom database selection provider, you _must_ not qualify this bean.
+
+If you are running in a SE Container - like the one https://weld.cdi-spec.org[Weld] provides for example, you can enable the extension like that:
+
+[source,java]
+[[cdi-driver-producer-se]]
+.Enabling the Neo4j CDI extension in a SE container
+----
+import javax.enterprise.inject.se.SeContainer;
+import javax.enterprise.inject.se.SeContainerInitializer;
+
+import org.springframework.data.neo4j.config.Neo4jCdiExtension;
+
+public class SomeClass {
+ void someMethod() {
+ try (SeContainer container = SeContainerInitializer.newInstance()
+ .disableDiscovery()
+ .addExtensions(Neo4jCdiExtension.class)
+ .addBeanClasses(YourDriverFactory.class)
+ .addPackages(Package.getPackage("your.domain.package"))
+ .initialize()
+ ) {
+ SomeRepository someRepository = container.select(SomeRepository.class).get();
+ }
+ }
+}
+----
\ No newline at end of file
diff --git a/src/main/asciidoc/index.adoc b/src/main/asciidoc/index.adoc
index 129e6156d..364b14278 100644
--- a/src/main/asciidoc/index.adoc
+++ b/src/main/asciidoc/index.adoc
@@ -24,7 +24,7 @@ include::{manualIncludeDir}/README.adoc[tags=properties]
:springVersion: 5.2.0.RELEASE
:spring-framework-docs: https://docs.spring.io/spring/docs/{springVersion}/spring-framework-reference
:spring-framework-javadoc: https://docs.spring.io/spring/docs/{springVersion}/javadoc-api
-:spring-data-commons-docs: ../../../../../other-spring-data/spring-data-commons/src/main/asciidoc/
+:spring-data-commons-docs: ../../../../../other-spring-data/spring-data-commons/src/main/asciidoc
(C) 2008-2020 The original authors.
diff --git a/src/main/java/org/springframework/data/neo4j/config/AbstractNeo4jConfig.java b/src/main/java/org/springframework/data/neo4j/config/AbstractNeo4jConfig.java
index 2b7bd91b1..e25089a00 100644
--- a/src/main/java/org/springframework/data/neo4j/config/AbstractNeo4jConfig.java
+++ b/src/main/java/org/springframework/data/neo4j/config/AbstractNeo4jConfig.java
@@ -22,6 +22,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
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;
@@ -60,7 +61,7 @@ public abstract class AbstractNeo4jConfig extends Neo4jConfigurationSupport {
}
@Bean(Neo4jRepositoryConfigurationExtension.DEFAULT_NEO4J_TEMPLATE_BEAN_NAME)
- public Neo4jTemplate neo4jTemplate(final Neo4jClient neo4jClient, final Neo4jMappingContext mappingContext,
+ public Neo4jOperations neo4jTemplate(final Neo4jClient neo4jClient, final Neo4jMappingContext mappingContext,
DatabaseSelectionProvider databaseNameProvider) {
return new Neo4jTemplate(neo4jClient, mappingContext, databaseNameProvider);
@@ -86,7 +87,7 @@ public abstract class AbstractNeo4jConfig extends Neo4jConfigurationSupport {
* Neo4j 3.5 and prior.
*/
@Bean
- protected DatabaseSelectionProvider neo4jDatabaseNameProvider() {
+ protected DatabaseSelectionProvider databaseSelectionProvider() {
return DatabaseSelectionProvider.getDefaultSelectionProvider();
}
diff --git a/src/main/java/org/springframework/data/neo4j/config/AbstractReactiveNeo4jConfig.java b/src/main/java/org/springframework/data/neo4j/config/AbstractReactiveNeo4jConfig.java
index aa8e4a6d6..a77072fcd 100644
--- a/src/main/java/org/springframework/data/neo4j/config/AbstractReactiveNeo4jConfig.java
+++ b/src/main/java/org/springframework/data/neo4j/config/AbstractReactiveNeo4jConfig.java
@@ -87,7 +87,7 @@ public abstract class AbstractReactiveNeo4jConfig extends Neo4jConfigurationSupp
* Neo4j 3.5 and prior.
*/
@Bean
- protected ReactiveDatabaseSelectionProvider reactiveNeo4jDatabaseNameProvider() {
+ protected ReactiveDatabaseSelectionProvider reactiveDatabaseSelectionProvider() {
return ReactiveDatabaseSelectionProvider.getDefaultSelectionProvider();
}
diff --git a/src/main/java/org/springframework/data/neo4j/config/Builtin.java b/src/main/java/org/springframework/data/neo4j/config/Builtin.java
new file mode 100644
index 000000000..df2cea8e8
--- /dev/null
+++ b/src/main/java/org/springframework/data/neo4j/config/Builtin.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011-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.data.neo4j.config;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import javax.inject.Qualifier;
+
+import org.apiguardian.api.API;
+
+/**
+ * An internally used CDI {@link Qualifier} to mark all beans produced by our
+ * {@link Neo4jCdiConfigurationSupport configuration support} as built in.
+ * When the {@link Neo4jCdiExtension Spring Data Neo4j CDI extension} is used,
+ * you can opt in to override any of the following beans by providing a {@link javax.enterprise.inject.Produces @Produces} method with the
+ * corresponding return type:
+ *
+ * The order in which the types are presented reflects the usefulness over overriding such a bean.
+ * You might want to add additional conversions to the mapping or provide a bean that dynamically selects a Neo4j database.
+ * Running a custom bean of the template or client might prove useful if you want to add additional methods.
+ *
+ * @author Michael J. Simons
+ * @soundtrack Buckethead - SIGIL Soundtrack
+ * @since 6.0
+ */
+@API(status = API.Status.STABLE, since = "6.0")
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Qualifier
+public @interface Builtin {
+}
diff --git a/src/main/java/org/springframework/data/neo4j/config/Neo4jCdiConfigurationSupport.java b/src/main/java/org/springframework/data/neo4j/config/Neo4jCdiConfigurationSupport.java
new file mode 100644
index 000000000..51fd1d1ef
--- /dev/null
+++ b/src/main/java/org/springframework/data/neo4j/config/Neo4jCdiConfigurationSupport.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2011-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.data.neo4j.config;
+
+import javax.enterprise.context.ApplicationScoped;
+import javax.enterprise.inject.Any;
+import javax.enterprise.inject.Instance;
+import javax.enterprise.inject.Produces;
+import javax.inject.Singleton;
+
+import org.apiguardian.api.API;
+import org.neo4j.driver.Driver;
+import org.springframework.data.mapping.callback.EntityCallback;
+import org.springframework.data.mapping.callback.EntityCallbacks;
+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.transaction.Neo4jTransactionManager;
+import org.springframework.data.neo4j.repository.event.BeforeBindCallback;
+import org.springframework.data.neo4j.repository.event.IdGeneratingBeforeBindCallback;
+import org.springframework.data.neo4j.repository.event.OptimisticLockingBeforeBindCallback;
+import org.springframework.transaction.PlatformTransactionManager;
+
+/**
+ * Support class that can be used as is for all necessary CDI beans or as a blueprint for custom producers.
+ *
+ * @author Michael J. Simons
+ * @soundtrack Buckethead - SIGIL Soundtrack
+ * @since 6.0
+ */
+@API(status = API.Status.INTERNAL, since = "6.0")
+@ApplicationScoped
+class Neo4jCdiConfigurationSupport {
+
+ private T resolve(Instance instance) {
+ if (!instance.isAmbiguous()) {
+ return instance.get();
+ }
+
+ Instance defaultInstance = instance.select(Neo4jCdiExtension.DEFAULT_BEAN);
+ return defaultInstance.get();
+ }
+
+ @Produces @Builtin @Singleton
+ public Neo4jConversions neo4jConversions() {
+ return new Neo4jConversions();
+ }
+
+ @Produces @Builtin @Singleton
+ public DatabaseSelectionProvider databaseSelectionProvider() {
+
+ return DatabaseSelectionProvider.getDefaultSelectionProvider();
+ }
+
+ @Produces @Builtin @Singleton
+ public Neo4jOperations neo4jOperations(
+ final @Any Instance neo4jClient,
+ final @Any Instance mappingContext,
+ final @Any Instance databaseNameProvider,
+ final Instance services
+ ) {
+
+ EntityCallbacks entityCallbacks = EntityCallbacks.create(services.stream().toArray(EntityCallback[]::new));
+ return new Neo4jTemplate(resolve(neo4jClient), resolve(mappingContext), resolve(databaseNameProvider),
+ entityCallbacks);
+ }
+
+ @Produces @Singleton
+ public Neo4jClient neo4jClient(Driver driver) {
+ return Neo4jClient.create(driver);
+ }
+
+ @Produces @Singleton
+ public Neo4jMappingContext neo4jMappingContext(final Driver driver, final @Any Instance neo4JConversions) {
+
+ Neo4jMappingContext neo4jMappingContext = new Neo4jMappingContext(resolve(neo4JConversions), driver.defaultTypeSystem());
+ return neo4jMappingContext;
+ }
+
+ @Produces @Singleton
+ public BeforeBindCallback