Commit 44b7f29e authored by Phillip Webb's avatar Phillip Webb

Merge branch 'gh-6142'

Closes gh-6142
parents c22a0e90 e8d4d0e2
...@@ -24,9 +24,9 @@ import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfigurati ...@@ -24,9 +24,9 @@ import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfigurati
import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration; import org.springframework.boot.autoconfigure.data.cassandra.CassandraDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration; import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration; import org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositoriesAutoConfiguration;
import org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration; import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration; 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.builder.SpringApplicationBuilder;
import org.springframework.boot.test.util.ApplicationContextTestUtils; import org.springframework.boot.test.util.ApplicationContextTestUtils;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
...@@ -64,7 +64,7 @@ public class SpringApplicationHierarchyTests { ...@@ -64,7 +64,7 @@ public class SpringApplicationHierarchyTests {
@EnableAutoConfiguration(exclude = { ElasticsearchDataAutoConfiguration.class, @EnableAutoConfiguration(exclude = { ElasticsearchDataAutoConfiguration.class,
ElasticsearchRepositoriesAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class,
CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class, CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class,
Neo4jAutoConfiguration.class, RedisAutoConfiguration.class, Neo4jDataAutoConfiguration.class, RedisAutoConfiguration.class,
RedisRepositoriesAutoConfiguration.class }, excludeName = { RedisRepositoriesAutoConfiguration.class }, excludeName = {
"org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration" }) "org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration" })
public static class Child { public static class Child {
...@@ -76,7 +76,7 @@ public class SpringApplicationHierarchyTests { ...@@ -76,7 +76,7 @@ public class SpringApplicationHierarchyTests {
ElasticsearchDataAutoConfiguration.class, ElasticsearchDataAutoConfiguration.class,
ElasticsearchRepositoriesAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class,
CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class, CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class,
Neo4jAutoConfiguration.class, RedisAutoConfiguration.class, Neo4jDataAutoConfiguration.class, RedisAutoConfiguration.class,
RedisRepositoriesAutoConfiguration.class }, excludeName = { RedisRepositoriesAutoConfiguration.class }, excludeName = {
"org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration" }) "org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration" })
public static class Parent { public static class Parent {
......
...@@ -16,18 +16,24 @@ ...@@ -16,18 +16,24 @@
package org.springframework.boot.autoconfigure.data.cassandra; package org.springframework.boot.autoconfigure.data.cassandra;
import java.util.List;
import com.datastax.driver.core.Cluster; import com.datastax.driver.core.Cluster;
import com.datastax.driver.core.Session; import com.datastax.driver.core.Session;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.boot.autoconfigure.cassandra.CassandraProperties; import org.springframework.boot.autoconfigure.cassandra.CassandraProperties;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.domain.EntityScanPackages;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.cassandra.config.CassandraEntityClassScanner;
import org.springframework.data.cassandra.config.CassandraSessionFactoryBean; import org.springframework.data.cassandra.config.CassandraSessionFactoryBean;
import org.springframework.data.cassandra.config.SchemaAction; import org.springframework.data.cassandra.config.SchemaAction;
import org.springframework.data.cassandra.convert.CassandraConverter; import org.springframework.data.cassandra.convert.CassandraConverter;
...@@ -50,20 +56,32 @@ import org.springframework.data.cassandra.mapping.CassandraMappingContext; ...@@ -50,20 +56,32 @@ import org.springframework.data.cassandra.mapping.CassandraMappingContext;
@AutoConfigureAfter(CassandraAutoConfiguration.class) @AutoConfigureAfter(CassandraAutoConfiguration.class)
public class CassandraDataAutoConfiguration { public class CassandraDataAutoConfiguration {
private final BeanFactory beanFactory;
private final CassandraProperties properties; private final CassandraProperties properties;
private final Cluster cluster; private final Cluster cluster;
public CassandraDataAutoConfiguration(CassandraProperties properties, public CassandraDataAutoConfiguration(BeanFactory beanFactory,
Cluster cluster) { CassandraProperties properties, Cluster cluster) {
this.beanFactory = beanFactory;
this.properties = properties; this.properties = properties;
this.cluster = cluster; this.cluster = cluster;
} }
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public CassandraMappingContext cassandraMapping() { public CassandraMappingContext cassandraMapping() throws ClassNotFoundException {
return new BasicCassandraMappingContext(); BasicCassandraMappingContext context = new BasicCassandraMappingContext();
List<String> packages = EntityScanPackages.get(this.beanFactory)
.getPackageNames();
if (packages.isEmpty() && AutoConfigurationPackages.has(this.beanFactory)) {
packages = AutoConfigurationPackages.get(this.beanFactory);
}
if (!packages.isEmpty()) {
context.setInitialEntitySet(CassandraEntityClassScanner.scan(packages));
}
return context;
} }
@Bean @Bean
......
...@@ -16,15 +16,21 @@ ...@@ -16,15 +16,21 @@
package org.springframework.boot.autoconfigure.data.couchbase; package org.springframework.boot.autoconfigure.data.couchbase;
import java.util.Set;
import org.springframework.beans.factory.ObjectProvider; import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.domain.EntityScanner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.annotation.Persistent;
import org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration; import org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration;
import org.springframework.data.couchbase.config.BeanNames; import org.springframework.data.couchbase.config.BeanNames;
import org.springframework.data.couchbase.config.CouchbaseConfigurer; import org.springframework.data.couchbase.config.CouchbaseConfigurer;
import org.springframework.data.couchbase.core.CouchbaseTemplate; import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.mapping.Document;
import org.springframework.data.couchbase.core.query.Consistency; import org.springframework.data.couchbase.core.query.Consistency;
import org.springframework.data.couchbase.repository.support.IndexManager; import org.springframework.data.couchbase.repository.support.IndexManager;
...@@ -38,12 +44,16 @@ import org.springframework.data.couchbase.repository.support.IndexManager; ...@@ -38,12 +44,16 @@ import org.springframework.data.couchbase.repository.support.IndexManager;
@ConditionalOnBean(CouchbaseConfigurer.class) @ConditionalOnBean(CouchbaseConfigurer.class)
class SpringBootCouchbaseDataConfiguration extends AbstractCouchbaseDataConfiguration { class SpringBootCouchbaseDataConfiguration extends AbstractCouchbaseDataConfiguration {
private final ApplicationContext applicationContext;
private final CouchbaseDataProperties properties; private final CouchbaseDataProperties properties;
private final CouchbaseConfigurer couchbaseConfigurer; private final CouchbaseConfigurer couchbaseConfigurer;
SpringBootCouchbaseDataConfiguration(CouchbaseDataProperties properties, SpringBootCouchbaseDataConfiguration(ApplicationContext applicationContext,
CouchbaseDataProperties properties,
ObjectProvider<CouchbaseConfigurer> couchbaseConfigurerProvider) { ObjectProvider<CouchbaseConfigurer> couchbaseConfigurerProvider) {
this.applicationContext = applicationContext;
this.properties = properties; this.properties = properties;
this.couchbaseConfigurer = couchbaseConfigurerProvider.getIfAvailable(); this.couchbaseConfigurer = couchbaseConfigurerProvider.getIfAvailable();
} }
...@@ -58,6 +68,12 @@ class SpringBootCouchbaseDataConfiguration extends AbstractCouchbaseDataConfigur ...@@ -58,6 +68,12 @@ class SpringBootCouchbaseDataConfiguration extends AbstractCouchbaseDataConfigur
return this.properties.getConsistency(); return this.properties.getConsistency();
} }
@Override
protected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {
return new EntityScanner(this.applicationContext).scan(Document.class,
Persistent.class);
}
@Override @Override
@ConditionalOnMissingBean(name = BeanNames.COUCHBASE_TEMPLATE) @ConditionalOnMissingBean(name = BeanNames.COUCHBASE_TEMPLATE)
@Bean(name = BeanNames.COUCHBASE_TEMPLATE) @Bean(name = BeanNames.COUCHBASE_TEMPLATE)
......
...@@ -17,34 +17,25 @@ ...@@ -17,34 +17,25 @@
package org.springframework.boot.autoconfigure.data.mongo; package org.springframework.boot.autoconfigure.data.mongo;
import java.net.UnknownHostException; import java.net.UnknownHostException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import com.mongodb.DB; import com.mongodb.DB;
import com.mongodb.Mongo; import com.mongodb.Mongo;
import com.mongodb.MongoClient; import com.mongodb.MongoClient;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.BeanClassLoaderAware;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException; import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.AutoConfigureAfter; import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.domain.EntityScanner;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoProperties; import org.springframework.boot.autoconfigure.mongo.MongoProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.PersistenceExceptionTranslator; import org.springframework.dao.support.PersistenceExceptionTranslator;
import org.springframework.data.annotation.Persistent; import org.springframework.data.annotation.Persistent;
...@@ -61,7 +52,6 @@ import org.springframework.data.mongodb.core.mapping.Document; ...@@ -61,7 +52,6 @@ import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.MongoMappingContext; import org.springframework.data.mongodb.core.mapping.MongoMappingContext;
import org.springframework.data.mongodb.gridfs.GridFsTemplate; import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
/** /**
...@@ -84,26 +74,16 @@ import org.springframework.util.StringUtils; ...@@ -84,26 +74,16 @@ import org.springframework.util.StringUtils;
@ConditionalOnClass({ Mongo.class, MongoTemplate.class }) @ConditionalOnClass({ Mongo.class, MongoTemplate.class })
@EnableConfigurationProperties(MongoProperties.class) @EnableConfigurationProperties(MongoProperties.class)
@AutoConfigureAfter(MongoAutoConfiguration.class) @AutoConfigureAfter(MongoAutoConfiguration.class)
public class MongoDataAutoConfiguration implements BeanClassLoaderAware { public class MongoDataAutoConfiguration {
private final MongoProperties properties; private final ApplicationContext applicationContext;
private final Environment environment;
private final ResourceLoader resourceLoader; private final MongoProperties properties;
private ClassLoader classLoader;
public MongoDataAutoConfiguration(MongoProperties properties, Environment environment, public MongoDataAutoConfiguration(ApplicationContext applicationContext,
ResourceLoader resourceLoader) { MongoProperties properties) {
this.applicationContext = applicationContext;
this.properties = properties; this.properties = properties;
this.environment = environment;
this.resourceLoader = resourceLoader;
}
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader;
} }
@Bean @Bean
...@@ -142,7 +122,8 @@ public class MongoDataAutoConfiguration implements BeanClassLoaderAware { ...@@ -142,7 +122,8 @@ public class MongoDataAutoConfiguration implements BeanClassLoaderAware {
public MongoMappingContext mongoMappingContext(BeanFactory beanFactory) public MongoMappingContext mongoMappingContext(BeanFactory beanFactory)
throws ClassNotFoundException { throws ClassNotFoundException {
MongoMappingContext context = new MongoMappingContext(); MongoMappingContext context = new MongoMappingContext();
context.setInitialEntitySet(getInitialEntitySet(beanFactory)); context.setInitialEntitySet(new EntityScanner(this.applicationContext)
.scan(Document.class, Persistent.class));
Class<?> strategyClass = this.properties.getFieldNamingStrategy(); Class<?> strategyClass = this.properties.getFieldNamingStrategy();
if (strategyClass != null) { if (strategyClass != null) {
context.setFieldNamingStrategy( context.setFieldNamingStrategy(
...@@ -151,37 +132,6 @@ public class MongoDataAutoConfiguration implements BeanClassLoaderAware { ...@@ -151,37 +132,6 @@ public class MongoDataAutoConfiguration implements BeanClassLoaderAware {
return context; return context;
} }
private Set<Class<?>> getInitialEntitySet(BeanFactory beanFactory)
throws ClassNotFoundException {
Set<Class<?>> entitySet = new HashSet<Class<?>>();
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(
false);
scanner.setEnvironment(this.environment);
scanner.setResourceLoader(this.resourceLoader);
scanner.addIncludeFilter(new AnnotationTypeFilter(Document.class));
scanner.addIncludeFilter(new AnnotationTypeFilter(Persistent.class));
for (String basePackage : getMappingBasePackages(beanFactory)) {
if (StringUtils.hasText(basePackage)) {
for (BeanDefinition candidate : scanner
.findCandidateComponents(basePackage)) {
entitySet.add(ClassUtils.forName(candidate.getBeanClassName(),
this.classLoader));
}
}
}
return entitySet;
}
private static Collection<String> getMappingBasePackages(BeanFactory beanFactory) {
try {
return AutoConfigurationPackages.get(beanFactory);
}
catch (IllegalStateException ex) {
// no auto-configuration package registered yet
return Collections.emptyList();
}
}
@Bean @Bean
@ConditionalOnMissingBean @ConditionalOnMissingBean
public GridFsTemplate gridFsTemplate(MongoDbFactory mongoDbFactory, public GridFsTemplate gridFsTemplate(MongoDbFactory mongoDbFactory,
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.autoconfigure.neo4j; package org.springframework.boot.autoconfigure.data.neo4j;
import java.util.List; import java.util.List;
...@@ -22,30 +22,22 @@ import org.neo4j.ogm.session.Neo4jSession; ...@@ -22,30 +22,22 @@ import org.neo4j.ogm.session.Neo4jSession;
import org.neo4j.ogm.session.Session; import org.neo4j.ogm.session.Session;
import org.neo4j.ogm.session.SessionFactory; 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.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.domain.EntityScanPackages;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.neo4j.SessionFactoryProvider; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Scope; import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.data.neo4j.config.Neo4jConfiguration; import org.springframework.data.neo4j.config.Neo4jConfiguration;
import org.springframework.data.neo4j.template.Neo4jOperations; import org.springframework.data.neo4j.template.Neo4jOperations;
import org.springframework.data.neo4j.template.Neo4jTemplate;
/** /**
* {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Neo4j support. * {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j.
* <p>
* Registers a {@link Neo4jTemplate} bean if no other bean of the same type is configured.
* *
* @author Michael Hunger * @author Michael Hunger
* @author Josh Long * @author Josh Long
...@@ -57,84 +49,53 @@ import org.springframework.data.neo4j.template.Neo4jTemplate; ...@@ -57,84 +49,53 @@ import org.springframework.data.neo4j.template.Neo4jTemplate;
@ConditionalOnClass({ Neo4jSession.class, Neo4jOperations.class }) @ConditionalOnClass({ Neo4jSession.class, Neo4jOperations.class })
@ConditionalOnMissingBean(Neo4jOperations.class) @ConditionalOnMissingBean(Neo4jOperations.class)
@EnableConfigurationProperties(Neo4jProperties.class) @EnableConfigurationProperties(Neo4jProperties.class)
public class Neo4jAutoConfiguration { public class Neo4jDataAutoConfiguration {
@Configuration private final Neo4jProperties properties;
@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() {
return this.sessionFactoryProvider.getObject().getSessionFactory();
}
@Bean public Neo4jDataAutoConfiguration(Neo4jProperties properties) {
@Scope(scopeName = "${spring.data.neo4j.session.scope:singleton}", proxyMode = ScopedProxyMode.TARGET_CLASS) this.properties = properties;
@Override }
public Session getSession() throws Exception {
return getSessionFactory().openSession();
}
@Bean
@ConditionalOnMissingBean
public org.neo4j.ogm.config.Configuration configuration() {
return this.properties.createConfiguration();
} }
@Configuration @Configuration
@Import(Neo4jConfigurationConfiguration.class) static class SpringBootNeo4jConfiguration extends Neo4jConfiguration {
static class SessionFactoryProviderConfiguration implements BeanFactoryAware {
private final org.neo4j.ogm.config.Configuration configuration; private final ApplicationContext applicationContext;
private ConfigurableListableBeanFactory beanFactory; private final org.neo4j.ogm.config.Configuration configuration;
SessionFactoryProviderConfiguration( SpringBootNeo4jConfiguration(ApplicationContext applicationContext,
org.neo4j.ogm.config.Configuration configuration) { org.neo4j.ogm.config.Configuration configuration) {
this.applicationContext = applicationContext;
this.configuration = configuration; this.configuration = configuration;
} }
@Bean
@ConditionalOnMissingBean
public SessionFactoryProvider sessionFactoryProvider() {
SessionFactoryProvider provider = new SessionFactoryProvider();
provider.setConfiguration(this.configuration);
provider.setPackagesToScan(getPackagesToScan());
return provider;
}
@Override @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException { public SessionFactory getSessionFactory() {
this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; return new SessionFactory(this.configuration, getPackagesToScan());
} }
protected String[] getPackagesToScan() { private String[] getPackagesToScan() {
if (AutoConfigurationPackages.has(this.beanFactory)) { List<String> packages = EntityScanPackages.get(this.applicationContext)
List<String> basePackages = AutoConfigurationPackages .getPackageNames();
.get(this.beanFactory); if (packages.isEmpty()
return basePackages.toArray(new String[basePackages.size()]); && AutoConfigurationPackages.has(this.applicationContext)) {
packages = AutoConfigurationPackages.get(this.applicationContext);
} }
return new String[0]; return packages.toArray(new String[packages.size()]);
}
}
@Configuration
static class Neo4jConfigurationConfiguration {
private final Neo4jProperties properties;
Neo4jConfigurationConfiguration(Neo4jProperties properties) {
this.properties = properties;
} }
@Override
@Bean @Bean
@ConditionalOnMissingBean @Scope(scopeName = "${spring.data.neo4j.session.scope:singleton}", proxyMode = ScopedProxyMode.TARGET_CLASS)
public org.neo4j.ogm.config.Configuration configuration() { public Session getSession() throws Exception {
return this.properties.createConfiguration(); return super.getSession();
} }
} }
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.autoconfigure.neo4j; package org.springframework.boot.autoconfigure.data.neo4j;
import java.net.URI; import java.net.URI;
import java.net.URISyntaxException; import java.net.URISyntaxException;
......
...@@ -23,7 +23,6 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; ...@@ -23,7 +23,6 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; 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.Configuration;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.data.neo4j.repository.GraphRepository; import org.springframework.data.neo4j.repository.GraphRepository;
...@@ -59,7 +58,7 @@ import org.springframework.data.neo4j.repository.support.GraphRepositoryFactoryB ...@@ -59,7 +58,7 @@ import org.springframework.data.neo4j.repository.support.GraphRepositoryFactoryB
Neo4jRepositoryConfigurationExtension.class }) Neo4jRepositoryConfigurationExtension.class })
@ConditionalOnProperty(prefix = "spring.data.neo4j.repositories", name = "enabled", havingValue = "true", matchIfMissing = true) @ConditionalOnProperty(prefix = "spring.data.neo4j.repositories", name = "enabled", havingValue = "true", matchIfMissing = true)
@Import(Neo4jRepositoriesAutoConfigureRegistrar.class) @Import(Neo4jRepositoriesAutoConfigureRegistrar.class)
@AutoConfigureAfter(Neo4jAutoConfiguration.class) @AutoConfigureAfter(Neo4jDataAutoConfiguration.class)
public class Neo4jRepositoriesAutoConfiguration { public class Neo4jRepositoriesAutoConfiguration {
} }
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.neo4j; package org.springframework.boot.autoconfigure.domain;
import java.lang.annotation.Documented; import java.lang.annotation.Documented;
import java.lang.annotation.ElementType; import java.lang.annotation.ElementType;
...@@ -22,49 +22,56 @@ import java.lang.annotation.Retention; ...@@ -22,49 +22,56 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.session.SessionFactory;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.AliasFor;
/** /**
* Configures the {@link SessionFactory} to scan for Neo4J {@link NodeEntity} classes in * Configures the base packages used by auto-configuration when scanning for entity
* the classpath. This annotation provides an alternative to manually setting * classes.
* {@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> * <p>
* A {@link SessionFactoryProvider} must be configured within your Spring * Using {@code @EntityScan} will cause auto-configuration to:
* ApplicationContext in order to use entity scanning. Furthermore, any existing * <ul>
* {@code packagesToScan} setting will be replaced. * <li>Set the
* {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#setPackagesToScan(String...)
* packages scanned} for JPA entities.</li>
* <li>Set the packages used with Neo4J's {@link org.neo4j.ogm.session.SessionFactory
* SessionFactory}.</li>
* <li>Set the
* {@link org.springframework.data.mapping.context.AbstractMappingContext#setInitialEntitySet(java.util.Set)
* initial entity set} used with Spring Data
* {@link org.springframework.data.mongodb.core.mapping.MongoMappingContext MongoDB},
* {@link org.springframework.data.cassandra.mapping.CassandraMappingContext Cassandra}
* and {@link org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext
* Couchbase} mapping contexts.</li>
* </ul>
* <p> * <p>
* One of {@link #basePackageClasses()}, {@link #basePackages()} or its alias * One of {@link #basePackageClasses()}, {@link #basePackages()} or its alias
* {@link #value()} may be specified to define specific packages to scan. If specific * {@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 * packages are not defined scanning will occur from the package of the class with this
* annotation. * annotation.
* *
* @author Stephane Nicoll * @author Phillip Webb
* @since 1.4.0 * @since 1.4.0
* @see EntityScanPackages
*/ */
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@Import(NodeEntityScanRegistrar.class) @Import(EntityScanPackages.Registrar.class)
public @interface NodeEntityScan { public @interface EntityScan {
/** /**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation
* declarations e.g.: {@code @NodeEntityScan("org.my.pkg")} instead of * declarations e.g.: {@code @EntityScan("org.my.pkg")} instead of
* {@code @NodeEntityScan(basePackages="org.my.pkg")}. * {@code @EntityScan(basePackages="org.my.pkg")}.
* @return the base packages to scan * @return the base packages to scan
*/ */
@AliasFor("basePackages") @AliasFor("basePackages")
String[] value() default {}; String[] value() default {};
/** /**
* Base packages to scan for node entities. {@link #value()} is an alias for (and * Base packages to scan for entities. {@link #value()} is an alias for (and mutually
* mutually exclusive with) this attribute. * exclusive with) this attribute.
* <p> * <p>
* Use {@link #basePackageClasses()} for a type-safe alternative to String-based * Use {@link #basePackageClasses()} for a type-safe alternative to String-based
* package names. * package names.
...@@ -75,7 +82,7 @@ public @interface NodeEntityScan { ...@@ -75,7 +82,7 @@ public @interface NodeEntityScan {
/** /**
* Type-safe alternative to {@link #basePackages()} for specifying the packages to * Type-safe alternative to {@link #basePackages()} for specifying the packages to
* scan for node entities. The package of each class specified will be scanned. * scan for entities. The package of each class specified will be scanned.
* <p> * <p>
* Consider creating a special no-op marker class or interface in each package that * Consider creating a special no-op marker class or interface in each package that
* serves no purpose other than being referenced by this attribute. * serves no purpose other than being referenced by this attribute.
......
/*
* 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.domain;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.BeanDefinition;
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.annotation.Order;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* Class for storing {@link EntityScan @EntityScan} specified packages for reference later
* (e.g. by JPA auto-configuration).
*
* @author Phillip Webb
* @since 1.4.0
* @see EntityScan
* @see EntityScanner
*/
public class EntityScanPackages {
private static final String BEAN = EntityScanPackages.class.getName();
private static final EntityScanPackages NONE = new EntityScanPackages();
private final List<String> packageNames;
EntityScanPackages(String... packageNames) {
List<String> packages = new ArrayList<String>();
for (String name : packageNames) {
if (StringUtils.hasText(name)) {
packages.add(name);
}
}
this.packageNames = Collections.unmodifiableList(packages);
}
/**
* Return the package names specified from all {@link EntityScan @EntityScan}
* annotations.
* @return the entity scan package names
*/
public List<String> getPackageNames() {
return this.packageNames;
}
/**
* Return the {@link EntityScanPackages} for the given bean factory.
* @param beanFactory the source bean factory
* @return the {@link EntityScanPackages} for the bean factory (never {@code null})
*/
public static EntityScanPackages get(BeanFactory beanFactory) {
// Currently we only store a single base package, but we return a list to
// allow this to change in the future if needed
try {
return beanFactory.getBean(BEAN, EntityScanPackages.class);
}
catch (NoSuchBeanDefinitionException ex) {
return NONE;
}
}
/**
* Register the specified entity scan packages with the system.
* @param registry the source registry
* @param packageNames the package names to register
*/
public static void register(BeanDefinitionRegistry registry, String... packageNames) {
Assert.notNull(registry, "Registry must not be null");
Assert.notNull(packageNames, "PackageNames must not be null");
register(registry, Arrays.asList(packageNames));
}
/**
* Register the specified entity scan packages with the system.
* @param registry the source registry
* @param packageNames the package names to register
*/
public static void register(BeanDefinitionRegistry registry,
Collection<String> packageNames) {
Assert.notNull(registry, "Registry must not be null");
Assert.notNull(packageNames, "PackageNames must not be null");
if (registry.containsBeanDefinition(BEAN)) {
BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);
ConstructorArgumentValues constructorArguments = beanDefinition
.getConstructorArgumentValues();
constructorArguments.addIndexedArgumentValue(0,
addPackageNames(constructorArguments, packageNames));
}
else {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(EntityScanPackages.class);
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
packageNames.toArray(new String[packageNames.size()]));
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
registry.registerBeanDefinition(BEAN, beanDefinition);
}
}
private static String[] addPackageNames(
ConstructorArgumentValues constructorArguments,
Collection<String> packageNames) {
String[] existing = (String[]) constructorArguments
.getIndexedArgumentValue(0, String[].class).getValue();
Set<String> merged = new LinkedHashSet<String>();
merged.addAll(Arrays.asList(existing));
merged.addAll(packageNames);
return merged.toArray(new String[merged.size()]);
}
/**
* {@link ImportBeanDefinitionRegistrar} to store the base package from the importing
* configuration.
*/
@Order(Ordered.HIGHEST_PRECEDENCE)
static class Registrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata,
BeanDefinitionRegistry registry) {
register(registry, getPackagesToScan(metadata));
}
private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
AnnotationAttributes attributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(EntityScan.class.getName()));
String[] basePackages = attributes.getStringArray("basePackages");
Class<?>[] basePackageClasses = attributes
.getClassArray("basePackageClasses");
Set<String> packagesToScan = new LinkedHashSet<String>();
packagesToScan.addAll(Arrays.asList(basePackages));
for (Class<?> basePackageClass : basePackageClasses) {
packagesToScan.add(ClassUtils.getPackageName(basePackageClass));
}
if (packagesToScan.isEmpty()) {
String packageName = ClassUtils.getPackageName(metadata.getClassName());
Assert.state(!StringUtils.isEmpty(packageName),
"@EntityScan cannot be used with the default package");
return Collections.singleton(packageName);
}
return packagesToScan;
}
}
}
/*
* 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.domain;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
/**
* An entity scanner that searches the classpath from a {@link EntityScan @EntityScan}
* specified packages.
*
* @author Phillip Webb
* @since 1.4.0
*/
public class EntityScanner {
private final ApplicationContext context;
/**
* Create a new {@link EntityScanner} instance.
* @param context the source application context
*/
public EntityScanner(ApplicationContext context) {
Assert.notNull(context, "Context must not be null");
this.context = context;
}
/**
* Scan for entities with the specified annotations.
* @param annotationTypes the annotation types used on the entities
* @return a set of entity classes
* @throws ClassNotFoundException if an entity class cannot be loaded
*/
@SafeVarargs
public final Set<Class<?>> scan(Class<? extends Annotation>... annotationTypes)
throws ClassNotFoundException {
List<String> packages = getPackages();
if (packages.isEmpty()) {
return Collections.<Class<?>>emptySet();
}
Set<Class<?>> entitySet = new HashSet<Class<?>>();
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(
false);
scanner.setEnvironment(this.context.getEnvironment());
scanner.setResourceLoader(this.context);
for (Class<? extends Annotation> annotationType : annotationTypes) {
scanner.addIncludeFilter(new AnnotationTypeFilter(annotationType));
}
for (String basePackage : packages) {
if (StringUtils.hasText(basePackage)) {
for (BeanDefinition candidate : scanner
.findCandidateComponents(basePackage)) {
entitySet.add(ClassUtils.forName(candidate.getBeanClassName(),
this.context.getClassLoader()));
}
}
}
return entitySet;
}
private List<String> getPackages() {
List<String> packages = EntityScanPackages.get(this.context).getPackageNames();
if (packages.isEmpty() && AutoConfigurationPackages.has(this.context)) {
packages = AutoConfigurationPackages.get(this.context);
}
return packages;
}
}
...@@ -15,6 +15,6 @@ ...@@ -15,6 +15,6 @@
*/ */
/** /**
* Support for component scanning. * General purpose domain annotations and classes.
*/ */
package org.springframework.boot.context.scan; package org.springframework.boot.autoconfigure.domain;
...@@ -33,6 +33,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; ...@@ -33,6 +33,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.domain.EntityScanPackages;
import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
...@@ -63,8 +64,6 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter ...@@ -63,8 +64,6 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
@Import(DataSourceInitializedPublisher.Registrar.class) @Import(DataSourceInitializedPublisher.Registrar.class)
public abstract class JpaBaseConfiguration implements BeanFactoryAware { public abstract class JpaBaseConfiguration implements BeanFactoryAware {
private static final String[] NO_PACKAGES = new String[0];
private final DataSource dataSource; private final DataSource dataSource;
private final JpaProperties properties; private final JpaProperties properties;
...@@ -138,11 +137,12 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware { ...@@ -138,11 +137,12 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
} }
protected String[] getPackagesToScan() { protected String[] getPackagesToScan() {
if (AutoConfigurationPackages.has(this.beanFactory)) { List<String> packages = EntityScanPackages.get(this.beanFactory)
List<String> basePackages = AutoConfigurationPackages.get(this.beanFactory); .getPackageNames();
return basePackages.toArray(new String[basePackages.size()]); if (packages.isEmpty() && AutoConfigurationPackages.has(this.beanFactory)) {
packages = AutoConfigurationPackages.get(this.beanFactory);
} }
return NO_PACKAGES; return packages.toArray(new String[packages.size()]);
} }
/** /**
......
...@@ -31,6 +31,7 @@ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositor ...@@ -31,6 +31,7 @@ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositor
org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\
org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
...@@ -70,7 +71,6 @@ org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\ ...@@ -70,7 +71,6 @@ org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\
org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\
org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration,\
org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\
org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\ org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\
org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\ org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\
......
...@@ -16,18 +16,24 @@ ...@@ -16,18 +16,24 @@
package org.springframework.boot.autoconfigure.data.cassandra; package org.springframework.boot.autoconfigure.data.cassandra;
import java.util.Set;
import com.datastax.driver.core.Session; import com.datastax.driver.core.Session;
import org.junit.After; import org.junit.After;
import org.junit.Test; import org.junit.Test;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration;
import org.springframework.boot.autoconfigure.data.cassandra.city.City;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType; import org.springframework.context.annotation.FilterType;
import org.springframework.data.cassandra.core.CassandraTemplate; import org.springframework.data.cassandra.core.CassandraTemplate;
import org.springframework.data.cassandra.mapping.CassandraMappingContext;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
...@@ -59,6 +65,21 @@ public class CassandraDataAutoConfigurationTests { ...@@ -59,6 +65,21 @@ public class CassandraDataAutoConfigurationTests {
.isEqualTo(1); .isEqualTo(1);
} }
@Test
@SuppressWarnings("unchecked")
public void entityScanShouldSetInitialEntitySet() throws Exception {
this.context = new AnnotationConfigApplicationContext();
this.context.register(TestConfiguration.class, EntityScanConfig.class,
PropertyPlaceholderAutoConfiguration.class,
CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class);
this.context.refresh();
CassandraMappingContext mappingContext = this.context
.getBean(CassandraMappingContext.class);
Set<Class<?>> initialEntitySet = (Set<Class<?>>) ReflectionTestUtils
.getField(mappingContext, "initialEntitySet");
assertThat(initialEntitySet).containsOnly(City.class);
}
@Configuration @Configuration
@ComponentScan(excludeFilters = @ComponentScan.Filter(classes = { @ComponentScan(excludeFilters = @ComponentScan.Filter(classes = {
Session.class }, type = FilterType.ASSIGNABLE_TYPE)) Session.class }, type = FilterType.ASSIGNABLE_TYPE))
...@@ -76,4 +97,10 @@ public class CassandraDataAutoConfigurationTests { ...@@ -76,4 +97,10 @@ public class CassandraDataAutoConfigurationTests {
} }
@Configuration
@EntityScan("org.springframework.boot.autoconfigure.data.cassandra.city")
static class EntityScanConfig {
}
} }
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package org.springframework.boot.autoconfigure.data.couchbase; package org.springframework.boot.autoconfigure.data.couchbase;
import java.util.Set;
import javax.validation.Validator; import javax.validation.Validator;
import org.junit.After; import org.junit.After;
...@@ -25,6 +27,8 @@ import org.springframework.beans.DirectFieldAccessor; ...@@ -25,6 +27,8 @@ import org.springframework.beans.DirectFieldAccessor;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration;
import org.springframework.boot.autoconfigure.couchbase.CouchbaseTestConfigurer; import org.springframework.boot.autoconfigure.couchbase.CouchbaseTestConfigurer;
import org.springframework.boot.autoconfigure.data.couchbase.city.City;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
...@@ -33,9 +37,11 @@ import org.springframework.context.annotation.Import; ...@@ -33,9 +37,11 @@ import org.springframework.context.annotation.Import;
import org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration; import org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration;
import org.springframework.data.couchbase.config.CouchbaseConfigurer; import org.springframework.data.couchbase.config.CouchbaseConfigurer;
import org.springframework.data.couchbase.core.CouchbaseTemplate; import org.springframework.data.couchbase.core.CouchbaseTemplate;
import org.springframework.data.couchbase.core.mapping.CouchbaseMappingContext;
import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener; import org.springframework.data.couchbase.core.mapping.event.ValidatingCouchbaseEventListener;
import org.springframework.data.couchbase.core.query.Consistency; import org.springframework.data.couchbase.core.query.Consistency;
import org.springframework.data.couchbase.repository.support.IndexManager; import org.springframework.data.couchbase.repository.support.IndexManager;
import org.springframework.test.util.ReflectionTestUtils;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
...@@ -108,6 +114,17 @@ public class CouchbaseDataAutoConfigurationTests { ...@@ -108,6 +114,17 @@ public class CouchbaseDataAutoConfigurationTests {
.isEqualTo(Consistency.EVENTUALLY_CONSISTENT); .isEqualTo(Consistency.EVENTUALLY_CONSISTENT);
} }
@Test
@SuppressWarnings("unchecked")
public void entityScanShouldSetInitialEntitySet() throws Exception {
load(EntityScanConfig.class);
CouchbaseMappingContext mappingContext = this.context
.getBean(CouchbaseMappingContext.class);
Set<Class<?>> initialEntitySet = (Set<Class<?>>) ReflectionTestUtils
.getField(mappingContext, "initialEntitySet");
assertThat(initialEntitySet).containsOnly(City.class);
}
private void load(Class<?> config, String... environment) { private void load(Class<?> config, String... environment) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(context, environment); EnvironmentTestUtils.addEnvironment(context, environment);
...@@ -146,4 +163,11 @@ public class CouchbaseDataAutoConfigurationTests { ...@@ -146,4 +163,11 @@ public class CouchbaseDataAutoConfigurationTests {
} }
@Configuration
@EntityScan("org.springframework.boot.autoconfigure.data.couchbase.city")
@Import(CustomCouchbaseConfiguration.class)
static class EntityScanConfig {
}
} }
...@@ -28,11 +28,11 @@ import org.springframework.boot.autoconfigure.data.jpa.city.City; ...@@ -28,11 +28,11 @@ import org.springframework.boot.autoconfigure.data.jpa.city.City;
import org.springframework.boot.autoconfigure.data.jpa.city.CityRepository; import org.springframework.boot.autoconfigure.data.jpa.city.CityRepository;
import org.springframework.boot.autoconfigure.data.mongo.country.Country; import org.springframework.boot.autoconfigure.data.mongo.country.Country;
import org.springframework.boot.autoconfigure.data.mongo.country.CountryRepository; import org.springframework.boot.autoconfigure.data.mongo.country.CountryRepository;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfigurationTests; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfigurationTests;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.orm.jpa.EntityScan;
import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -80,6 +80,19 @@ public class MixedMongoRepositoriesAutoConfigurationTests { ...@@ -80,6 +80,19 @@ public class MixedMongoRepositoriesAutoConfigurationTests {
assertThat(this.context.getBean(CityRepository.class)).isNotNull(); assertThat(this.context.getBean(CityRepository.class)).isNotNull();
} }
@Test
public void testMixedRepositoryConfigurationWithDeprecatedEntityScan()
throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.initialize:false");
this.context.register(MixedConfigurationWithDeprecatedEntityScan.class,
BaseConfiguration.class);
this.context.refresh();
assertThat(this.context.getBean(CountryRepository.class)).isNotNull();
assertThat(this.context.getBean(CityRepository.class)).isNotNull();
}
@Test @Test
public void testJpaRepositoryConfigurationWithMongoTemplate() throws Exception { public void testJpaRepositoryConfigurationWithMongoTemplate() throws Exception {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
...@@ -90,6 +103,18 @@ public class MixedMongoRepositoriesAutoConfigurationTests { ...@@ -90,6 +103,18 @@ public class MixedMongoRepositoriesAutoConfigurationTests {
assertThat(this.context.getBean(CityRepository.class)).isNotNull(); assertThat(this.context.getBean(CityRepository.class)).isNotNull();
} }
@Test
public void testJpaRepositoryConfigurationWithMongoTemplateAndDeprecatedEntityScan()
throws Exception {
this.context = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.initialize:false");
this.context.register(JpaConfigurationWithDeprecatedEntityScan.class,
BaseConfiguration.class);
this.context.refresh();
assertThat(this.context.getBean(CityRepository.class)).isNotNull();
}
@Test @Test
public void testJpaRepositoryConfigurationWithMongoOverlap() throws Exception { public void testJpaRepositoryConfigurationWithMongoOverlap() throws Exception {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
...@@ -137,6 +162,25 @@ public class MixedMongoRepositoriesAutoConfigurationTests { ...@@ -137,6 +162,25 @@ public class MixedMongoRepositoriesAutoConfigurationTests {
} }
@Configuration
@TestAutoConfigurationPackage(MongoAutoConfigurationTests.class)
@EnableMongoRepositories(basePackageClasses = Country.class)
@org.springframework.boot.orm.jpa.EntityScan(basePackageClasses = City.class)
@EnableJpaRepositories(basePackageClasses = CityRepository.class)
@SuppressWarnings("deprecation")
protected static class MixedConfigurationWithDeprecatedEntityScan {
}
@Configuration
@TestAutoConfigurationPackage(MongoAutoConfigurationTests.class)
@org.springframework.boot.orm.jpa.EntityScan(basePackageClasses = City.class)
@EnableJpaRepositories(basePackageClasses = CityRepository.class)
@SuppressWarnings("deprecation")
protected static class JpaConfigurationWithDeprecatedEntityScan {
}
// In this one the Jpa repositories and the auto-configuration packages overlap, so // In this one the Jpa repositories and the auto-configuration packages overlap, so
// Mongo will try and configure the same repositories // Mongo will try and configure the same repositories
@Configuration @Configuration
......
...@@ -30,6 +30,8 @@ import org.springframework.beans.factory.UnsatisfiedDependencyException; ...@@ -30,6 +30,8 @@ import org.springframework.beans.factory.UnsatisfiedDependencyException;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages; import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.data.mongo.city.City; import org.springframework.boot.autoconfigure.data.mongo.city.City;
import org.springframework.boot.autoconfigure.data.mongo.country.Country;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration;
import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
...@@ -139,6 +141,21 @@ public class MongoDataAutoConfigurationTests { ...@@ -139,6 +141,21 @@ public class MongoDataAutoConfigurationTests {
} }
} }
@Test
@SuppressWarnings("unchecked")
public void entityScanShouldSetInitialEntitySet() throws Exception {
this.context = new AnnotationConfigApplicationContext();
this.context.register(EntityScanConfig.class,
PropertyPlaceholderAutoConfiguration.class, MongoAutoConfiguration.class,
MongoDataAutoConfiguration.class);
this.context.refresh();
MongoMappingContext mappingContext = this.context
.getBean(MongoMappingContext.class);
Set<Class<?>> initialEntitySet = (Set<Class<?>>) ReflectionTestUtils
.getField(mappingContext, "initialEntitySet");
assertThat(initialEntitySet).containsOnly(City.class, Country.class);
}
public void testFieldNamingStrategy(String strategy, public void testFieldNamingStrategy(String strategy,
Class<? extends FieldNamingStrategy> expectedType) { Class<? extends FieldNamingStrategy> expectedType) {
this.context = new AnnotationConfigApplicationContext(); this.context = new AnnotationConfigApplicationContext();
...@@ -173,6 +190,12 @@ public class MongoDataAutoConfigurationTests { ...@@ -173,6 +190,12 @@ public class MongoDataAutoConfigurationTests {
} }
} }
@Configuration
@EntityScan("org.springframework.boot.autoconfigure.data.mongo")
static class EntityScanConfig {
}
private static class MyConverter implements Converter<Mongo, Boolean> { private static class MyConverter implements Converter<Mongo, Boolean> {
@Override @Override
......
...@@ -29,11 +29,10 @@ import org.springframework.boot.autoconfigure.data.jpa.city.City; ...@@ -29,11 +29,10 @@ import org.springframework.boot.autoconfigure.data.jpa.city.City;
import org.springframework.boot.autoconfigure.data.jpa.city.CityRepository; 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.Country;
import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository; import org.springframework.boot.autoconfigure.data.neo4j.country.CountryRepository;
import org.springframework.boot.autoconfigure.data.neo4j.empty.EmptyMarker;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; 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.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
import org.springframework.boot.orm.jpa.EntityScan;
import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -113,7 +112,7 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests { ...@@ -113,7 +112,7 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests {
} }
@Configuration @Configuration
@TestAutoConfigurationPackage(Neo4jAutoConfigurationTests.class) @TestAutoConfigurationPackage(EmptyMarker.class)
// Not this package or its parent // Not this package or its parent
@EnableNeo4jRepositories(basePackageClasses = Country.class) @EnableNeo4jRepositories(basePackageClasses = Country.class)
protected static class TestConfiguration { protected static class TestConfiguration {
...@@ -121,7 +120,7 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests { ...@@ -121,7 +120,7 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests {
} }
@Configuration @Configuration
@TestAutoConfigurationPackage(Neo4jAutoConfigurationTests.class) @TestAutoConfigurationPackage(EmptyMarker.class)
@EnableNeo4jRepositories(basePackageClasses = Country.class) @EnableNeo4jRepositories(basePackageClasses = Country.class)
@EntityScan(basePackageClasses = City.class) @EntityScan(basePackageClasses = City.class)
@EnableJpaRepositories(basePackageClasses = CityRepository.class) @EnableJpaRepositories(basePackageClasses = CityRepository.class)
...@@ -130,7 +129,7 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests { ...@@ -130,7 +129,7 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests {
} }
@Configuration @Configuration
@TestAutoConfigurationPackage(Neo4jAutoConfigurationTests.class) @TestAutoConfigurationPackage(EmptyMarker.class)
@EntityScan(basePackageClasses = City.class) @EntityScan(basePackageClasses = City.class)
@EnableJpaRepositories(basePackageClasses = CityRepository.class) @EnableJpaRepositories(basePackageClasses = CityRepository.class)
protected static class JpaConfiguration { protected static class JpaConfiguration {
...@@ -159,7 +158,8 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests { ...@@ -159,7 +158,8 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests {
List<String> names = new ArrayList<String>(); List<String> names = new ArrayList<String>();
for (Class<?> type : new Class<?>[] { DataSourceAutoConfiguration.class, for (Class<?> type : new Class<?>[] { DataSourceAutoConfiguration.class,
HibernateJpaAutoConfiguration.class, HibernateJpaAutoConfiguration.class,
JpaRepositoriesAutoConfiguration.class, Neo4jAutoConfiguration.class, JpaRepositoriesAutoConfiguration.class,
Neo4jDataAutoConfiguration.class,
Neo4jRepositoriesAutoConfiguration.class }) { Neo4jRepositoriesAutoConfiguration.class }) {
names.add(type.getName()); names.add(type.getName());
} }
......
...@@ -21,18 +21,29 @@ import org.junit.After; ...@@ -21,18 +21,29 @@ import org.junit.After;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
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.AutoConfigurationPackages; import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration;
import org.springframework.boot.autoconfigure.data.neo4j.city.City; import org.springframework.boot.autoconfigure.data.neo4j.city.City;
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.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.neo4j.mapping.Neo4jMappingContext; import org.springframework.data.neo4j.mapping.Neo4jMappingContext;
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 Neo4jDataAutoConfiguration}. Tests can't use the embedded driver as we
* use Lucene 4 and Neo4j still requires 3.
* *
* @author Josh Long * @author Stephane Nicoll
* @author Oliver Gierke * @author Michael Hunger
* @author Vince Bickers * @author Vince Bickers
*/ */
public class Neo4jDataAutoConfigurationTests { public class Neo4jDataAutoConfigurationTests {
...@@ -40,23 +51,79 @@ public class Neo4jDataAutoConfigurationTests { ...@@ -40,23 +51,79 @@ public class Neo4jDataAutoConfigurationTests {
@Rule @Rule
public final ExpectedException thrown = ExpectedException.none(); public final ExpectedException thrown = ExpectedException.none();
private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); private AnnotationConfigApplicationContext context;
@After @After
public void close() { public void close() {
this.context.close(); if (this.context != null) {
this.context.close();
}
}
@Test
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);
} }
@Test @Test
public void usesAutoConfigurationPackageToPickUpDomainTypes() { public void usesAutoConfigurationPackageToPickUpDomainTypes() {
this.context = new AnnotationConfigApplicationContext();
String cityPackage = City.class.getPackage().getName(); String cityPackage = City.class.getPackage().getName();
AutoConfigurationPackages.register(this.context, cityPackage); AutoConfigurationPackages.register(this.context, cityPackage);
this.context.register(Neo4jAutoConfiguration.class); this.context.register(Neo4jDataAutoConfiguration.class);
this.context.refresh(); this.context.refresh();
assertDomainTypesDiscovered(this.context.getBean(Neo4jMappingContext.class), assertDomainTypesDiscovered(this.context.getBean(Neo4jMappingContext.class),
City.class); City.class);
} }
private void load(Class<?> config, String... environment) {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
EnvironmentTestUtils.addEnvironment(ctx, environment);
if (config != null) {
ctx.register(config);
}
ctx.register(PropertyPlaceholderAutoConfiguration.class,
Neo4jDataAutoConfiguration.class);
ctx.refresh();
this.context = ctx;
}
private static void assertDomainTypesDiscovered(Neo4jMappingContext mappingContext, private static void assertDomainTypesDiscovered(Neo4jMappingContext mappingContext,
Class<?>... types) { Class<?>... types) {
for (Class<?> type : types) { for (Class<?> type : types) {
...@@ -64,4 +131,27 @@ public class Neo4jDataAutoConfigurationTests { ...@@ -64,4 +131,27 @@ public class Neo4jDataAutoConfigurationTests {
} }
} }
@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;
}
}
} }
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.autoconfigure.neo4j; package org.springframework.boot.autoconfigure.data.neo4j;
import java.net.URL; import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
......
...@@ -27,7 +27,6 @@ import org.springframework.boot.autoconfigure.data.alt.neo4j.CityNeo4jRepository ...@@ -27,7 +27,6 @@ import org.springframework.boot.autoconfigure.data.alt.neo4j.CityNeo4jRepository
import org.springframework.boot.autoconfigure.data.empty.EmptyDataPackage; 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.City;
import org.springframework.boot.autoconfigure.data.neo4j.city.CityRepository; 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.boot.test.util.EnvironmentTestUtils;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -57,32 +56,27 @@ public class Neo4jRepositoriesAutoConfigurationTests { ...@@ -57,32 +56,27 @@ public class Neo4jRepositoriesAutoConfigurationTests {
@Test @Test
public void testDefaultRepositoryConfiguration() throws Exception { public void testDefaultRepositoryConfiguration() throws Exception {
prepareApplicationContext(TestConfiguration.class); prepareApplicationContext(TestConfiguration.class);
assertThat(this.context.getBean(CityRepository.class)).isNotNull(); assertThat(this.context.getBean(CityRepository.class)).isNotNull();
Neo4jMappingContext mappingContext = this.context Neo4jMappingContext mappingContext = this.context
.getBean(Neo4jMappingContext.class); .getBean(Neo4jMappingContext.class);
assertThat(mappingContext.getPersistentEntity(City.class)).isNotNull(); assertThat(mappingContext.getPersistentEntity(City.class)).isNotNull();
} }
@Test @Test
public void testNoRepositoryConfiguration() throws Exception { public void testNoRepositoryConfiguration() throws Exception {
prepareApplicationContext(EmptyConfiguration.class); prepareApplicationContext(EmptyConfiguration.class);
assertThat(this.context.getBean(SessionFactory.class)).isNotNull(); assertThat(this.context.getBean(SessionFactory.class)).isNotNull();
} }
@Test @Test
public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() {
prepareApplicationContext(CustomizedConfiguration.class); prepareApplicationContext(CustomizedConfiguration.class);
assertThat(this.context.getBean(CityNeo4jRepository.class)).isNotNull(); assertThat(this.context.getBean(CityNeo4jRepository.class)).isNotNull();
} }
@Test(expected = NoSuchBeanDefinitionException.class) @Test(expected = NoSuchBeanDefinitionException.class)
public void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() { public void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() {
prepareApplicationContext(SortOfInvalidCustomConfiguration.class); prepareApplicationContext(SortOfInvalidCustomConfiguration.class);
this.context.getBean(CityRepository.class); this.context.getBean(CityRepository.class);
} }
...@@ -91,7 +85,8 @@ public class Neo4jRepositoriesAutoConfigurationTests { ...@@ -91,7 +85,8 @@ public class Neo4jRepositoriesAutoConfigurationTests {
EnvironmentTestUtils.addEnvironment(this.context, EnvironmentTestUtils.addEnvironment(this.context,
"spring.data.neo4j.uri=http://localhost:9797"); "spring.data.neo4j.uri=http://localhost:9797");
this.context.register(configurationClasses); this.context.register(configurationClasses);
this.context.register(Neo4jAutoConfiguration.class, this.context.register(Neo4jDataAutoConfiguration.class,
Neo4jDataAutoConfiguration.class,
Neo4jRepositoriesAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class); PropertyPlaceholderAutoConfiguration.class);
this.context.refresh(); this.context.refresh();
......
...@@ -14,7 +14,8 @@ ...@@ -14,7 +14,8 @@
* limitations under the License. * limitations under the License.
*/ */
/** package org.springframework.boot.autoconfigure.data.neo4j.empty;
* Neo4j support classes.
*/ public class EmptyMarker {
package org.springframework.boot.neo4j;
}
/*
* 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.domain;
import java.util.Collection;
import java.util.Collections;
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.Configuration;
import org.springframework.core.annotation.AnnotationConfigurationException;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link EntityScanPackages}.
*
* @author Phillip Webb
*/
public class EntityScanPackagesTests {
private AnnotationConfigApplicationContext context;
@Rule
public ExpectedException thrown = ExpectedException.none();
@After
public void cleanup() {
if (this.context != null) {
this.context.close();
}
}
@Test
public void getWhenNoneRegisteredShouldReturnNone() throws Exception {
this.context = new AnnotationConfigApplicationContext();
this.context.refresh();
EntityScanPackages packages = EntityScanPackages.get(this.context);
assertThat(packages).isNotNull();
assertThat(packages.getPackageNames()).isEmpty();
}
@Test
public void getShouldReturnRegisterPackages() throws Exception {
this.context = new AnnotationConfigApplicationContext();
EntityScanPackages.register(this.context, "a", "b");
EntityScanPackages.register(this.context, "b", "c");
this.context.refresh();
EntityScanPackages packages = EntityScanPackages.get(this.context);
assertThat(packages.getPackageNames()).containsExactly("a", "b", "c");
}
@Test
public void registerFromArrayWhenRegistryIsNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Registry must not be null");
EntityScanPackages.register(null);
}
@Test
public void registerFromArrayWhenPackageNamesIsNullShouldThrowException()
throws Exception {
this.context = new AnnotationConfigApplicationContext();
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("PackageNames must not be null");
EntityScanPackages.register(this.context, (String[]) null);
}
@Test
public void registerFromCollectionWhenRegistryIsNullShouldThrowException()
throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Registry must not be null");
EntityScanPackages.register(null, Collections.<String>emptyList());
}
@Test
public void registerFromCollectionWhenPackageNamesIsNullShouldThrowException()
throws Exception {
this.context = new AnnotationConfigApplicationContext();
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("PackageNames must not be null");
EntityScanPackages.register(this.context, (Collection<String>) null);
}
@Test
public void entityScanAnnotationWhenHasValueAttributeShouldSetupPackages()
throws Exception {
this.context = new AnnotationConfigApplicationContext(
EntityScanValueConfig.class);
EntityScanPackages packages = EntityScanPackages.get(this.context);
assertThat(packages.getPackageNames()).containsExactly("a");
}
@Test
public void entityScanAnnotationWhenHasBasePackagesAttributeShouldSetupPackages()
throws Exception {
this.context = new AnnotationConfigApplicationContext(
EntityScanBasePackagesConfig.class);
EntityScanPackages packages = EntityScanPackages.get(this.context);
assertThat(packages.getPackageNames()).containsExactly("b");
}
@Test
public void entityScanAnnotationWhenHasValueAndBasePackagesAttributeShouldThrow()
throws Exception {
this.thrown.expect(AnnotationConfigurationException.class);
this.context = new AnnotationConfigApplicationContext(
EntityScanValueAndBasePackagesConfig.class);
}
@Test
public void entityScanAnnotationWhenHasBasePackageClassesAttributeShouldSetupPackages()
throws Exception {
this.context = new AnnotationConfigApplicationContext(
EntityScanBasePackageClassesConfig.class);
EntityScanPackages packages = EntityScanPackages.get(this.context);
assertThat(packages.getPackageNames())
.containsExactly(getClass().getPackage().getName());
}
@Test
public void entityScanAnnotationWhenNoAttributesShouldSetupPackages()
throws Exception {
this.context = new AnnotationConfigApplicationContext(
EntityScanNoAttributesConfig.class);
EntityScanPackages packages = EntityScanPackages.get(this.context);
assertThat(packages.getPackageNames())
.containsExactly(getClass().getPackage().getName());
}
@Test
public void entityScanAnnotationWhenLoadingFromMultipleConfigsShouldCombinePackages()
throws Exception {
this.context = new AnnotationConfigApplicationContext(EntityScanValueConfig.class,
EntityScanBasePackagesConfig.class);
EntityScanPackages packages = EntityScanPackages.get(this.context);
assertThat(packages.getPackageNames()).containsExactly("a", "b");
}
@Configuration
@EntityScan("a")
static class EntityScanValueConfig {
}
@Configuration
@EntityScan(basePackages = "b")
static class EntityScanBasePackagesConfig {
}
@Configuration
@EntityScan(value = "a", basePackages = "b")
static class EntityScanValueAndBasePackagesConfig {
}
@Configuration
@EntityScan(basePackageClasses = EntityScanPackagesTests.class)
static class EntityScanBasePackageClassesConfig {
}
@Configuration
@EntityScan
static class EntityScanNoAttributesConfig {
}
}
/*
* 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.domain;
import java.util.Set;
import javax.persistence.Embeddable;
import javax.persistence.Entity;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.springframework.boot.autoconfigure.domain.scan.a.EmbeddableA;
import org.springframework.boot.autoconfigure.domain.scan.a.EntityA;
import org.springframework.boot.autoconfigure.domain.scan.b.EmbeddableB;
import org.springframework.boot.autoconfigure.domain.scan.b.EntityB;
import org.springframework.boot.autoconfigure.domain.scan.c.EmbeddableC;
import org.springframework.boot.autoconfigure.domain.scan.c.EntityC;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Tests for {@link EntityScanner}.
*
* @author Phillip Webb
*/
public class EntityScannerTests {
@Rule
public ExpectedException thrown = ExpectedException.none();
@Test
public void createWhenContextIsNullShouldThrowException() throws Exception {
this.thrown.expect(IllegalArgumentException.class);
this.thrown.expectMessage("Context must not be null");
new EntityScanner(null);
}
@Test
public void scanShouldScanFromSinglePackage() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
ScanConfig.class);
EntityScanner scanner = new EntityScanner(context);
Set<Class<?>> scanned = scanner.scan(Entity.class);
assertThat(scanned).containsOnly(EntityA.class, EntityB.class, EntityC.class);
context.close();
}
@Test
public void scanShouldScanFromMultiplePackages() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
ScanAConfig.class, ScanBConfig.class);
EntityScanner scanner = new EntityScanner(context);
Set<Class<?>> scanned = scanner.scan(Entity.class);
assertThat(scanned).containsOnly(EntityA.class, EntityB.class);
context.close();
}
@Test
public void scanShouldFilterOnAnnotation() throws Exception {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
ScanConfig.class);
EntityScanner scanner = new EntityScanner(context);
assertThat(scanner.scan(Entity.class)).containsOnly(EntityA.class, EntityB.class,
EntityC.class);
assertThat(scanner.scan(Embeddable.class)).containsOnly(EmbeddableA.class,
EmbeddableB.class, EmbeddableC.class);
assertThat(scanner.scan(Entity.class, Embeddable.class)).containsOnly(
EntityA.class, EntityB.class, EntityC.class, EmbeddableA.class,
EmbeddableB.class, EmbeddableC.class);
context.close();
}
@Configuration
@EntityScan("org.springframework.boot.autoconfigure.domain.scan")
static class ScanConfig {
}
@Configuration
@EntityScan(basePackageClasses = EntityA.class)
static class ScanAConfig {
}
@Configuration
@EntityScan(basePackageClasses = EntityB.class)
static class ScanBConfig {
}
}
...@@ -14,34 +14,11 @@ ...@@ -14,34 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.context.scan; package org.springframework.boot.autoconfigure.domain.scan.a;
import java.lang.annotation.Documented; import javax.persistence.Embeddable;
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; @Embeddable
import org.springframework.core.annotation.AliasFor; public class EmbeddableA {
/**
* EntityScan test annotation.
*
* @author Stephane Nicoll
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(TestEntityScanRegistrar.class)
public @interface TestEntityScan {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
} }
...@@ -14,7 +14,11 @@ ...@@ -14,7 +14,11 @@
* limitations under the License. * limitations under the License.
*/ */
/** package org.springframework.boot.autoconfigure.domain.scan.a;
* Auto-configuration for Neo4j.
*/ import javax.persistence.Entity;
package org.springframework.boot.autoconfigure.neo4j;
@Entity
public class EntityA {
}
/*
* 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.domain.scan.b;
import javax.persistence.Embeddable;
@Embeddable
public class EmbeddableB {
}
/*
* 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.domain.scan.b;
import javax.persistence.Entity;
@Entity
public class EntityB {
}
/*
* 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.domain.scan.c;
import javax.persistence.Embeddable;
@Embeddable
public class EmbeddableC {
}
/*
* 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.domain.scan.c;
import javax.persistence.Entity;
@Entity
public class EntityC {
}
...@@ -97,7 +97,7 @@ public class MongoAutoConfigurationTests { ...@@ -97,7 +97,7 @@ public class MongoAutoConfigurationTests {
} }
@Configuration @Configuration
protected static class OptionsConfig { static class OptionsConfig {
@Bean @Bean
public MongoClientOptions mongoOptions() { public MongoClientOptions mongoOptions() {
...@@ -107,7 +107,7 @@ public class MongoAutoConfigurationTests { ...@@ -107,7 +107,7 @@ public class MongoAutoConfigurationTests {
} }
@Configuration @Configuration
protected static class SslOptionsConfig { static class SslOptionsConfig {
@Bean @Bean
public MongoClientOptions mongoClientOptions() { public MongoClientOptions mongoClientOptions() {
......
/*
* 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 org.junit.After;
import org.junit.Test;
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.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 can't use the embedded driver as we use
* lucene 4 and Neo4j still requires 3.
*
* @author Stephane Nicoll
* @author Michael Hunger
* @author Vince Bickers
*/
public class Neo4jAutoConfigurationTests {
private AnnotationConfigApplicationContext context;
@After
public void close() {
if (this.context != null) {
this.context.close();
}
}
@Test
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;
}
}
}
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
package org.springframework.boot.autoconfigure.security.user; package org.springframework.boot.autoconfigure.security.user;
import org.springframework.boot.orm.jpa.EntityScan; import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
......
/*
* 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 Phillip Webb
* @author Oliver Gierke
* @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;
}
}
/*
* 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.");
}
}
}
/*
* 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 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);
}
}
...@@ -43,11 +43,14 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; ...@@ -43,11 +43,14 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
* annotation. * annotation.
* *
* @author Phillip Webb * @author Phillip Webb
* @deprecated as of 1.4 in favor of explicit configuration or
* {@code @org.springframework.boot.autoconfigure.domain.EntityScan}
*/ */
@Target(ElementType.TYPE) @Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@Documented @Documented
@Import(JpaEntityScanRegistrar.class) @Import(EntityScanRegistrar.class)
@Deprecated
public @interface EntityScan { public @interface EntityScan {
/** /**
......
/* /*
* Copyright 2012-2016 the original author or authors. * Copyright 2012-2015 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -14,68 +14,45 @@ ...@@ -14,68 +14,45 @@
* limitations under the License. * limitations under the License.
*/ */
package org.springframework.boot.context.scan; package org.springframework.boot.orm.jpa;
import java.lang.annotation.Annotation;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.Set; 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.BeanDefinition;
import org.springframework.beans.factory.config.ConstructorArgumentValues; import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata; 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.ClassUtils;
/** /**
* A base {@link ImportBeanDefinitionRegistrar} used to collect the packages to scan for a * {@link ImportBeanDefinitionRegistrar} used by {@link EntityScan}.
* 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 Phillip Webb
* @author Oliver Gierke * @author Oliver Gierke
* @author Stephane Nicoll * @deprecated as of 1.4 along with {@link EntityScan}
* @since 1.4.0
* @see AbstractEntityScanBeanPostProcessor
*/ */
public abstract class AbstractEntityScanRegistrar @Deprecated
implements ImportBeanDefinitionRegistrar { class EntityScanRegistrar implements ImportBeanDefinitionRegistrar {
private final Class<? extends Annotation> annotationType; private static final String BEAN_NAME = "entityScanBeanPostProcessor";
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;
}
@Override @Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) { BeanDefinitionRegistry registry) {
Set<String> packagesToScan = getPackagesToScan(importingClassMetadata); Set<String> packagesToScan = getPackagesToScan(importingClassMetadata);
if (!registry.containsBeanDefinition(this.beanPostProcessorName)) { if (!registry.containsBeanDefinition(BEAN_NAME)) {
addEntityScanBeanPostProcessor(registry, packagesToScan); addEntityScanBeanPostProcessor(registry, packagesToScan);
} }
else { else {
...@@ -83,9 +60,9 @@ public abstract class AbstractEntityScanRegistrar ...@@ -83,9 +60,9 @@ public abstract class AbstractEntityScanRegistrar
} }
} }
protected Set<String> getPackagesToScan(AnnotationMetadata metadata) { private Set<String> getPackagesToScan(AnnotationMetadata metadata) {
AnnotationAttributes attributes = AnnotationAttributes AnnotationAttributes attributes = AnnotationAttributes
.fromMap(metadata.getAnnotationAttributes(this.annotationType.getName())); .fromMap(metadata.getAnnotationAttributes(EntityScan.class.getName()));
String[] basePackages = attributes.getStringArray("basePackages"); String[] basePackages = attributes.getStringArray("basePackages");
Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses"); Class<?>[] basePackageClasses = attributes.getClassArray("basePackageClasses");
Set<String> packagesToScan = new LinkedHashSet<String>(); Set<String> packagesToScan = new LinkedHashSet<String>();
...@@ -103,22 +80,21 @@ public abstract class AbstractEntityScanRegistrar ...@@ -103,22 +80,21 @@ public abstract class AbstractEntityScanRegistrar
private void addEntityScanBeanPostProcessor(BeanDefinitionRegistry registry, private void addEntityScanBeanPostProcessor(BeanDefinitionRegistry registry,
Set<String> packagesToScan) { Set<String> packagesToScan) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(this.beanPostProcessorType); beanDefinition.setBeanClass(EntityScanBeanPostProcessor.class);
beanDefinition.getConstructorArgumentValues() beanDefinition.getConstructorArgumentValues()
.addGenericArgumentValue(toArray(packagesToScan)); .addGenericArgumentValue(toArray(packagesToScan));
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// We don't need this one to be post processed otherwise it can cause a // We don't need this one to be post processed otherwise it can cause a
// cascade of bean instantiation that we would rather avoid. // cascade of bean instantiation that we would rather avoid.
beanDefinition.setSynthetic(true); beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(this.beanPostProcessorName, beanDefinition); registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
} }
private void updateEntityScanBeanPostProcessor(BeanDefinitionRegistry registry, private void updateEntityScanBeanPostProcessor(BeanDefinitionRegistry registry,
Set<String> packagesToScan) { Set<String> packagesToScan) {
BeanDefinition definition = registry BeanDefinition definition = registry.getBeanDefinition(BEAN_NAME);
.getBeanDefinition(this.beanPostProcessorName); ValueHolder constructorArguments = definition.getConstructorArgumentValues()
ConstructorArgumentValues.ValueHolder constructorArguments = definition .getGenericArgumentValue(String[].class);
.getConstructorArgumentValues().getGenericArgumentValue(String[].class);
Set<String> mergedPackages = new LinkedHashSet<String>(); Set<String> mergedPackages = new LinkedHashSet<String>();
mergedPackages.addAll(Arrays.asList((String[]) constructorArguments.getValue())); mergedPackages.addAll(Arrays.asList((String[]) constructorArguments.getValue()));
mergedPackages.addAll(packagesToScan); mergedPackages.addAll(packagesToScan);
...@@ -129,4 +105,52 @@ public abstract class AbstractEntityScanRegistrar ...@@ -129,4 +105,52 @@ public abstract class AbstractEntityScanRegistrar
return set.toArray(new String[set.size()]); 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;
}
}
} }
/*
* 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.");
}
}
}
/*
* 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;
}
}
}
/*
* 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 org.springframework.core.annotation.AnnotationConfigurationException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.Matchers.containsString;
/**
* 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(AnnotationConfigurationException.class);
this.thrown.expectMessage(allOf(containsString("'value'"),
containsString("'basePackages'"), containsString("com.mycorp.entity"),
containsString("com.mycorp")));
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 {
}
}
/*
* 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;
}
}
}
...@@ -40,6 +40,7 @@ import static org.mockito.Mockito.mock; ...@@ -40,6 +40,7 @@ import static org.mockito.Mockito.mock;
* @author Phillip Webb * @author Phillip Webb
* @author Stephane Nicoll * @author Stephane Nicoll
*/ */
@Deprecated
public class EntityScanTests { public class EntityScanTests {
@Rule @Rule
...@@ -94,16 +95,19 @@ public class EntityScanTests { ...@@ -94,16 +95,19 @@ public class EntityScanTests {
} }
@EntityScan("com.mycorp.entity") @EntityScan("com.mycorp.entity")
@SuppressWarnings("deprecation")
static class ValueConfig extends BaseConfig { static class ValueConfig extends BaseConfig {
} }
@Configuration @Configuration
@EntityScan("com.mycorp.entity") @EntityScan("com.mycorp.entity")
@SuppressWarnings("deprecation")
static class MissingEntityManager { static class MissingEntityManager {
} }
@Configuration @Configuration
@EntityScan("com.mycorp.entity") @EntityScan("com.mycorp.entity")
@SuppressWarnings("deprecation")
static class BeanPostProcessorConfiguration { static class BeanPostProcessorConfiguration {
protected final EntityManagerFactory entityManagerFactory; protected final EntityManagerFactory entityManagerFactory;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment