Skip to content

Commit af21b84

Browse files
michael-simonswilkinsona
authored andcommitted
Add opt-in support for Neo4j-OGM native types
This includes tests for the autoconfiguration using that new property. The test require the native types for Bolt and embedded in the test scope, so the Neo4j-OGM native types have been added to managed dependencies. The enhanced autoconfiguration throws an InvalidConfigurationPropertyValueException when native types cannot be used due to missing dependencies or wrong transport mode. See spring-projectsgh-15637
1 parent c8070f4 commit af21b84

File tree

7 files changed

+168
-13
lines changed

7 files changed

+168
-13
lines changed

spring-boot-project/spring-boot-autoconfigure/pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -782,14 +782,19 @@
782782
</dependency>
783783
<dependency>
784784
<groupId>org.neo4j</groupId>
785-
<artifactId>neo4j-ogm-http-driver</artifactId>
785+
<artifactId>neo4j-ogm-bolt-native-types</artifactId>
786786
<scope>test</scope>
787787
</dependency>
788788
<dependency>
789789
<groupId>org.neo4j</groupId>
790790
<artifactId>neo4j-ogm-embedded-driver</artifactId>
791791
<scope>test</scope>
792792
</dependency>
793+
<dependency>
794+
<groupId>org.neo4j</groupId>
795+
<artifactId>neo4j-ogm-http-driver</artifactId>
796+
<scope>test</scope>
797+
</dependency>
793798
<dependency>
794799
<groupId>org.springframework</groupId>
795800
<artifactId>spring-test</artifactId>

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -20,6 +20,9 @@
2020

2121
import org.apache.commons.logging.Log;
2222
import org.apache.commons.logging.LogFactory;
23+
import org.neo4j.ogm.driver.NativeTypesException;
24+
import org.neo4j.ogm.driver.NativeTypesNotAvailableException;
25+
import org.neo4j.ogm.driver.NativeTypesNotSupportedException;
2326
import org.neo4j.ogm.session.SessionFactory;
2427
import org.neo4j.ogm.session.event.EventListener;
2528

