Polish contribution

This commit polihes the original Neo4j contribution in several areas.

Rather than providing the packages to scan, this commit rearranges the
`EntityScan` and `EntityScanRegistrar` so that the logic can be shared
for other components. If no package is provided, scanning now defaults to
the "auto-configured" package(s) and a `@NodeEntityScan` annotation
allows to override that.

The configuration has also been updated to detect the driver based on the
`uri` property. If the embedded driver is available we use that by
default. If it is not available, we're trying to connect to a Neo4j
server running on localhost. It is possible to disable the embedded mode
or set the `uri` parameter explicitly to deviate from these defaults.

The sample no longer relies on the embedded driver for licensing reason:
rather it expects an instance running on localhost (like other
data-related samples) and gracefully ignore any connection error. A
README has been added in the sample to further explain the available
options;

Closes gh-5458
This commit is contained in:
Stephane Nicoll 2016-03-22 16:03:14 +01:00
parent 0658cc8aee
commit fd437797b6
45 changed files with 1623 additions and 643 deletions

View File

@ -26,6 +26,7 @@ import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDa
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.test.util.ApplicationContextTestUtils;
import org.springframework.context.ConfigurableApplicationContext;
@ -63,6 +64,7 @@ public class SpringApplicationHierarchyTests {
@EnableAutoConfiguration(exclude = { ElasticsearchDataAutoConfiguration.class,
ElasticsearchRepositoriesAutoConfiguration.class,
CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class,
Neo4jAutoConfiguration.class,
RedisAutoConfiguration.class,
RedisRepositoriesAutoConfiguration.class }, excludeName = {
"org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration" })
@ -75,6 +77,7 @@ public class SpringApplicationHierarchyTests {
ElasticsearchDataAutoConfiguration.class,
ElasticsearchRepositoriesAutoConfiguration.class,
CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class,
Neo4jAutoConfiguration.class,
RedisAutoConfiguration.class,
RedisRepositoriesAutoConfiguration.class }, excludeName = {
"org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration" })

View File

@ -53,7 +53,8 @@ import org.springframework.data.mongodb.repository.support.MongoRepositoryFactor
*/
@Configuration
@ConditionalOnClass({ Mongo.class, MongoRepository.class })
@ConditionalOnMissingBean({ MongoRepositoryFactoryBean.class, MongoRepositoryConfigurationExtension.class })
@ConditionalOnMissingBean({ MongoRepositoryFactoryBean.class,
MongoRepositoryConfigurationExtension.class })
@ConditionalOnProperty(prefix = "spring.data.mongodb.repositories", name = "enabled", havingValue = "true", matchIfMissing = true)
@Import(MongoRepositoriesAutoConfigureRegistrar.class)
@AutoConfigureAfter(MongoDataAutoConfiguration.class)

View File

@ -1,83 +0,0 @@
/*
* Copyright 2012-2015 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
*
* http://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.ogm.session.Neo4jSession;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
import org.springframework.data.neo4j.template.Neo4jOperations;
import org.springframework.data.neo4j.template.Neo4jTemplate;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Neo4j support.
* <p>
* Registers a {@link Neo4jTemplate} bean if no other bean of
* the same type is configured.
*
* @author Michael Hunger
* @author Josh Long
* @author Vince Bickers
* @since 1.3.0
*/
@Configuration
@EnableConfigurationProperties(Neo4jProperties.class)
@ConditionalOnMissingBean(type = "org.springframework.data.neo4j.template.Neo4jOperations")
@ConditionalOnClass({ Neo4jSession.class, Neo4jOperations.class })
public class Neo4jAutoConfiguration extends Neo4jConfiguration {
@Autowired
private Neo4jProperties properties;
@Value("${spring.data.neo4j.domain.packages:null}")
private String[] domainPackages;
@Bean
@ConditionalOnMissingBean(org.neo4j.ogm.config.Configuration.class)
public org.neo4j.ogm.config.Configuration configuration() {
return this.properties.configure();
}
@Override
@ConditionalOnMissingBean(SessionFactory.class)
public SessionFactory getSessionFactory() {
return new SessionFactory(configuration(), this.domainPackages);
}
@Bean
@ConditionalOnMissingBean(Session.class)
@Scope(value = "${spring.data.neo4j.session.lifetime:session}", proxyMode = ScopedProxyMode.TARGET_CLASS)
public Session getSession() throws Exception {
return getSessionFactory().openSession();
}
}

View File

