Polish "Add opt-in support for Neo4j-OGM native types"

See gh-15637
pull/13916/head
Andy Wilkinson 6 years ago
parent af21b847a0
commit 18174a8e9e

@ -1,5 +1,5 @@
/* /*
* Copyright 2012-2019 the original author or authors. * Copyright 2012-2018 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -20,9 +20,6 @@ import java.util.List;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.neo4j.ogm.driver.NativeTypesException;
import org.neo4j.ogm.driver.NativeTypesNotAvailableException;
import org.neo4j.ogm.driver.NativeTypesNotSupportedException;
import org.neo4j.ogm.session.SessionFactory; import org.neo4j.ogm.session.SessionFactory;
import org.neo4j.ogm.session.event.EventListener; import org.neo4j.ogm.session.event.EventListener;
@ -37,14 +34,12 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplicat
import org.springframework.boot.autoconfigure.domain.EntityScanPackages; import org.springframework.boot.autoconfigure.domain.EntityScanPackages;
import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers; import org.springframework.boot.autoconfigure.transaction.TransactionManagerCustomizers;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.data.neo4j.transaction.Neo4jTransactionManager; import org.springframework.data.neo4j.transaction.Neo4jTransactionManager;
import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor; import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor;
import org.springframework.lang.Nullable;
import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
@ -58,7 +53,6 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
* @author Vince Bickers * @author Vince Bickers
* @author Stephane Nicoll * @author Stephane Nicoll
* @author Kazuki Shimizu * @author Kazuki Shimizu
* @author Michael Simons
* @since 1.4.0 * @since 1.4.0
*/ */
@Configuration @Configuration
@ -79,45 +73,11 @@ public class Neo4jDataAutoConfiguration {
public SessionFactory sessionFactory(org.neo4j.ogm.config.Configuration configuration, public SessionFactory sessionFactory(org.neo4j.ogm.config.Configuration configuration,
ApplicationContext applicationContext, ApplicationContext applicationContext,
ObjectProvider<EventListener> eventListeners) { ObjectProvider<EventListener> eventListeners) {
try {
SessionFactory sessionFactory = new SessionFactory(configuration, SessionFactory sessionFactory = new SessionFactory(configuration,
getPackagesToScan(applicationContext)); getPackagesToScan(applicationContext));
eventListeners.forEach(sessionFactory::register); eventListeners.stream().forEach(sessionFactory::register);
return sessionFactory; return sessionFactory;
} }
catch (NativeTypesException ex) {
InvalidConfigurationPropertyValueException translatedMessage = translateNativeTypesException(
ex);
throw (translatedMessage != null) ? translatedMessage : ex;
}
}
@Nullable
private static InvalidConfigurationPropertyValueException translateNativeTypesException(
NativeTypesException cause) {
String propertyName = Neo4jProperties.CONFIGURATION_PREFIX + ".use-native-types";
boolean propertyValue = true;
if (cause instanceof NativeTypesNotAvailableException) {
String message = String.format(
"The native type module for your Neo4j-OGM driver is not available. "
+ "Please add the following dependency to your build:%n'%s'.",
((NativeTypesNotAvailableException) cause).getRequiredModule());
return new InvalidConfigurationPropertyValueException(propertyName,
propertyValue, message);
}
if (cause instanceof NativeTypesNotSupportedException) {
String message = String.format(
"The configured Neo4j-OGM driver %s does not support Neo4j native types. "
+ "Please consider one of the drivers that support Neo4js native types like the Bolt or the embedded driver.",
cause.getDriverClassName());
return new InvalidConfigurationPropertyValueException(propertyName,
propertyValue, message);
}
return null;
}
@Bean @Bean
@ConditionalOnMissingBean(PlatformTransactionManager.class) @ConditionalOnMissingBean(PlatformTransactionManager.class)

@ -36,11 +36,9 @@ import org.springframework.util.ClassUtils;
* @author Michael Simons * @author Michael Simons
* @since 1.4.0 * @since 1.4.0
*/ */
@ConfigurationProperties(prefix = Neo4jProperties.CONFIGURATION_PREFIX) @ConfigurationProperties(prefix = "spring.data.neo4j")
public class Neo4jProperties implements ApplicationContextAware { public class Neo4jProperties implements ApplicationContextAware {
static final String CONFIGURATION_PREFIX = "spring.data.neo4j";
static final String EMBEDDED_DRIVER = "org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver"; static final String EMBEDDED_DRIVER = "org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver";
static final String HTTP_DRIVER = "org.neo4j.ogm.drivers.http.driver.HttpDriver"; static final String HTTP_DRIVER = "org.neo4j.ogm.drivers.http.driver.HttpDriver";
@ -76,8 +74,7 @@ public class Neo4jProperties implements ApplicationContextAware {
private Boolean openInView; private Boolean openInView;
/** /**
* Disables the conversion of java.time.* and spatial types in Neo4j-OGM entities and * Whether to use Neo4j native types wherever possible.
* uses Neo4j native types wherever possible.
*/ */
private boolean useNativeTypes = false; private boolean useNativeTypes = false;

@ -18,6 +18,8 @@ package org.springframework.boot.autoconfigure.data.neo4j;
import com.github.benmanes.caffeine.cache.Caffeine; import com.github.benmanes.caffeine.cache.Caffeine;
import org.junit.Test; import org.junit.Test;
import org.neo4j.ogm.driver.NativeTypesNotAvailableException;
import org.neo4j.ogm.driver.NativeTypesNotSupportedException;
import org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver; import org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver;
import org.neo4j.ogm.session.Session; import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory; import org.neo4j.ogm.session.SessionFactory;
@ -32,7 +34,6 @@ import org.springframework.boot.autoconfigure.data.neo4j.city.City;
import org.springframework.boot.autoconfigure.data.neo4j.country.Country; import org.springframework.boot.autoconfigure.data.neo4j.country.Country;
import org.springframework.boot.autoconfigure.domain.EntityScan; import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration;
import org.springframework.boot.context.properties.source.InvalidConfigurationPropertyValueException;
import org.springframework.boot.test.context.FilteredClassLoader; import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner; import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner; import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
@ -47,7 +48,6 @@ import org.springframework.data.neo4j.web.support.OpenSessionInViewInterceptor;
import org.springframework.web.context.WebApplicationContext; import org.springframework.web.context.WebApplicationContext;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
@ -158,35 +158,33 @@ public class Neo4jDataAutoConfigurationTests {
} }
@Test @Test
public void shouldDealWithNativeTypesNotAvailableException() { public void shouldFailWhenNativeTypesAreNotAvailable() {
assertThatIllegalStateException().isThrownBy(() -> {
this.contextRunner this.contextRunner
.withClassLoader( .withClassLoader(
new FilteredClassLoader("org.neo4j.ogm.drivers.bolt.types")) new FilteredClassLoader("org.neo4j.ogm.drivers.bolt.types"))
.withPropertyValues("spring.data.neo4j.uri=bolt://localhost:7687", .withPropertyValues("spring.data.neo4j.uri=bolt://localhost:7687",
"spring.data.neo4j.use-native-types:true") "spring.data.neo4j.use-native-types:true")
.withConfiguration( .withConfiguration(AutoConfigurations.of(Neo4jDataAutoConfiguration.class,
AutoConfigurations.of(Neo4jDataAutoConfiguration.class,
TransactionAutoConfiguration.class)) TransactionAutoConfiguration.class))
.run((context) -> context.getBean(SessionFactory.class)); .run((context) -> {
}).withRootCauseInstanceOf(InvalidConfigurationPropertyValueException.class) assertThat(context).hasFailed();
.withStackTraceContaining( assertThat(context.getStartupFailure()).hasRootCauseInstanceOf(
"The native type module for your Neo4j-OGM driver is not available. Please add the following dependency to your build:"); NativeTypesNotAvailableException.class);
});
} }
@Test @Test
public void shouldDealWithNativeTypesNotSupportedException() { public void shouldFailWhenNativeTypesAreNotSupported() {
assertThatIllegalStateException().isThrownBy(() -> {
this.contextRunner this.contextRunner
.withPropertyValues("spring.data.neo4j.uri=http://localhost:7474", .withPropertyValues("spring.data.neo4j.uri=http://localhost:7474",
"spring.data.neo4j.use-native-types:true") "spring.data.neo4j.use-native-types:true")
.withConfiguration( .withConfiguration(AutoConfigurations.of(Neo4jDataAutoConfiguration.class,
AutoConfigurations.of(Neo4jDataAutoConfiguration.class,
TransactionAutoConfiguration.class)) TransactionAutoConfiguration.class))
.run((context) -> context.getBean(SessionFactory.class)); .run((context) -> {
}).withRootCauseInstanceOf(InvalidConfigurationPropertyValueException.class) assertThat(context).hasFailed();
.withStackTraceContaining( assertThat(context.getStartupFailure()).hasRootCauseInstanceOf(
" The configured Neo4j-OGM driver org.neo4j.ogm.drivers.http.driver.HttpDriver does not support Neo4j native types."); NativeTypesNotSupportedException.class);
});
} }
@Test @Test

@ -695,6 +695,7 @@ content into your application. Rather, pick only the properties that you need.
spring.data.neo4j.password= # Login password of the server. spring.data.neo4j.password= # Login password of the server.
spring.data.neo4j.repositories.enabled=true # Whether to enable Neo4j repositories. spring.data.neo4j.repositories.enabled=true # Whether to enable Neo4j repositories.
spring.data.neo4j.uri= # URI used by the driver. Auto-detected by default. spring.data.neo4j.uri= # URI used by the driver. Auto-detected by default.
spring.data.neo4j.use-native-types=false # Whether to use Neo4j native types wherever possible.
spring.data.neo4j.username= # Login user of the server. spring.data.neo4j.username= # Login user of the server.
# DATA REST ({sc-spring-boot-autoconfigure}/data/rest/RepositoryRestProperties.{sc-ext}[RepositoryRestProperties]) # DATA REST ({sc-spring-boot-autoconfigure}/data/rest/RepositoryRestProperties.{sc-ext}[RepositoryRestProperties])

@ -4441,22 +4441,19 @@ in your configuration, e.g. `spring.data.neo4j.uri=file://var/tmp/graph.db`.
[[boot-features-neo4j-ogm-native-types]] [[boot-features-neo4j-ogm-native-types]]
==== Using native types ==== Using Native Types
Neo4j-OGM can map some types, like `java.time.*` to `String` based properties or Neo4j-OGM can map some types, like those in `java.time.*`, to `String`-based properties
use one of the various native types that Neo4j provides. or to one of the native types that Neo4j provides. For backwards compatibility reasons
For backwards compatibility reasons the default for Neo4j-OGM is using a `String` based representation. the default for Neo4j-OGM is to use a `String`-based representation. To use native types,
To change that behaviour, please add one of `org.neo4j:neo4j-ogm-bolt-native-types` or `org.neo4j:neo4j-ogm-embedded-native-types` add a dependency on either `org.neo4j:neo4j-ogm-bolt-native-types` or
to the dependencies of your application `org.neo4j:neo4j-ogm-embedded-native-types`, and configure the
and use the following property in your Spring Boot configuration: `spring.data.neo4j.use-native-types` property as shown in the following example:
[source,properties,indent=0] [source,properties,indent=0]
---- ----
spring.data.neo4j.use-native-types=true spring.data.neo4j.use-native-types=true
---- ----
Please refer to the Neo4j-OGM reference for more information about
https://neo4j.com/docs/ogm-manual/current/reference/#reference:native-property-types[native property types].
[[boot-features-neo4j-ogm-session]] [[boot-features-neo4j-ogm-session]]

Loading…
Cancel
Save