@@ -34,12 +37,14 @@
3437
import org.springframework.boot.autoconfigure.domain.EntityScanPackages;
3538
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
3639
import org.springframework.boot.context.properties.EnableConfigurationProperties;
40+
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
3741
import org.springframework.context.ApplicationContext;
3842
import org.springframework.context.annotation.Bean;
3943
import org.springframework.context.annotation.Configuration;
4044
import org.springframework.context.annotation.Import;
4145
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
4246
import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor;
47+
import org.springframework.lang.Nullable;
4348
import org.springframework.transaction.PlatformTransactionManager;
4449
import org.springframework.util.StringUtils;
4550
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
@@ -53,6 +58,7 @@
5358
* @author Vince Bickers
5459
* @author Stephane Nicoll
5560
* @author Kazuki Shimizu
61+
* @author Michael Simons
5662
* @since 1.4.0
5763
*/
5864
@Configuration
@@ -73,10 +79,44 @@ public org.neo4j.ogm.config.Configuration configuration(Neo4jProperties properti
7379
public SessionFactory sessionFactory(org.neo4j.ogm.config.Configuration configuration,
7480
ApplicationContext applicationContext,
7581
ObjectProvider<EventListener> eventListeners) {
76-
SessionFactory sessionFactory = new SessionFactory(configuration,
77-
getPackagesToScan(applicationContext));
78-
eventListeners.stream().forEach(sessionFactory::register);
79-
return sessionFactory;
82+
try {
83+
SessionFactory sessionFactory = new SessionFactory(configuration,
84+
getPackagesToScan(applicationContext));
85+
eventListeners.forEach(sessionFactory::register);
86+
return sessionFactory;
87+
}
88+
catch (NativeTypesException ex) {
89+
InvalidConfigurationPropertyValueException translatedMessage = translateNativeTypesException(
90+
ex);
91+
throw (translatedMessage != null) ? translatedMessage : ex;
92+
}
93+
}
94+
95+
@Nullable
96+
private static InvalidConfigurationPropertyValueException translateNativeTypesException(
97+
NativeTypesException cause) {
98+
99+
String propertyName = Neo4jProperties.CONFIGURATION_PREFIX + ".use-native-types";
100+
boolean propertyValue = true;
101+
102+
if (cause instanceof NativeTypesNotAvailableException) {
103+
String message = String.format(
104+
"The native type module for your Neo4j-OGM driver is not available. "
105+
+ "Please add the following dependency to your build:%n'%s'.",
106+
((NativeTypesNotAvailableException) cause).getRequiredModule());
107+
return new InvalidConfigurationPropertyValueException(propertyName,
108+
propertyValue, message);
109+
}
110+
if (cause instanceof NativeTypesNotSupportedException) {
111+
String message = String.format(
112+
"The configured Neo4j-OGM driver %s does not support Neo4j native types. "
113+
+ "Please consider one of the drivers that support Neo4js native types like the Bolt or the embedded driver.",
114+
cause.getDriverClassName());
115+
return new InvalidConfigurationPropertyValueException(propertyName,
116+
propertyValue, message);
117+
}
118+
119+
return null;
80120
}
81121

82122
@Bean

spring-boot-project/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jProperties.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2017 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -33,11 +33,14 @@
3333
* @author Michael Hunger
3434
* @author Vince Bickers
3535
* @author Aurélien Leboulanger
36+
* @author Michael Simons
3637
* @since 1.4.0
3738
*/
38-
@ConfigurationProperties(prefix = "spring.data.neo4j")
39+
@ConfigurationProperties(prefix = Neo4jProperties.CONFIGURATION_PREFIX)
3940
public class Neo4jProperties implements ApplicationContextAware {
4041

42+
static final String CONFIGURATION_PREFIX = "spring.data.neo4j";
43+
4144
static final String EMBEDDED_DRIVER = "org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver";
4245

4346
static final String HTTP_DRIVER = "org.neo4j.ogm.drivers.http.driver.HttpDriver";
@@ -72,6 +75,12 @@ public class Neo4jProperties implements ApplicationContextAware {
7275
*/
7376
private Boolean openInView;
7477

78+
/**
79+
* Disables the conversion of java.time.* and spatial types in Neo4j-OGM entities and
80+
* uses Neo4j native types wherever possible.
81+
*/
82+
private boolean useNativeTypes = false;
83+
7584
private final Embedded embedded = new Embedded();
7685

7786
private ClassLoader classLoader = Neo4jProperties.class.getClassLoader();
@@ -116,6 +125,14 @@ public void setOpenInView(Boolean openInView) {
116125
this.openInView = openInView;
117126
}
118127

128+
public boolean isUseNativeTypes() {
129+
return this.useNativeTypes;
130+
}
131+
132+
public void setUseNativeTypes(boolean useNativeTypes) {
133+
this.useNativeTypes = useNativeTypes;
134+
}
135+
119136
public Embedded getEmbedded() {
120137
return this.embedded;
121138
}
@@ -146,6 +163,9 @@ private void configure(Builder builder) {
146163
builder.credentials(this.username, this.password);
147164
}
148165
builder.autoIndex(this.getAutoIndex().getName());
166+
if (this.useNativeTypes) {
167+
builder.useNativeTypes();
168+
}
149169
}
150170

151171
private void configureUriWithDefaults(Builder builder) {

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java

Lines changed: 49 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -32,6 +32,7 @@
3232
import org.springframework.boot.autoconfigure.data.neo4j.country.Country;
3333
import org.springframework.boot.autoconfigure.domain.EntityScan;
3434
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
35+
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
3536
import org.springframework.boot.test.context.FilteredClassLoader;
3637
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
3738
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
@@ -46,13 +47,14 @@
4647
import org.springframework.web.context.WebApplicationContext;
4748

4849
import static org.assertj.core.api.Assertions.assertThat;
50+
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
4951
import static org.mockito.ArgumentMatchers.any;
5052
import static org.mockito.Mockito.mock;
5153
import static org.mockito.Mockito.verify;
5254

5355
/**
54-
* Tests for {@link Neo4jDataAutoConfiguration}. Tests can't use the embedded driver as we
55-
* use Lucene 4 and Neo4j still requires 3.
56+
* Tests for {@link Neo4jDataAutoConfiguration}. Tests should not use the embedded driver
57+
* as it requires the complete Neo4j-Kernel and server to function properly.
5658
*
5759
* @author Stephane Nicoll
5860
* @author Michael Hunger
@@ -116,7 +118,6 @@ public void customConfiguration() {
116118
assertThat(context)
117119
.hasSingleBean(org.neo4j.ogm.config.Configuration.class);
118120
});
119-
120121
}
121122

122123
@Test
@@ -144,6 +145,50 @@ public void openSessionInViewInterceptorCanBeDisabled() {
144145
.doesNotHaveBean(OpenSessionInViewInterceptor.class));
145146
}
146147

148+
@Test
149+
public void shouldBeAbleToUseNativeTypesWithBolt() {
150+
this.contextRunner
151+
.withPropertyValues("spring.data.neo4j.uri=bolt://localhost:7687",
152+
"spring.data.neo4j.use-native-types:true")
153+
.withConfiguration(AutoConfigurations.of(Neo4jDataAutoConfiguration.class,
154+
TransactionAutoConfiguration.class))
155+
.run((context) -> assertThat(context)
156+
.getBean(org.neo4j.ogm.config.Configuration.class)
157+
.hasFieldOrPropertyWithValue("useNativeTypes", true));
158+
}
159+
160+
@Test
161+
public void shouldDealWithNativeTypesNotAvailableException() {
162+
assertThatIllegalStateException().isThrownBy(() -> {
163+
this.contextRunner
164+
.withClassLoader(
165+
new FilteredClassLoader("org.neo4j.ogm.drivers.bolt.types"))
166+
.withPropertyValues("spring.data.neo4j.uri=bolt://localhost:7687",
167+
"spring.data.neo4j.use-native-types:true")
168+
.withConfiguration(
169+
AutoConfigurations.of(Neo4jDataAutoConfiguration.class,
170+
TransactionAutoConfiguration.class))
171+
.run((context) -> context.getBean(SessionFactory.class));
172+
}).withRootCauseInstanceOf(InvalidConfigurationPropertyValueException.class)
173+
.withStackTraceContaining(
174+
"The native type module for your Neo4j-OGM driver is not available. Please add the following dependency to your build:");
175+
}
176+
177+
@Test
178+
public void shouldDealWithNativeTypesNotSupportedException() {
179+
assertThatIllegalStateException().isThrownBy(() -> {
180+
this.contextRunner
181+
.withPropertyValues("spring.data.neo4j.uri=http://localhost:7474",
182+
"spring.data.neo4j.use-native-types:true")
183+
.withConfiguration(
184+
AutoConfigurations.of(Neo4jDataAutoConfiguration.class,
185+
TransactionAutoConfiguration.class))
186+
.run((context) -> context.getBean(SessionFactory.class));
187+
}).withRootCauseInstanceOf(InvalidConfigurationPropertyValueException.class)
188+
.withStackTraceContaining(
189+
" The configured Neo4j-OGM driver org.neo4j.ogm.drivers.http.driver.HttpDriver does not support Neo4j native types.");
190+
}
191+
147192
@Test
148193
public void eventListenersAreAutoRegistered() {
149194
this.contextRunner.withUserConfiguration(EventListenerConfiguration.class)

spring-boot-project/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jPropertiesTests.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2012-2018 the original author or authors.
2+
* Copyright 2012-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -35,6 +35,7 @@
3535
* Tests for {@link Neo4jProperties}.
3636
*
3737
* @author Stephane Nicoll
38+
* @author Michael Simons
3839
*/
3940
public class Neo4jPropertiesTests {
4041

@@ -147,6 +148,21 @@ public void embeddedModeWithRelativeLocation() {
147148
"file:relative/path/to/my.db");
148149
}
149150

151+
@Test
152+
public void nativeTypesAreSetToFalseByDefault() {
153+
Neo4jProperties properties = load(true);
154+
Configuration configuration = properties.createConfiguration();
155+
assertThat(configuration.getUseNativeTypes()).isFalse();
156+
}
157+
158+
@Test
159+
public void nativeTypesCanBeConfigured() {
160+
Neo4jProperties properties = load(true,
161+
"spring.data.neo4j.use-native-types=true");
162+
Configuration configuration = properties.createConfiguration();
163+
assertThat(configuration.getUseNativeTypes()).isTrue();
164+
}
165+
150166
private static void assertDriver(Configuration actual, String driver, String uri) {
151167
assertThat(actual).isNotNull();
152168
assertThat(actual.getDriverClassName()).isEqualTo(driver);

spring-boot-project/spring-boot-dependencies/pom.xml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2527,6 +2527,11 @@
25272527
<artifactId>neo4j-ogm-bolt-driver</artifactId>
25282528
<version>${neo4j-ogm.version}</version>
25292529
</dependency>
2530+
<dependency>
2531+
<groupId>org.neo4j</groupId>
2532+
<artifactId>neo4j-ogm-bolt-native-types</artifactId>
2533+
<version>${neo4j-ogm.version}</version>
2534+
</dependency>
25302535
<dependency>
25312536
<groupId>org.neo4j</groupId>
25322537
<artifactId>neo4j-ogm-core</artifactId>
@@ -2537,6 +2542,11 @@
25372542
<artifactId>neo4j-ogm-embedded-driver</artifactId>
25382543
<version>${neo4j-ogm.version}</version>
25392544
</dependency>
2545+
<dependency>
2546+
<groupId>org.neo4j</groupId>
2547+
<artifactId>neo4j-ogm-embedded-native-types</artifactId>
2548+
<version>${neo4j-ogm.version}</version>
2549+
</dependency>
25402550
<dependency>
25412551
<groupId>org.neo4j</groupId>
25422552
<artifactId>neo4j-ogm-http-driver</artifactId>

spring-boot-project/spring-boot-docs/src/main/asciidoc/spring-boot-features.adoc

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4440,6 +4440,25 @@ in your configuration, e.g. `spring.data.neo4j.uri=file://var/tmp/graph.db`.
44404440

44414441

44424442

4443+
[[boot-features-neo4j-ogm-native-types]]
4444+
==== Using native types
4445+
Neo4j-OGM can map some types, like `java.time.*` to `String` based properties or
4446+
use one of the various native types that Neo4j provides.
4447+
For backwards compatibility reasons the default for Neo4j-OGM is using a `String` based representation.
4448+
To change that behaviour, please add one of `org.neo4j:neo4j-ogm-bolt-native-types` or `org.neo4j:neo4j-ogm-embedded-native-types`
4449+
to the dependencies of your application
4450+
and use the following property in your Spring Boot configuration:
4451+
4452+
[source,properties,indent=0]
4453+
----
4454+
spring.data.neo4j.use-native-types=true
4455+
----
4456+
4457+
Please refer to the Neo4j-OGM reference for more information about
4458+
https://neo4j.com/docs/ogm-manual/current/reference/#reference:native-property-types[native property types].
4459+
4460+
4461+
44434462
[[boot-features-neo4j-ogm-session]]
44444463
==== Neo4jSession
44454464
By default, if you are running a web application, the session is bound to the thread for

0 commit comments

Comments
 (0)