@ -1,105 +0,0 @@
/*
* Copyright 2012-2015 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
*
* http://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.ogm.config.Configuration;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* Configuration properties for Neo4j.
*
* @author Dave Syer
* @author Phillip Webb
* @author Josh Long
* @author Andy Wilkinson
* @author Eddú Meléndez
* @author Michael Hunger
* @author Vince Bickers
*/
@ConfigurationProperties(prefix = "spring.data.neo4j")
public class Neo4jProperties {
// if you don't set this up somewhere, this is what we'll use by default
private String driver = "org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver";
private String compiler;
private String URI;
private String username;
private String password;
public String getDriver() {
return this.driver;
}
public void setDriver(String driver) {
this.driver = driver;
}
public String getCompiler() {
return this.compiler;
}
public void setCompiler(String compiler) {
this.compiler = compiler;
}
public String getURI() {
return this.URI;
}
public void setURI(String URI) {
this.URI = URI;
}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public Configuration configure() {
Configuration configuration = new Configuration();
if (this.driver != null) {
configuration.driverConfiguration().setDriverClassName(this.driver);
}
if (this.URI != null) {
configuration.driverConfiguration().setURI(this.URI);
}
if (this.username != null && this.password != null) {
configuration.driverConfiguration().setCredentials(this.username, this.password);
}
if (this.compiler != null) {
configuration.compilerConfiguration().setCompilerClassName(this.compiler);
}
return configuration;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2016 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.
@ -20,16 +20,13 @@ import org.neo4j.ogm.session.Neo4jSession;
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.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.neo4j.repository.GraphRepository;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import org.springframework.data.neo4j.repository.config.Neo4jRepositoryConfigurationExtension;
import org.springframework.data.neo4j.repository.support.GraphRepositoryFactoryBean;
@ -53,13 +50,14 @@ import org.springframework.data.neo4j.repository.support.GraphRepositoryFactoryB
* @author Dave Syer
* @author Oliver Gierke
* @author Josh Long
* @since 1.4.0
* @see EnableNeo4jRepositories
*/
@Configuration
@ConditionalOnClass({ Neo4jSession.class, GraphRepository.class })
@ConditionalOnMissingBean({ GraphRepositoryFactoryBean.class, Neo4jRepositoryConfigurationExtension.class })
@ConditionalOnProperty(prefix = "spring.data.neo4j.repositories", name = "enabled", havingValue = "true", matchIfMissing = true)
@Import({Neo4jRepositoriesAutoConfigureRegistrar.class})
@Import(Neo4jRepositoriesAutoConfigureRegistrar.class)
@AutoConfigureAfter(Neo4jAutoConfiguration.class)
public class Neo4jRepositoriesAutoConfiguration {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2016 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.
@ -28,7 +28,7 @@ import org.springframework.data.repository.config.RepositoryConfigurationExtensi
* {@link ImportBeanDefinitionRegistrar} used to auto-configure Spring Data Neo4j
* Repositories.
*
* @author Dave Syer
* @author Michael Hunger
*/
class Neo4jRepositoriesAutoConfigureRegistrar extends
AbstractRepositoryConfigurationSourceSupport {

View File

@ -0,0 +1,142 @@
/*
* Copyright 2012-2016 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
*
* http://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.neo4j;
import java.util.List;
import org.neo4j.ogm.session.Neo4jSession;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.neo4j.SessionFactoryProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.data.neo4j.config.Neo4jConfiguration;
import org.springframework.data.neo4j.template.Neo4jOperations;
import org.springframework.data.neo4j.template.Neo4jTemplate;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Neo4j support.
* <p>
* Registers a {@link Neo4jTemplate} bean if no other bean of
* the same type is configured.
*
* @author Michael Hunger
* @author Josh Long
* @author Vince Bickers
* @author Stephane Nicoll
* @since 1.4.0
*/
@Configuration
@ConditionalOnClass({Neo4jSession.class, Neo4jOperations.class})
@ConditionalOnMissingBean(Neo4jOperations.class)
@EnableConfigurationProperties(Neo4jProperties.class)
public class Neo4jAutoConfiguration {
@Configuration
@Import(SessionFactoryProviderConfiguration.class)
public static class SpringBootNeo4jConfiguration extends Neo4jConfiguration {
private final ObjectProvider<SessionFactoryProvider> sessionFactoryProvider;
public SpringBootNeo4jConfiguration(ObjectProvider<SessionFactoryProvider> sessionFactoryProvider) {
this.sessionFactoryProvider = sessionFactoryProvider;
}
@Override
public SessionFactory getSessionFactory() {
SessionFactoryProvider provider = this.sessionFactoryProvider.getObject();
return provider.getSessionFactory();
}
@Bean
@Scope(scopeName = "${spring.data.neo4j.session.scope:singleton}",
proxyMode = ScopedProxyMode.TARGET_CLASS)
@Override
public Session getSession() throws Exception {
return getSessionFactory().openSession();
}
}
@Configuration
@Import(Neo4jConfigurationConfiguration.class)
static class SessionFactoryProviderConfiguration implements BeanFactoryAware {
private final org.neo4j.ogm.config.Configuration configuration;
private ConfigurableListableBeanFactory beanFactory;
SessionFactoryProviderConfiguration(org.neo4j.ogm.config.Configuration configuration) {
this.configuration = configuration;
}
@Bean
@ConditionalOnMissingBean
public SessionFactoryProvider sessionFactoryProvider() {
SessionFactoryProvider provider = new SessionFactoryProvider();
provider.setConfiguration(this.configuration);
provider.setPackagesToScan(getPackagesToScan());
return provider;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory;
}
protected String[] getPackagesToScan() {
if (AutoConfigurationPackages.has(this.beanFactory)) {
List<String> basePackages = AutoConfigurationPackages.get(this.beanFactory);
return basePackages.toArray(new String[basePackages.size()]);
}
return new String[0];
}
}
@Configuration
static class Neo4jConfigurationConfiguration {
private final Neo4jProperties properties;
Neo4jConfigurationConfiguration(Neo4jProperties properties) {
this.properties = properties;
}
@Bean
@ConditionalOnMissingBean
public org.neo4j.ogm.config.Configuration configuration() {
return this.properties.createConfiguration();
}
}
}

View File

@ -0,0 +1,179 @@
/*
* Copyright 2012-2016 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
*
* http://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.neo4j;
import java.net.URI;
import java.net.URISyntaxException;
import org.neo4j.ogm.config.Configuration;
import org.springframework.beans.BeansException;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.ClassUtils;
/**
* Configuration properties for Neo4j.
*
* @author Stephane Nicoll
* @author Michael Hunger
* @author Vince Bickers
* @since 1.4.0
*/
@ConfigurationProperties(prefix = "spring.data.neo4j")
public class Neo4jProperties implements ApplicationContextAware {
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 DEFAULT_HTTP_URI = "http://localhost:7474";
/**
* URI used by the driver. Auto-detected by default.
*/
private String uri;
/**
* Login user of the server.
*/
private String username;
/**
* Login password of the server.
*/
private String password;
/**
* Compiler to use.
*/
private String compiler;
private final Embedded embedded = new Embedded();
private ClassLoader classLoader = Neo4jProperties.class.getClassLoader();
public String getUri() {
return this.uri;
}
public void setUri(String uri) {
this.uri = uri;
}
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public String getCompiler() {
return this.compiler;
}
public void setCompiler(String compiler) {
this.compiler = compiler;
}
public Embedded getEmbedded() {
return this.embedded;
}
@Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
this.classLoader = ctx.getClassLoader();
}
/**
* Create a {@link Configuration} based on the state of this instance.
* @return a configuration
*/
public Configuration createConfiguration() {
Configuration configuration = new Configuration();
if (this.uri == null) {
if (getEmbedded().isEnabled()
&& ClassUtils.isPresent(EMBEDDED_DRIVER, this.classLoader)) {
configuration.driverConfiguration().setDriverClassName(EMBEDDED_DRIVER);
}
else {
configuration.driverConfiguration().setDriverClassName(HTTP_DRIVER);
configuration.driverConfiguration().setURI(DEFAULT_HTTP_URI);
}
}
else {
configuration.driverConfiguration().setDriverClassName(deduceDriverFromUri());
configuration.driverConfiguration().setURI(this.uri);
}
if (this.username != null && this.password != null) {
configuration.driverConfiguration().setCredentials(this.username, this.password);
}
if (this.compiler != null) {
configuration.compilerConfiguration().setCompilerClassName(this.compiler);
}
return configuration;
}
private String deduceDriverFromUri() {
try {
URI uri = new URI(this.uri);
String scheme = uri.getScheme();
if (scheme == null || scheme.equals("file")) {
return EMBEDDED_DRIVER;
}
else if ("http".equals(scheme)) {
return HTTP_DRIVER;
}
else {
throw new IllegalArgumentException("Could not deduce driver to use based on URI '" + uri + "'");
}
}
catch (URISyntaxException ex) {
throw new IllegalArgumentException("Invalid URI for spring.data.neo4j.uri '" + this.uri + "'", ex);
}
}
public static class Embedded {
/**
* Enable embedded mode if the embedded driver is available.
*/
private boolean enabled = true;
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2012-2016 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
*
* http://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.
*/
/**
* Auto-configuration for Neo4j.
*/
package org.springframework.boot.autoconfigure.neo4j;

View File

@ -96,6 +96,12 @@
"description": "Enable Neo4j repositories.",
"defaultValue": true
},
{
"name": "spring.data.neo4j.session.scope",
"type": "java.lang.String",
"description": "Scope (lifetime) of the session.",
"defaultValue": "singleton"
},
{
"name": "spring.data.redis.repositories.enabled",
"type": "java.lang.Boolean",
@ -336,6 +342,36 @@
}
]
},
{
"name": "spring.data.neo4j.compiler",
"providers": [
{
"name": "class-reference",
"parameters": {
"target": "org.neo4j.ogm.compiler.Compiler"
}
}
]
},
{
"name": "spring.data.neo4j.session.scope",
"values": [
{
"value": "singleton"
},
{
"value": "session"
},
{
"value": "request"
}
],
"providers": [
{
"name": "any"
}
]
},
{
"name": "spring.datasource.driver-class-name",
"providers": [

View File

@ -31,7 +31,6 @@ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositor
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
@ -70,6 +69,7 @@ org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2016 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-2014 the original author or authors.
* Copyright 2012-2016 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,8 +19,6 @@ package org.springframework.boot.autoconfigure.data.neo4j;
import java.util.ArrayList;
import java.util.List;
import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Ignore;
import org.junit.Test;
@ -32,35 +30,34 @@ import org.springframework.boot.autoconfigure.data.jpa.city.CityRepository;
import org.springframework.boot.autoconfigure.data.neo4j.country.Country;
import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfigurationTests;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.orm.jpa.EntityScan;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration}.
* Tests for {@link Neo4jRepositoriesAutoConfiguration}.
*
* @author Dave Syer
* @author Oliver Gierke
* @author Michael Hunger
* @author Vince Bickers
* @author Stephane Nicoll
*/
public class MixedNeo4jRepositoriesAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
private AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext();
@After
public void close() {
@ -69,51 +66,46 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests {
@Test
public void testDefaultRepositoryConfiguration() throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context, "spring.datasource.initialize:false");
this.context.register(TestConfiguration.class, BaseConfiguration.class);
this.context.refresh();
Assertions.assertThat(this.context.getBean(CountryRepository.class)).isNotNull();
assertThat(this.context.getBean(CountryRepository.class)).isNotNull();
}
@Test
public void testMixedRepositoryConfiguration() throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context, "spring.datasource.initialize:false");
this.context.register(MixedConfiguration.class, BaseConfiguration.class);
this.context.refresh();
Assertions.assertThat(this.context.getBean(CountryRepository.class)).isNotNull();
Assertions.assertThat(this.context.getBean(CityRepository.class)).isNotNull();
assertThat(this.context.getBean(CountryRepository.class)).isNotNull();
assertThat(this.context.getBean(CityRepository.class)).isNotNull();
}
@Test
public void testJpaRepositoryConfigurationWithNeo4jTemplate() throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context, "spring.datasource.initialize:false");
this.context.register(JpaConfiguration.class, BaseConfiguration.class);
this.context.refresh();
Assertions.assertThat(this.context.getBean(CityRepository.class)).isNotNull();
assertThat(this.context.getBean(CityRepository.class)).isNotNull();
}
@Test
@Ignore
public void testJpaRepositoryConfigurationWithNeo4jOverlap() throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context, "spring.datasource.initialize:false");
this.context.register(OverlapConfiguration.class, BaseConfiguration.class);
this.context.refresh();
Assertions.assertThat(this.context.getBean(CityRepository.class)).isNotNull();
assertThat(this.context.getBean(CityRepository.class)).isNotNull();
}
@Test
public void testJpaRepositoryConfigurationWithNeo4jOverlapDisabled() throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.initialize:false",
"spring.data.neo4j.repositories.enabled:false");
this.context.register(OverlapConfiguration.class, BaseConfiguration.class);
this.context.refresh();
Assertions.assertThat(this.context.getBean(CityRepository.class)).isNotNull();
assertThat(this.context.getBean(CityRepository.class)).isNotNull();
}
@Configuration
@ -141,7 +133,7 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests {
}
// In this one the Jpa repositories and the autoconfiguration packages overlap, so
// In this one the Jpa repositories and the auto-configuration packages overlap, so
// Neo4j will try and configure the same repositories
@Configuration
@TestAutoConfigurationPackage(CityRepository.class)
@ -161,11 +153,11 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
List<String> names = new ArrayList<String>();
for (Class<?> type : new Class<?>[] { DataSourceAutoConfiguration.class,
for (Class<?> type : new Class<?>[] {DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class,
Neo4jAutoConfiguration.class,
Neo4jRepositoriesAutoConfiguration.class }) {
Neo4jRepositoriesAutoConfiguration.class}) {
names.add(type.getName());
}
return names.toArray(new String[names.size()]);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 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.
@ -14,27 +14,19 @@
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.neo4j;
package org.springframework.boot.autoconfigure.data.neo4j;
import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.autoconfigure.data.neo4j.city.City;
import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.template.Neo4jOperations;
/**
* Tests for {@link Neo4jAutoConfiguration}.
@ -48,34 +40,15 @@ public class Neo4jDataAutoConfigurationTests {
@Rule
public final ExpectedException thrown = ExpectedException.none();
private AnnotationConfigApplicationContext context;
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void templateExists() {
this.context = new AnnotationConfigApplicationContext();
this.context.register(PropertyPlaceholderAutoConfiguration.class, Neo4jAutoConfiguration.class);
this.context.refresh();
Assertions.assertThat(this.context.getBeanNamesForType(Neo4jOperations.class).length).isEqualTo(1);
}
@Test
public void sessionFactoryExists() {
this.context = new AnnotationConfigApplicationContext();
this.context.register(PropertyPlaceholderAutoConfiguration.class, Neo4jAutoConfiguration.class);
this.context.refresh();
Assertions.assertThat(this.context.getBeanNamesForType(SessionFactory.class).length).isEqualTo(1);
this.context.close();
}
@Test
public void usesAutoConfigurationPackageToPickUpDomainTypes() {
this.context = new AnnotationConfigApplicationContext();
String cityPackage = City.class.getPackage().getName();
AutoConfigurationPackages.register(this.context, cityPackage);
this.context.register(Neo4jAutoConfiguration.class);
@ -85,7 +58,7 @@ public class Neo4jDataAutoConfigurationTests {
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({"unchecked", "rawtypes"})
private static void assertDomainTypesDiscovered(Neo4jMappingContext mappingContext,
Class<?>... types) {
for (Class<?> type : types) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2014 the original author or authors.
* Copyright 2012-2016 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,35 +16,34 @@
package org.springframework.boot.autoconfigure.data.neo4j;
import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Test;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage;
import org.springframework.boot.autoconfigure.data.alt.neo4j.CityNeo4jRepository;
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.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
import org.springframework.data.neo4j.repository.config.EnableNeo4jRepositories;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration}.
* Tests for {@link Neo4jRepositoriesAutoConfiguration}.
*
* @author Dave Syer
* @author Oliver Gierke
* @author Michael Hunger
* @author Vince Bickers
* @author Stephane Nicoll
*/
public class Neo4jRepositoriesAutoConfigurationTests {
@ -57,27 +56,26 @@ public class Neo4jRepositoriesAutoConfigurationTests {
@Test
public void testDefaultRepositoryConfiguration() throws Exception {
prepareApplicationContext(TestConfiguration.class);
Assertions.assertThat(this.context.getBean(CityRepository.class)).isNotNull();
assertThat(this.context.getBean(CityRepository.class)).isNotNull();
Neo4jMappingContext mappingContext = this.context.getBean(Neo4jMappingContext.class);
Assertions.assertThat(mappingContext.getPersistentEntity(City.class)).isNotNull();
assertThat(mappingContext.getPersistentEntity(City.class)).isNotNull();
}
@Test
public void testNoRepositoryConfiguration() throws Exception {
prepareApplicationContext(EmptyConfiguration.class);
Assertions.assertThat(this.context.getBean(SessionFactory.class)).isNotNull();
assertThat(this.context.getBean(SessionFactory.class)).isNotNull();
}
@Test
public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() {
prepareApplicationContext(CustomizedConfiguration.class);
Assertions.assertThat(this.context.getBean(CityNeo4jRepository.class)).isNotNull();
assertThat(this.context.getBean(CityNeo4jRepository.class)).isNotNull();
}
@Test(expected = NoSuchBeanDefinitionException.class)
@ -89,6 +87,8 @@ public class Neo4jRepositoriesAutoConfigurationTests {
private void prepareApplicationContext(Class<?>... configurationClasses) {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context,
"spring.data.neo4j.uri=http://localhost:9797");
this.context.register(configurationClasses);
this.context.register(Neo4jAutoConfiguration.class,
Neo4jRepositoriesAutoConfiguration.class,
@ -122,4 +122,5 @@ public class Neo4jRepositoriesAutoConfigurationTests {
protected static class SortOfInvalidCustomConfiguration {
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-2016 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.
@ -67,4 +67,5 @@ public class City implements Serializable {
public String toString() {
return getName() + "," + getState() + "," + getCountry();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-2016 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.
@ -24,11 +24,4 @@ public interface CityRepository extends GraphRepository<City> {
Page<City> findAll(Pageable pageable);
// TODO: cannot resolve queries like this at the moment.
//
// Page<City> findByNameLikeAndCountryLikeAllIgnoringCase(String name, String country,
// Pageable pageable);
//
// City findByNameAndCountry(String name, String country);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-2016 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.
@ -46,4 +46,5 @@ public class Country implements Serializable {
public String toString() {
return getName();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2013 the original author or authors.
* Copyright 2012-2016 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-2014 the original author or authors.
* Copyright 2012-2016 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,21 +16,27 @@
package org.springframework.boot.autoconfigure.neo4j;
import org.assertj.core.api.Assertions;
import org.junit.After;
import org.junit.Test;
import org.neo4j.ogm.config.Configuration;
import org.neo4j.ogm.drivers.http.driver.HttpDriver;
import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jAutoConfiguration;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.template.Neo4jOperations;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
/**
* Tests for {@link Neo4jAutoConfiguration}.
* Tests for {@link Neo4jAutoConfiguration}. Tests can't use the embedded driver
* as we use lucene 4 and Neo4j still requires 3.
*
* @author Dave Syer
* @author Stephane Nicoll
* @author Michael Hunger
* @author Vince Bickers
*/
@ -46,10 +52,74 @@ public class Neo4jAutoConfigurationTests {
}
@Test
public void configurationExists() {
this.context = new AnnotationConfigApplicationContext(
PropertyPlaceholderAutoConfiguration.class, Neo4jAutoConfiguration.class);
Assertions.assertThat(this.context.getBeanNamesForType(Configuration.class).length).isEqualTo(1);
public void defaultConfiguration() {
load(null, "spring.data.neo4j.uri=http://localhost:8989");
assertThat(this.context.getBeansOfType(Neo4jOperations.class)).hasSize(1);
assertThat(this.context.getBeansOfType(org.neo4j.ogm.config.Configuration.class)).hasSize(1);
assertThat(this.context.getBeansOfType(SessionFactory.class)).hasSize(1);
assertThat(this.context.getBeanDefinition("scopedTarget.getSession").getScope()).isEqualTo("singleton");
}
@Test
public void customScope() {
load(null, "spring.data.neo4j.uri=http://localhost:8989",
"spring.data.neo4j.session.scope=prototype");
assertThat(this.context.getBeanDefinition("scopedTarget.getSession").getScope()).isEqualTo("prototype");
}
@Test
public void customNeo4jOperations() {
load(CustomNeo4jOperations.class);
assertThat(this.context.getBean(Neo4jOperations.class))
.isSameAs(this.context.getBean("myNeo4jOperations"));
assertThat(this.context.getBeansOfType(org.neo4j.ogm.config.Configuration.class)).hasSize(0);
assertThat(this.context.getBeansOfType(SessionFactory.class)).hasSize(0);
assertThat(this.context.getBeansOfType(Session.class)).hasSize(0);
}
@Test
public void customConfiguration() {
load(CustomConfiguration.class);
assertThat(this.context.getBean(org.neo4j.ogm.config.Configuration.class))
.isSameAs(this.context.getBean("myConfiguration"));
assertThat(this.context.getBeansOfType(Neo4jOperations.class)).hasSize(1);
assertThat(this.context.getBeansOfType(org.neo4j.ogm.config.Configuration.class)).hasSize(1);
assertThat(this.context.getBeansOfType(SessionFactory.class)).hasSize(1);
}
public void load(Class<?> config, String... environment) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(ctx, environment);
if (config != null) {
ctx.register(config);
}
ctx.register(PropertyPlaceholderAutoConfiguration.class,
Neo4jAutoConfiguration.class);
ctx.refresh();
this.context = ctx;
}
@Configuration
static class CustomNeo4jOperations {
@Bean
public Neo4jOperations myNeo4jOperations() {
return mock(Neo4jOperations.class);
}
}
@Configuration
static class CustomConfiguration {
@Bean
public org.neo4j.ogm.config.Configuration myConfiguration() {
org.neo4j.ogm.config.Configuration configuration = new org.neo4j.ogm.config.Configuration();
configuration.driverConfiguration().setDriverClassName(HttpDriver.class.getName());
return configuration;
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 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,69 +16,171 @@
package org.springframework.boot.autoconfigure.neo4j;
import org.assertj.core.api.Assertions;
import java.net.URL;
import java.net.URLClassLoader;
import com.hazelcast.util.Base64;
import org.junit.After;
import org.junit.Test;
import org.neo4j.ogm.authentication.Credentials;
import org.neo4j.ogm.config.Configuration;
import org.neo4j.ogm.config.DriverConfiguration;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link Neo4jProperties}.
*
* @author Phillip Webb
* @author Andy Wilkinson
* @author Vince Bickers
* @author Stephane Nicoll
*/
public class Neo4jPropertiesTests {
@Test
public void shouldHaveCorrectDefaultDriver() {
private AnnotationConfigApplicationContext context;
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(Conf.class);
context.refresh();
Neo4jProperties neo4jProperties = context.getBean(Neo4jProperties.class);
Assertions.assertThat(neo4jProperties.getDriver()).isEqualTo("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver");
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void shouldConfigureFromDefaults() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(Conf.class);
context.refresh();
Neo4jProperties neo4jProperties = context.getBean(Neo4jProperties.class);
org.neo4j.ogm.config.Configuration configuration = neo4jProperties.configure();
Assertions.assertThat(configuration.driverConfiguration().getDriverClassName())
.isEqualTo("org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver");
public void defaultUseEmbeddedInMemoryIfAvailable() {
Neo4jProperties properties = load(true);
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.EMBEDDED_DRIVER, null);
}
@Test
public void shouldBeCustomisable() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(context, "spring.data.neo4j.driver:CustomDriver");
context.register(Conf.class);
context.refresh();
Neo4jProperties neo4jProperties = context.getBean(Neo4jProperties.class);
Assertions.assertThat(neo4jProperties.getDriver()).isEqualTo("CustomDriver");
public void defaultUseHttpDriverIfEmbeddedDriverIsNotAvailable() {
Neo4jProperties properties = load(false);
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.HTTP_DRIVER,
Neo4jProperties.DEFAULT_HTTP_URI);
}
@Configuration
@Test
public void httpUriUseHttpServer() {
Neo4jProperties properties = load(true,
"spring.data.neo4j.uri=http://localhost:7474");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.HTTP_DRIVER,
"http://localhost:7474");
}
@Test
public void fileUriUseEmbeddedServer() {
Neo4jProperties properties = load(true,
"spring.data.neo4j.uri=file://var/tmp/graph.db");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.EMBEDDED_DRIVER,
"file://var/tmp/graph.db");
}
@Test
public void credentialsAreSet() {
Neo4jProperties properties = load(true,
"spring.data.neo4j.uri=http://localhost:7474",
"spring.data.neo4j.username=user",
"spring.data.neo4j.password=secret");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.HTTP_DRIVER,
"http://localhost:7474");
assertCredentials(configuration, "user", "secret");
}
@Test
public void credentialsAreSetFromUri() {
Neo4jProperties properties = load(true,
"spring.data.neo4j.uri=http://user:secret@my-server:7474");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.HTTP_DRIVER,
"http://user:secret@my-server:7474");
assertCredentials(configuration, "user", "secret");
}
@Test
public void embeddedModeDisabledUseHttpUri() {
Neo4jProperties properties = load(true,
"spring.data.neo4j.embedded.enabled=false");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.HTTP_DRIVER,
Neo4jProperties.DEFAULT_HTTP_URI);
}
@Test
public void embeddedModeWithRelativeLocation() {
Neo4jProperties properties = load(true,
"spring.data.neo4j.uri=target/neo4j/my.db");
Configuration configuration = properties.createConfiguration();
assertDriver(configuration, Neo4jProperties.EMBEDDED_DRIVER,
"target/neo4j/my.db");
}
private static void assertDriver(Configuration actual, String driver,
String uri) {
assertThat(actual).isNotNull();
DriverConfiguration driverConfig = actual.driverConfiguration();
assertThat(driverConfig.getDriverClassName()).isEqualTo(driver);
assertThat(driverConfig.getURI()).isEqualTo(uri);
}
private static void assertCredentials(Configuration actual, String username, String password) {
Credentials credentials = actual.driverConfiguration().getCredentials();
if (username == null & password == null) {
assertThat(credentials).isNull();
}
else {
assertThat(credentials).isNotNull();
Object content = credentials.credentials();
assertThat(content).isInstanceOf(String.class);
String[] auth = new String(Base64.decode(((String) content)
.getBytes())).split(":");
assertThat(auth[0]).isEqualTo(username);
assertThat(auth[1]).isEqualTo(password);
assertThat(auth).hasSize(2);
}
}
public Neo4jProperties load(final boolean embeddedAvailable, String... environment) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.setClassLoader(
new URLClassLoader(new URL[0], getClass().getClassLoader()) {
@Override
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException {
if (name.equals(Neo4jProperties.EMBEDDED_DRIVER)) {
if (embeddedAvailable) {
return TestEmbeddedDriver.class;
}
else {
throw new ClassNotFoundException();
}
}
return super.loadClass(name, resolve);
}
});
EnvironmentTestUtils.addEnvironment(ctx, environment);
ctx.register(TestConfiguration.class);
ctx.refresh();
this.context = ctx;
return this.context.getBean(Neo4jProperties.class);
}
@org.springframework.context.annotation.Configuration
@EnableConfigurationProperties(Neo4jProperties.class)
static class Conf {
static class TestConfiguration {
}
private static class TestEmbeddedDriver {
}
}

View File

@ -59,7 +59,6 @@
<commons-dbcp.version>1.4</commons-dbcp.version>
<commons-dbcp2.version>2.1.1</commons-dbcp2.version>
<commons-digester.version>2.1</commons-digester.version>
<commons-lang3.version>3.4</commons-lang3.version>
<commons-pool.version>1.6</commons-pool.version>
<commons-pool2.version>2.4.2</commons-pool2.version>
<couchbase-client.version>2.2.3</couchbase-client.version>
@ -124,6 +123,7 @@
<mongodb.version>2.14.1</mongodb.version>
<mysql.version>5.1.38</mysql.version>
<nekohtml.version>1.9.22</nekohtml.version>
<neo4j-ogm.version>2.0.0-M04</neo4j-ogm.version>
<postgresql.version>9.4.1208.jre7</postgresql.version>
<reactor.version>2.0.7.RELEASE</reactor.version>
<reactor-spring.version>2.0.7.RELEASE</reactor-spring.version>
@ -785,7 +785,6 @@
<artifactId>commons-dbcp</artifactId>
<version>${commons-dbcp.version}</version>
</dependency>
<dependency>
<groupId>commons-digester</groupId>
<artifactId>commons-digester</artifactId>
@ -1773,6 +1772,26 @@
<artifactId>mongo-java-driver</artifactId>
<version>${mongodb.version}</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-api</artifactId>
<version>${neo4j-ogm.version}</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-compiler</artifactId>
<version>${neo4j-ogm.version}</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-core</artifactId>
<version>${neo4j-ogm.version}</version>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-http-driver</artifactId>
<version>${neo4j-ogm.version}</version>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
@ -2162,7 +2181,6 @@
<artifactId>wsdl4j</artifactId>
<version>${wsdl4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
<build>

View File

@ -536,6 +536,15 @@ content into your application; rather pick only the properties that you need.
# DATA REDIS
spring.data.redis.repositories.enabled=true # Enable Redis repositories.
# NEO4J ({sc-spring-boot-autoconfigure}/neo4j/Neo4jProperties.{sc-ext}[Neo4jProperties])
spring.data.neo4j.compiler= # Compiler to use.
spring.data.neo4j.embedded.enabled=true # Enable embedded mode if the embedded driver is available.
spring.data.neo4j.password= # Login password of the server.
spring.data.neo4j.repositories.enabled=true # Enable Neo4j repositories.
spring.data.neo4j.session.scope=singleton # Scope (lifetime) of the session.
spring.data.neo4j.uri= # URI used by the driver. Auto-detected by default.
spring.data.neo4j.username= # Login user of the server.
# DATA REST ({sc-spring-boot-autoconfigure}/data/rest/RepositoryRestProperties.{sc-ext}[RepositoryRestProperties])
spring.data.rest.base-path= # Base path to be used by Spring Data REST to expose repository resources.
spring.data.rest.default-page-size= # Default size of pages.

View File

@ -2805,9 +2805,9 @@ http://projects.spring.io/spring-data-redis/[Redis],
http://projects.spring.io/spring-data-gemfire/[Gemfire],
http://projects.spring.io/spring-data-couchbase/[Couchbase] and
http://projects.spring.io/spring-data-cassandra/[Cassandra].
Spring Boot provides auto-configuration for Redis, MongoDB, Elasticsearch, Solr and
Cassandra; you can make use of the other projects, but you will need to configure them
yourself. Refer to the appropriate reference documentation at
Spring Boot provides auto-configuration for Redis, MongoDB, Neo4j, Elasticsearch, Solr
and Cassandra; you can make use of the other projects, but you will need to configure
them yourself. Refer to the appropriate reference documentation at
http://projects.spring.io/spring-data[projects.spring.io/spring-data].
@ -3011,121 +3011,21 @@ Mongo instance's configuration and logging routing.
[[boot-features-neo4j]]
=== Neo4j
http://neo4j.com/[Neo4j] is an open-source NoSQL graph database that uses a
rich data model of nodes related by first class relationships which is better
suited for connected big data than traditional rdbms approaches.
Spring Boot offers several conveniences for working with Neo4j, including the
`spring-boot-starter-data-neo4j` '`Starter POM`'.
http://neo4j.com/[Neo4j] is an open-source NoSQL graph database that uses a rich data
model of nodes related by first class relationships which is better suited for connected
big data than traditional rdbms approaches. Spring Boot offers several conveniences for
working with Neo4j, including the `spring-boot-starter-data-neo4j` '`Starter POM`'.
[[boot-features-connecting-to-neo4j]]
==== Connecting to a Neo4j database
You can inject an auto-configured `org.neo4j.ogm.session.Neo4jSession` to
access Neo4j databases.
In your `application properties`, you can supply any domain packages to be scanned by the OGM at startup
as well as the lifetime of the OGM session that will be established for web clients.
By default your application will be configured to use an in-process embedded instance of Neo4j that will not persist any data when your application shuts down. You can also connect to a remote Neo4j server, or to an embedded instance that persists data between restarts of your application.
The following sections show how you can configure your application for each of these scenarios.
[[boot-features-neo4j-embedded]]
==== Connecting to an embedded database
[source,properties,indent=0]
----
# embedded driver (optional: default is embedded driver)
spring.data.neo4j.driver=org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver
# database path (optional: default is in-memory)
spring.data.neo4j.URI=file://var/tmp/graph.db
# declare the domain packages for the OGM to scan at startup
# note: if you don't need to do any object mapping, you can omit this property
spring.data.neo4.domain.packages=my.app.domain.core, my.app.domain.external, ...
# OGM session lifetime for web clients
# options: session (httpSession), request (httpRequest)
# default: session
spring.data.neo4j.session.lifetime=session
----
[[boot-features-neo4j-remote]]
==== Connecting to a remote database
[source,properties,indent=0]
----
# http driver
spring.data.neo4j.driver=org.neo4j.ogm.drivers.http.driver.HttpDriver
# database uri
spring.data.neo4j.URI=http://user:password@localhost:7474
# declare the domain packages for the OGM to scan at startup
# note: if you don't need to do any object mapping, you can omit this property
spring.data.neo4.domain.packages=my.app.domain.core, my.app.domain.external, ...
# OGM session lifetime for web clients
# options: session (httpSession), request (httpRequest)
# default: session
spring.data.neo4j.session.lifetime=session
----
[[boot-features-spring-data-neo4j-application]]
==== Application
[source,java,indent=0]]
----
@SpringBootApplication
@Import(Neo4jAutoConfiguration.class)
public class Application {
public static void main(String[] args) {
new SpringApplication(Application.class).run(args);
}
}
----
[[boot-features-neo4j-ogm-session]]
==== Neo4jSession
[source,java,indent=0]
----
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.neo4j.ogm.session.Neo4jSession;
@Component
public class MyBean {
private final Session session;
@Autowired
public MyBean(Session session) {
this.session = session;
}
// ...
public void example() {
Iterable result = session.query("MATCH (c:Customer) RETURN count(*)",null);
// ...
}
}
----
[[boot-features-spring-data-neo4j-template]]
==== Neo4jTemplate
Spring Data Neo4j provides a
{spring-data-neo4j-javadoc}/core/Neo4jTemplate.html[`Neo4jTemplate`] class that is very
similar in its design to Spring's `JdbcTemplate`. As with `JdbcTemplate` Spring Boot
auto-configures a bean for you to simply inject:
You can inject an auto-configured `Neo4jSession`, `Session` or `Neo4jOperations` instance
as you would any other Spring Bean. By default the instance will attempt to connect to a
Neo4j server using `localhost:7474`:
[source,java,indent=0]
----
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.data.neo4j.template.Neo4jTemplate;
@Component
public class MyBean {
@ -3141,7 +3041,47 @@ auto-configures a bean for you to simply inject:
}
----
See the `Neo4jOperations` Javadoc for complete details.
You can take full control of the configuration by adding a
`org.neo4j.ogm.config.Configuration` `@Bean` of your own. Also, adding a `@Bean` of type
`Neo4jOperations` disables the auto-configuration.
You can configure the user and credentials to use via the `spring.data.couchbase.*`
properties:
[source,properties,indent=0]
----
spring.data.neo4j.uri=http://my-server:7474
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=secret
----
[[boot-features-connecting-to-neo4j-embedded]]
==== Using the embedded mode
NOTE: Neo4j's embedded mode is subject to a different licensing, make sure to review it
before integrating the dependency in your application.
If you add `org.neo4j:neo4j-ogm-embedded-driver` to the dependencies of your application,
Spring Boot will automatically configure an in-process embedded instance of Neo4j that
will not persist any data when your application shuts down. You can explicitly disable
that mode using `spring.data.neo4j.embedded.enabled=false`. You can also enable
persistence for the embedded mode:
----
spring.data.neo4j.uri=file://var/tmp/graph.db
----
[[boot-features-neo4j-ogm-session]]
==== Neo4jSession
By default, the lifetime of the session is scope to the application. If you are running a
web application you can change it to scope or request easily:
----
spring.data.neo4j.session.scope=session
----
[[boot-features-spring-data-neo4j-repositories]]
==== Spring Data Neo4j repositories
@ -3151,8 +3091,10 @@ In fact, both Spring Data JPA and Spring Data Neo4j share the same common
infrastructure; so you could take the JPA example from earlier and, assuming that `City`
is now a Neo4j OGM `@NodeEntity` rather than a JPA `@Entity`, it will work in the same way.
To enable repository support (and optionally support for `@Transactional`), add the following two annotations to
your Spring configuration:
TIP: You can customize entity scanning locations using the `@NodeEntityScan` annotation.
To enable repository support (and optionally support for `@Transactional`), add the following
two annotations to your Spring configuration:
[source,java,indent=0]
----
@ -3182,6 +3124,7 @@ technologies, refer to their http://projects.spring.io/spring-data-neo4j/[refere
documentation].
[[boot-features-gemfire]]
=== Gemfire
https://github.com/spring-projects/spring-data-gemfire[Spring Data Gemfire] provides

View File

@ -38,6 +38,7 @@
<module>spring-boot-sample-data-gemfire</module>
<module>spring-boot-sample-data-jpa</module>
<module>spring-boot-sample-data-mongodb</module>
<module>spring-boot-sample-data-neo4j</module>
<module>spring-boot-sample-data-redis</module>
<module>spring-boot-sample-data-rest</module>
<module>spring-boot-sample-data-solr</module>

View File

@ -0,0 +1,23 @@
= Spring Boot Neo4j Sample
This sample demonstrates the integration of Neo4j with a simple entity. It
expects a Neo4j instance running on `localhost`. If your neo4j instance
requires authentication, update `application.properties` with your credentials:
```
spring.data.neo4j.username=neo4j
spring.data.neo4j.password=secret
```
You can also locally add the embedded driver to embed Neo4j instead. Note
that Spring Boot does not provide dependency management for that GPL-licensed
library:
```
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-embedded-driver</artifactId>
<version>${neo4j-ogm.version}</version>
</dependency>
```

View File

@ -19,12 +19,6 @@
<main.basedir>${basedir}/../..</main.basedir>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-neo4j</artifactId>
@ -35,14 +29,6 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-embedded-driver</artifactId>
<version>2.0.0-M04</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>

View File

@ -22,8 +22,6 @@ import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
@SpringBootApplication
public class SampleNeo4jApplication implements CommandLineRunner {

View File

@ -1,3 +0,0 @@
spring.data.neo4j.driver=org.neo4j.ogm.drivers.embedded.driver.EmbeddedDriver
spring.data.neo4j.domain.packages=sample.data.neo4j
spring.data.neo4j.session.lifetime=prototype

View File

@ -16,35 +16,46 @@
package sample.data.neo4j;
import org.junit.ClassRule;
import java.net.ConnectException;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.IntegrationTest;
import org.springframework.boot.test.OutputCapture;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.boot.test.rule.OutputCapture;
import static org.junit.Assert.assertTrue;
/**
* Tests for {@link SampleNeo4jApplication}.
*
* @author Dave Syer
* @author Andy Wilkinson
* @author Stephane Nicoll
*/
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(SampleNeo4jApplication.class)
@IntegrationTest
public class SampleNeo4jApplicationTests {
@ClassRule
public static OutputCapture outputCapture = new OutputCapture();
@Rule
public OutputCapture outputCapture = new OutputCapture();
@Test
public void testDefaultSettings() throws Exception {
String output = SampleNeo4jApplicationTests.outputCapture.toString();
try {
SampleNeo4jApplication.main(new String[0]);
}
catch (Exception ex) {
if (!neo4jServerRunning(ex)) {
return;
}
}
String output = this.outputCapture.toString();
assertTrue("Wrong output: " + output,
output.contains("firstName='Alice', lastName='Smith'"));
}
private boolean neo4jServerRunning(Throwable ex) {
System.out.println(ex.getMessage());
if (ex instanceof ConnectException) {
return false;
}
return (ex.getCause() == null || neo4jServerRunning(ex.getCause()));
}
}

View File

@ -189,6 +189,11 @@
<artifactId>liquibase-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-ogm-core</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>

View File

@ -0,0 +1,59 @@
/*
* Copyright 2012-2016 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
*
* http://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.context.scan;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.Ordered;
/**
* A base {@link BeanPostProcessor} implementation that holds the packages to
* use for a given component. An implementation must implement
* {@link #postProcessBeforeInitialization(Object, String)} and update the
* component responsible to manage the packages to scan.
*
* @author Stephane Nicoll
* @since 1.4.0
*/
public abstract class AbstractEntityScanBeanPostProcessor implements BeanPostProcessor, Ordered {
private final String[] packagesToScan;
protected AbstractEntityScanBeanPostProcessor(String[] packagesToScan) {
this.packagesToScan = packagesToScan;
}
/**
* Return the packages to use.
* @return the packages to use.
*/
protected String[] getPackagesToScan() {
return this.packagesToScan;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
@Override
public int getOrder() {
return 0;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2012-2015 the original author or authors.
* Copyright 2012-2016 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.
@ -14,44 +14,69 @@
* limitations under the License.
*/
package org.springframework.boot.orm.jpa;
package org.springframework.boot.context.scan;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Set;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.config.ConstructorArgumentValues;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ObjectUtils;
/**
* {@link ImportBeanDefinitionRegistrar} used by {@link EntityScan}.
* A base {@link ImportBeanDefinitionRegistrar} used to collect the packages to
* scan for a given component.
* <p>
* Expect to process an annotation type that defines a {@code basePackage} and
* {@code basePackageClasses} attributes as well as a {@code value} alias of
* {@code basePackage}.
* <p>
* The {@link ImportBeanDefinitionRegistrar} registers a single
* {@link AbstractEntityScanBeanPostProcessor} implementation with the packages
* to use.
*
* @author Phillip Webb
* @author Oliver Gierke
* @author Stephane Nicoll
* @since 1.4.0
* @see AbstractEntityScanBeanPostProcessor
*/
class EntityScanRegistrar implements ImportBeanDefinitionRegistrar {
public abstract class AbstractEntityScanRegistrar implements ImportBeanDefinitionRegistrar {
private final Class<? extends Annotation> annotationType;
private final String beanPostProcessorName;
private final Class<? extends AbstractEntityScanBeanPostProcessor> beanPostProcessorType;
/**
* Create an instance.
* @param annotationType the annotation to inspect
* @param beanPostProcessorName the name of the bean post processor
* @param beanPostProcessorType the type of the bean post processor implementation
*/
protected AbstractEntityScanRegistrar(Class<? extends Annotation> annotationType,
String beanPostProcessorName,
Class<? extends AbstractEntityScanBeanPostProcessor> beanPostProcessorType) {
this.beanPostProcessorName = beanPostProcessorName;
this.annotationType = annotationType;
this.beanPostProcessorType = beanPostProcessorType;
}
private static final String BEAN_NAME = "entityScanBeanPostProcessor";
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
if (!registry.containsBeanDefinition(BEAN_NAME)) {
if (!registry.containsBeanDefinition(this.beanPostProcessorName)) {
addEntityScanBeanPostProcessor(registry, packagesToScan);
}
else {
@ -59,15 +84,16 @@ class EntityScanRegistrar implements ImportBeanDefinitionRegistrar {
}
}
private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
protected Set<String> getPackagesToScan(AnnotationMetadata metadata) {
AnnotationAttributes attributes = AnnotationAttributes
.fromMap(metadata.getAnnotationAttributes(EntityScan.class.getName()));
.fromMap(metadata.getAnnotationAttributes(this.annotationType.getName()));
String[] value = attributes.getStringArray("value");
String[] basePackages = attributes.getStringArray("basePackages");
Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
if (!ObjectUtils.isEmpty(value)) {
Assert.state(ObjectUtils.isEmpty(basePackages),
"@EntityScan basePackages and value attributes are mutually exclusive");
Assert.state(ObjectUtils.isEmpty(basePackages), String.format(
"@%s basePackages and value attributes are mutually exclusive",
this.annotationType.getSimpleName()));
}
Set<String> packagesToScan = new LinkedHashSet<String>();
packagesToScan.addAll(Arrays.asList(value));
@ -85,20 +111,20 @@ class EntityScanRegistrar implements ImportBeanDefinitionRegistrar {
private void addEntityScanBeanPostProcessor(BeanDefinitionRegistry registry,
Set<String> packagesToScan) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(EntityScanBeanPostProcessor.class);
beanDefinition.setBeanClass(this.beanPostProcessorType);
beanDefinition.getConstructorArgumentValues()
.addGenericArgumentValue(toArray(packagesToScan));
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// We don't need this one to be post processed otherwise it can cause a
// cascade of bean instantiation that we would rather avoid.
beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
registry.registerBeanDefinition(this.beanPostProcessorName, beanDefinition);
}
private void updateEntityScanBeanPostProcessor(BeanDefinitionRegistry registry,
Set<String> packagesToScan) {
BeanDefinition definition = registry.getBeanDefinition(BEAN_NAME);
ValueHolder constructorArguments = definition.getConstructorArgumentValues()
BeanDefinition definition = registry.getBeanDefinition(this.beanPostProcessorName);
ConstructorArgumentValues.ValueHolder constructorArguments = definition.getConstructorArgumentValues()
.getGenericArgumentValue(String[].class);
Set<String> mergedPackages = new LinkedHashSet<String>();
mergedPackages.addAll(Arrays.asList((String[]) constructorArguments.getValue()));
@ -110,52 +136,4 @@ class EntityScanRegistrar implements ImportBeanDefinitionRegistrar {
return set.toArray(new String[set.size()]);
}
/**
* {@link BeanPostProcessor} to set
* {@link LocalContainerEntityManagerFactoryBean#setPackagesToScan(String...)} based
* on an {@link EntityScan} annotation.
*/
static class EntityScanBeanPostProcessor
implements BeanPostProcessor, SmartInitializingSingleton, Ordered {
private final String[] packagesToScan;
private boolean processed;
EntityScanBeanPostProcessor(String[] packagesToScan) {
this.packagesToScan = packagesToScan;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof LocalContainerEntityManagerFactoryBean) {
LocalContainerEntityManagerFactoryBean factoryBean = (LocalContainerEntityManagerFactoryBean) bean;
factoryBean.setPackagesToScan(this.packagesToScan);
this.processed = true;
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
@Override
public void afterSingletonsInstantiated() {
Assert.state(this.processed,
"Unable to configure "
+ "LocalContainerEntityManagerFactoryBean from @EntityScan, "
+ "ensure an appropriate bean is registered.");
}
@Override
public int getOrder() {
return 0;
}
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2012-2016 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
*
* http://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.
*/
/**
* Support for component scanning.
*/
package org.springframework.boot.context.scan;

View File

@ -0,0 +1,83 @@
/*
* Copyright 2012-2016 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
*
* http://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.neo4j;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.context.annotation.Import;
/**
* Configures the {@link SessionFactory} to scan for node entity
* classes in the classpath. This annotation provides an alternative to manually setting
* {@link SessionFactoryProvider#setPackagesToScan(String...)} and is
* particularly useful if you want to configure entity scanning in a type-safe way, or if
* your {@link SessionFactory} is auto-configured.
* <p>
* A {@link SessionFactoryProvider} must be configured within your Spring
* ApplicationContext in order to use entity scanning. Furthermore, any existing
* {@code packagesToScan} setting will be replaced.
* <p>
* One of {@link #basePackageClasses()}, {@link #basePackages()} or its alias
* {@link #value()} may be specified to define specific packages to scan. If specific
* packages are not defined scanning will occur from the package of the class with this
* annotation.
*
* @author Phillip Webb
* @author Stephane Nicoll
* @since 1.4.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(NodeEntityScanRegistrar.class)
public @interface NodeEntityScan {
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
* declarations e.g.: {@code @NodeEntityScan("org.my.pkg")} instead of
* {@code @NodeEntityScan(basePackages="org.my.pkg")}.
* @return the base packages to scan
*/
String[] value() default {};
/**
* Base packages to scan for node entities. {@link #value()} is an alias for (and
* mutually exclusive with) this attribute.
* <p>
* Use {@link #basePackageClasses()} for a type-safe alternative to String-based
* package names.
* @return the base packages to scan
*/
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages to
* scan for node entities. The package of each class specified will be scanned.
* <p>
* Consider creating a special no-op marker class or interface in each package that
* serves no purpose other than being referenced by this attribute.
* @return classes from the base packages to scan
*/
Class<?>[] basePackageClasses() default {};
}

View File

@ -0,0 +1,73 @@
/*
* Copyright 2012-2016 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
*
* http://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.neo4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.context.scan.AbstractEntityScanBeanPostProcessor;
import org.springframework.boot.context.scan.AbstractEntityScanRegistrar;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.util.Assert;
/**
* {@link ImportBeanDefinitionRegistrar} used by {@link NodeEntityScan}.
*
* @author Stephane Nicoll
*/
class NodeEntityScanRegistrar extends AbstractEntityScanRegistrar {
NodeEntityScanRegistrar() {
super(NodeEntityScan.class, "nodeEntityScanBeanPostProcessor", NodeEntityScanBeanPostProcessor.class);
}
/**
* {@link BeanPostProcessor} to set
* {@link SessionFactoryProvider#setPackagesToScan(String...)} based
* on an {@link NodeEntityScan} annotation.
*/
static class NodeEntityScanBeanPostProcessor extends AbstractEntityScanBeanPostProcessor
implements SmartInitializingSingleton {
private boolean processed;
NodeEntityScanBeanPostProcessor(String[] packagesToScan) {
super(packagesToScan);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof SessionFactoryProvider) {
SessionFactoryProvider provider = (SessionFactoryProvider) bean;
provider.setPackagesToScan(getPackagesToScan());
this.processed = true;
}
return bean;
}
@Override
public void afterSingletonsInstantiated() {
Assert.state(this.processed,
"Unable to configure "
+ "SessionFactoryFactoryBean from @NodeEntityScan, "
+ "ensure an appropriate bean is registered.");
}
}
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2012-2016 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
*
* http://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.neo4j;
import org.neo4j.ogm.config.Configuration;
import org.neo4j.ogm.session.SessionFactory;
/**
* Provide a a Neo4j {@link SessionFactory} instance based on a
* configurable {@link Configuration} and custom packages to scan.
*
* @author Stephane Nicoll
* @since 1.4.0
* @see NodeEntityScan
*/
public class SessionFactoryProvider {
private Configuration configuration;
private String[] packagesToScan;
/**
* Set the configuration to use.
* @param configuration the configuration
*/
public void setConfiguration(Configuration configuration) {
this.configuration = configuration;
}
/**
* Set the packages to scan.
* @param packagesToScan the packages to scan
*/
public void setPackagesToScan(String[] packagesToScan) {
this.packagesToScan = packagesToScan;
}
public SessionFactory getSessionFactory() {
return new SessionFactory(this.configuration, this.packagesToScan);
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2012-2016 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
*
* http://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.
*/
/**
* Neo4j support classes.
*/
package org.springframework.boot.neo4j;

View File

@ -46,7 +46,7 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(EntityScanRegistrar.class)
@Import(JpaEntityScanRegistrar.class)
public @interface EntityScan {
/**

View File

@ -0,0 +1,75 @@
/*
* Copyright 2012-2015 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
*
* http://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.orm.jpa;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.context.scan.AbstractEntityScanBeanPostProcessor;
import org.springframework.boot.context.scan.AbstractEntityScanRegistrar;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.util.Assert;
/**
* {@link ImportBeanDefinitionRegistrar} used by {@link EntityScan}.
*
* @author Phillip Webb
* @author Oliver Gierke
*/
class JpaEntityScanRegistrar extends AbstractEntityScanRegistrar {
JpaEntityScanRegistrar() {
super(EntityScan.class, "entityScanBeanPostProcessor", JpaEntityScanBeanPostProcessor.class);
}
/**
* {@link BeanPostProcessor} to set
* {@link LocalContainerEntityManagerFactoryBean#setPackagesToScan(String...)} based
* on an {@link EntityScan} annotation.
*/
static class JpaEntityScanBeanPostProcessor extends AbstractEntityScanBeanPostProcessor
implements SmartInitializingSingleton {
private boolean processed;
JpaEntityScanBeanPostProcessor(String[] packagesToScan) {
super(packagesToScan);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof LocalContainerEntityManagerFactoryBean) {
LocalContainerEntityManagerFactoryBean factoryBean = (LocalContainerEntityManagerFactoryBean) bean;
factoryBean.setPackagesToScan(getPackagesToScan());
this.processed = true;
}
return bean;
}
@Override
public void afterSingletonsInstantiated() {
Assert.state(this.processed,
"Unable to configure "
+ "LocalContainerEntityManagerFactoryBean from @EntityScan, "
+ "ensure an appropriate bean is registered.");
}
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 2012-2016 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
*
* http://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.context.scan;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.context.annotation.Import;
/**
* EntityScan test annotation.
*
* @author Stephane Nicoll
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TestEntityScanRegistrar.class)
public @interface TestEntityScan {
String[] value() default {};
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
}

View File

@ -0,0 +1,65 @@
/*
* Copyright 2012-2016 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
*
* http://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.context.scan;
import org.springframework.beans.BeansException;
/**
* Test implementation of {@link AbstractEntityScanRegistrar}.
*
* @author Stephane Nicoll
*/
class TestEntityScanRegistrar extends AbstractEntityScanRegistrar {
static final String BEAN_NAME = "testEntityScanBeanPostProcessor";
TestEntityScanRegistrar() {
super(TestEntityScan.class, BEAN_NAME, TestEntityScanBeanPostProcessor.class);
}
static class TestFactoryBean {
private String[] packagesToScan;
public void setPackagesToScan(String... packagesToScan) {
this.packagesToScan = packagesToScan;
}
public String[] getPackagesToScan() {
return this.packagesToScan;
}
}
static class TestEntityScanBeanPostProcessor extends AbstractEntityScanBeanPostProcessor {
TestEntityScanBeanPostProcessor(String[] packagesToScan) {
super(packagesToScan);
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof TestFactoryBean) {
TestFactoryBean factoryBean = (TestFactoryBean) bean;
factoryBean.setPackagesToScan(getPackagesToScan());
}
return bean;
}
}
}

View File

@ -0,0 +1,158 @@
/*
* Copyright 2012-2016 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
*
* http://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.context.scan;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.boot.context.scan.TestEntityScanRegistrar.TestFactoryBean;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link TestEntityScan}.
*
* @author Phillip Webb
* @author Stephane Nicoll
*/
public class TestEntityScanTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
private AnnotationConfigApplicationContext context;
@After
public void closeContext() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void testValue() throws Exception {
this.context = new AnnotationConfigApplicationContext(ValueConfig.class);
assertSetPackagesToScan("com.mycorp.entity");
}
@Test
public void basePackages() throws Exception {
this.context = new AnnotationConfigApplicationContext(BasePackagesConfig.class);
assertSetPackagesToScan("com.mycorp.entity2");
}
@Test
public void basePackageClasses() throws Exception {
this.context = new AnnotationConfigApplicationContext(
BasePackageClassesConfig.class);
assertSetPackagesToScan(getClass().getPackage().getName());
}
@Test
public void fromConfigurationClass() throws Exception {
this.context = new AnnotationConfigApplicationContext(FromConfigConfig.class);
assertSetPackagesToScan(getClass().getPackage().getName());
}
@Test
public void valueAndBasePackagesThrows() throws Exception {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("@TestEntityScan basePackages and value "
+ "attributes are mutually exclusive");
this.context = new AnnotationConfigApplicationContext(ValueAndBasePackages.class);
}
@Test
public void valueAndBasePackageClassesMerges() throws Exception {
this.context = new AnnotationConfigApplicationContext(
ValueAndBasePackageClasses.class);
assertSetPackagesToScan("com.mycorp.entity", getClass().getPackage().getName());
}
@Test
public void basePackageAndBasePackageClassesMerges() throws Exception {
this.context = new AnnotationConfigApplicationContext(
BasePackagesAndBasePackageClasses.class);
assertSetPackagesToScan("com.mycorp.entity2", getClass().getPackage().getName());
}
@Test
public void considersMultipleAnnotations() {
this.context = new AnnotationConfigApplicationContext(MultiScanFirst.class,
MultiScanSecond.class);
assertSetPackagesToScan("foo", "bar");
}
private void assertSetPackagesToScan(String... expected) {
String[] actual = this.context
.getBean(TestFactoryBean.class)
.getPackagesToScan();
assertThat(actual).isEqualTo(expected);
}
@Configuration
static class BaseConfig {
@Bean
public TestFactoryBean testFactoryBean() {
return new TestFactoryBean();
}
}
@TestEntityScan("com.mycorp.entity")
static class ValueConfig extends BaseConfig {
}
@TestEntityScan(basePackages = "com.mycorp.entity2")
static class BasePackagesConfig extends BaseConfig {
}
@TestEntityScan(basePackageClasses = TestEntityScanTests.class)
static class BasePackageClassesConfig extends BaseConfig {
}
@TestEntityScan
static class FromConfigConfig extends BaseConfig {
}
@TestEntityScan(value = "com.mycorp.entity", basePackages = "com.mycorp")
static class ValueAndBasePackages extends BaseConfig {
}
@TestEntityScan(value = "com.mycorp.entity", basePackageClasses = TestEntityScanTests.class)
static class ValueAndBasePackageClasses extends BaseConfig {
}
@TestEntityScan(basePackages = "com.mycorp.entity2", basePackageClasses = TestEntityScanTests.class)
static class BasePackagesAndBasePackageClasses extends BaseConfig {
}
@TestEntityScan(basePackages = "foo")
static class MultiScanFirst extends BaseConfig {
}
@TestEntityScan(basePackages = "bar")
static class MultiScanSecond extends BaseConfig {
}
}

View File

@ -0,0 +1,107 @@
/*
* Copyright 2012-2016 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
*
* http://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.neo4j;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link NodeEntityScan}.
*
* @author Stephane Nicoll
*/
public class NodeEntityScanTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
private AnnotationConfigApplicationContext context;
@After
public void closeContext() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void simpleValue() throws Exception {
this.context = new AnnotationConfigApplicationContext(ValueConfig.class);
assertSetPackagesToScan("com.mycorp.entity");
}
@Test
public void needsSessionFactoryFactory() throws Exception {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("Unable to configure "
+ "SessionFactoryFactoryBean from @NodeEntityScan, "
+ "ensure an appropriate bean is registered.");
this.context = new AnnotationConfigApplicationContext(MissingSessionFactory.class);
}
private void assertSetPackagesToScan(String... expected) {
String[] actual = this.context
.getBean(TestSessionFactoryProvider.class)
.getPackagesToScan();
assertThat(actual).isEqualTo(expected);
}
@Configuration
static class BaseConfig {
@Bean
public SessionFactoryProvider sessionFactoryFactoryBean() {
return new TestSessionFactoryProvider();
}
}
@NodeEntityScan("com.mycorp.entity")
static class ValueConfig extends BaseConfig {
}
@Configuration
@NodeEntityScan("com.mycorp.entity")
static class MissingSessionFactory {
}
private static class TestSessionFactoryProvider
extends SessionFactoryProvider {
private String[] packagesToScan;
@Override
public void setPackagesToScan(String... packagesToScan) {
this.packagesToScan = packagesToScan;
}
public String[] getPackagesToScan() {
return this.packagesToScan;
}
}
}

View File

@ -19,6 +19,7 @@ package org.springframework.boot.orm.jpa;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceException;
import org.junit.After;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
@ -37,6 +38,7 @@ import static org.mockito.Mockito.mock;
* Tests for {@link EntityScan}.
*
* @author Phillip Webb
* @author Stephane Nicoll
*/
public class EntityScanTests {
@ -45,53 +47,19 @@ public class EntityScanTests {
private AnnotationConfigApplicationContext context;
@After
public void closeContext() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void testValue() throws Exception {
public void simpleValue() throws Exception {
this.context = new AnnotationConfigApplicationContext(ValueConfig.class);
assertSetPackagesToScan("com.mycorp.entity");
}
@Test
public void basePackages() throws Exception {
this.context = new AnnotationConfigApplicationContext(BasePackagesConfig.class);
assertSetPackagesToScan("com.mycorp.entity2");
}
@Test
public void basePackageClasses() throws Exception {
this.context = new AnnotationConfigApplicationContext(
BasePackageClassesConfig.class);
assertSetPackagesToScan(getClass().getPackage().getName());
}
@Test
public void fromConfigurationClass() throws Exception {
this.context = new AnnotationConfigApplicationContext(FromConfigConfig.class);
assertSetPackagesToScan(getClass().getPackage().getName());
}
@Test
public void valueAndBasePackagesThrows() throws Exception {
this.thrown.expect(IllegalStateException.class);
this.thrown.expectMessage("@EntityScan basePackages and value "
+ "attributes are mutually exclusive");
this.context = new AnnotationConfigApplicationContext(ValueAndBasePackages.class);
}
@Test
public void valueAndBasePackageClassesMerges() throws Exception {
this.context = new AnnotationConfigApplicationContext(
ValueAndBasePackageClasses.class);
assertSetPackagesToScan("com.mycorp.entity", getClass().getPackage().getName());
}
@Test
public void basePackageAndBasePackageClassesMerges() throws Exception {
this.context = new AnnotationConfigApplicationContext(
BasePackagesAndBasePackageClasses.class);
assertSetPackagesToScan("com.mycorp.entity2", getClass().getPackage().getName());
}
@Test
public void needsEntityManageFactory() throws Exception {
this.thrown.expect(IllegalStateException.class);
@ -108,13 +76,6 @@ public class EntityScanTests {
assertSetPackagesToScan("com.mycorp.entity");
}
@Test
public void considersMultipleEntityScanAnnotations() {
this.context = new AnnotationConfigApplicationContext(MultiScanFirst.class,
MultiScanSecond.class);
assertSetPackagesToScan("foo", "bar");
}
private void assertSetPackagesToScan(String... expected) {
String[] actual = this.context
.getBean(TestLocalContainerEntityManagerFactoryBean.class)
@ -136,30 +97,6 @@ public class EntityScanTests {
static class ValueConfig extends BaseConfig {
}
@EntityScan(basePackages = "com.mycorp.entity2")
static class BasePackagesConfig extends BaseConfig {
}
@EntityScan(basePackageClasses = EntityScanTests.class)
static class BasePackageClassesConfig extends BaseConfig {
}
@EntityScan
static class FromConfigConfig extends BaseConfig {
}
@EntityScan(value = "com.mycorp.entity", basePackages = "com.mycorp")
static class ValueAndBasePackages extends BaseConfig {
}
@EntityScan(value = "com.mycorp.entity", basePackageClasses = EntityScanTests.class)
static class ValueAndBasePackageClasses extends BaseConfig {
}
@EntityScan(basePackages = "com.mycorp.entity2", basePackageClasses = EntityScanTests.class)
static class BasePackagesAndBasePackageClasses extends BaseConfig {
}
@Configuration
@EntityScan("com.mycorp.entity")
static class MissingEntityManager {
@ -195,16 +132,6 @@ public class EntityScanTests {
}
}
@EntityScan(basePackages = "foo")
static class MultiScanFirst extends BaseConfig {
}
@EntityScan(basePackages = "bar")
static class MultiScanSecond extends BaseConfig {
}
private static class TestLocalContainerEntityManagerFactoryBean
extends LocalContainerEntityManagerFactoryBean {