diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/SpringApplicationHierarchyTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/SpringApplicationHierarchyTests.java index a821dc580a..c36d8bb3af 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/SpringApplicationHierarchyTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/autoconfigure/SpringApplicationHierarchyTests.java @@ -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.elasticsearch.ElasticsearchDataAutoConfiguration; 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.RedisRepositoriesAutoConfiguration; -import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.test.util.ApplicationContextTestUtils; import org.springframework.context.ConfigurableApplicationContext; @@ -64,7 +64,7 @@ public class SpringApplicationHierarchyTests { @EnableAutoConfiguration(exclude = { ElasticsearchDataAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class, CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class, - Neo4jAutoConfiguration.class, RedisAutoConfiguration.class, + Neo4jDataAutoConfiguration.class, RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class }, excludeName = { "org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration" }) public static class Child { @@ -76,7 +76,7 @@ public class SpringApplicationHierarchyTests { ElasticsearchDataAutoConfiguration.class, ElasticsearchRepositoriesAutoConfiguration.class, CassandraAutoConfiguration.class, CassandraDataAutoConfiguration.class, - Neo4jAutoConfiguration.class, RedisAutoConfiguration.class, + Neo4jDataAutoConfiguration.class, RedisAutoConfiguration.class, RedisRepositoriesAutoConfiguration.class }, excludeName = { "org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchAutoConfiguration" }) public static class Parent { diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfiguration.java index 65594fb3e2..a086da5a02 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfiguration.java @@ -16,18 +16,24 @@ package org.springframework.boot.autoconfigure.data.cassandra; +import java.util.List; + import com.datastax.driver.core.Cluster; 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.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration; import org.springframework.boot.autoconfigure.cassandra.CassandraProperties; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.domain.EntityScanPackages; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; 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.SchemaAction; import org.springframework.data.cassandra.convert.CassandraConverter; @@ -50,20 +56,32 @@ import org.springframework.data.cassandra.mapping.CassandraMappingContext; @AutoConfigureAfter(CassandraAutoConfiguration.class) public class CassandraDataAutoConfiguration { + private final BeanFactory beanFactory; + private final CassandraProperties properties; private final Cluster cluster; - public CassandraDataAutoConfiguration(CassandraProperties properties, - Cluster cluster) { + public CassandraDataAutoConfiguration(BeanFactory beanFactory, + CassandraProperties properties, Cluster cluster) { + this.beanFactory = beanFactory; this.properties = properties; this.cluster = cluster; } @Bean @ConditionalOnMissingBean - public CassandraMappingContext cassandraMapping() { - return new BasicCassandraMappingContext(); + public CassandraMappingContext cassandraMapping() throws ClassNotFoundException { + BasicCassandraMappingContext context = new BasicCassandraMappingContext(); + List 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 diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/SpringBootCouchbaseDataConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/SpringBootCouchbaseDataConfiguration.java index 22e0b363c2..7ecae7bdbd 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/SpringBootCouchbaseDataConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/couchbase/SpringBootCouchbaseDataConfiguration.java @@ -16,15 +16,21 @@ package org.springframework.boot.autoconfigure.data.couchbase; +import java.util.Set; + import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; 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.Configuration; +import org.springframework.data.annotation.Persistent; import org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration; import org.springframework.data.couchbase.config.BeanNames; import org.springframework.data.couchbase.config.CouchbaseConfigurer; 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.repository.support.IndexManager; @@ -38,12 +44,16 @@ import org.springframework.data.couchbase.repository.support.IndexManager; @ConditionalOnBean(CouchbaseConfigurer.class) class SpringBootCouchbaseDataConfiguration extends AbstractCouchbaseDataConfiguration { + private final ApplicationContext applicationContext; + private final CouchbaseDataProperties properties; private final CouchbaseConfigurer couchbaseConfigurer; - SpringBootCouchbaseDataConfiguration(CouchbaseDataProperties properties, + SpringBootCouchbaseDataConfiguration(ApplicationContext applicationContext, + CouchbaseDataProperties properties, ObjectProvider couchbaseConfigurerProvider) { + this.applicationContext = applicationContext; this.properties = properties; this.couchbaseConfigurer = couchbaseConfigurerProvider.getIfAvailable(); } @@ -58,6 +68,12 @@ class SpringBootCouchbaseDataConfiguration extends AbstractCouchbaseDataConfigur return this.properties.getConsistency(); } + @Override + protected Set> getInitialEntitySet() throws ClassNotFoundException { + return new EntityScanner(this.applicationContext).scan(Document.class, + Persistent.class); + } + @Override @ConditionalOnMissingBean(name = BeanNames.COUCHBASE_TEMPLATE) @Bean(name = BeanNames.COUCHBASE_TEMPLATE) diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java index 44fcc070a2..32544d4915 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfiguration.java @@ -17,34 +17,25 @@ package org.springframework.boot.autoconfigure.data.mongo; 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.Mongo; import com.mongodb.MongoClient; import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.beans.factory.BeanFactory; 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.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; 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.MongoProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider; 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.support.PersistenceExceptionTranslator; import org.springframework.data.annotation.Persistent; @@ -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.gridfs.GridFsTemplate; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** @@ -84,26 +74,16 @@ import org.springframework.util.StringUtils; @ConditionalOnClass({ Mongo.class, MongoTemplate.class }) @EnableConfigurationProperties(MongoProperties.class) @AutoConfigureAfter(MongoAutoConfiguration.class) -public class MongoDataAutoConfiguration implements BeanClassLoaderAware { +public class MongoDataAutoConfiguration { - private final MongoProperties properties; - - private final Environment environment; + private final ApplicationContext applicationContext; - private final ResourceLoader resourceLoader; - - private ClassLoader classLoader; + private final MongoProperties properties; - public MongoDataAutoConfiguration(MongoProperties properties, Environment environment, - ResourceLoader resourceLoader) { + public MongoDataAutoConfiguration(ApplicationContext applicationContext, + MongoProperties properties) { + this.applicationContext = applicationContext; this.properties = properties; - this.environment = environment; - this.resourceLoader = resourceLoader; - } - - @Override - public void setBeanClassLoader(ClassLoader classLoader) { - this.classLoader = classLoader; } @Bean @@ -142,7 +122,8 @@ public class MongoDataAutoConfiguration implements BeanClassLoaderAware { public MongoMappingContext mongoMappingContext(BeanFactory beanFactory) throws ClassNotFoundException { MongoMappingContext context = new MongoMappingContext(); - context.setInitialEntitySet(getInitialEntitySet(beanFactory)); + context.setInitialEntitySet(new EntityScanner(this.applicationContext) + .scan(Document.class, Persistent.class)); Class strategyClass = this.properties.getFieldNamingStrategy(); if (strategyClass != null) { context.setFieldNamingStrategy( @@ -151,37 +132,6 @@ public class MongoDataAutoConfiguration implements BeanClassLoaderAware { return context; } - private Set> getInitialEntitySet(BeanFactory beanFactory) - throws ClassNotFoundException { - Set> entitySet = new HashSet>(); - 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 getMappingBasePackages(BeanFactory beanFactory) { - try { - return AutoConfigurationPackages.get(beanFactory); - } - catch (IllegalStateException ex) { - // no auto-configuration package registered yet - return Collections.emptyList(); - } - } - @Bean @ConditionalOnMissingBean public GridFsTemplate gridFsTemplate(MongoDbFactory mongoDbFactory, diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java new file mode 100644 index 0000000000..45e9e00f99 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfiguration.java @@ -0,0 +1,103 @@ +/* + * 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.data.neo4j; + +import java.util.List; + +import org.neo4j.ogm.session.Neo4jSession; +import org.neo4j.ogm.session.Session; +import org.neo4j.ogm.session.SessionFactory; + +import org.springframework.boot.autoconfigure.AutoConfigurationPackages; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.domain.EntityScanPackages; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; +import org.springframework.data.neo4j.config.Neo4jConfiguration; +import org.springframework.data.neo4j.template.Neo4jOperations; + +/** + * {@link EnableAutoConfiguration Auto-configuration} for Spring Data Neo4j. + * + * @author Michael Hunger + * @author Josh Long + * @author Vince Bickers + * @author Stephane Nicoll + * @since 1.4.0 + */ +@Configuration +@ConditionalOnClass({ Neo4jSession.class, Neo4jOperations.class }) +@ConditionalOnMissingBean(Neo4jOperations.class) +@EnableConfigurationProperties(Neo4jProperties.class) +public class Neo4jDataAutoConfiguration { + + private final Neo4jProperties properties; + + public Neo4jDataAutoConfiguration(Neo4jProperties properties) { + this.properties = properties; + } + + @Bean + @ConditionalOnMissingBean + public org.neo4j.ogm.config.Configuration configuration() { + return this.properties.createConfiguration(); + } + + @Configuration + static class SpringBootNeo4jConfiguration extends Neo4jConfiguration { + + private final ApplicationContext applicationContext; + + private final org.neo4j.ogm.config.Configuration configuration; + + SpringBootNeo4jConfiguration(ApplicationContext applicationContext, + org.neo4j.ogm.config.Configuration configuration) { + this.applicationContext = applicationContext; + this.configuration = configuration; + } + + @Override + public SessionFactory getSessionFactory() { + return new SessionFactory(this.configuration, getPackagesToScan()); + } + + private String[] getPackagesToScan() { + List packages = EntityScanPackages.get(this.applicationContext) + .getPackageNames(); + if (packages.isEmpty() + && AutoConfigurationPackages.has(this.applicationContext)) { + packages = AutoConfigurationPackages.get(this.applicationContext); + } + return packages.toArray(new String[packages.size()]); + } + + @Override + @Bean + @Scope(scopeName = "${spring.data.neo4j.session.scope:singleton}", proxyMode = ScopedProxyMode.TARGET_CLASS) + public Session getSession() throws Exception { + return super.getSession(); + } + + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/neo4j/Neo4jProperties.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jProperties.java similarity index 98% rename from spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/neo4j/Neo4jProperties.java rename to spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jProperties.java index aa23c6c394..f85b56b83a 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/neo4j/Neo4jProperties.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jProperties.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.neo4j; +package org.springframework.boot.autoconfigure.data.neo4j; import java.net.URI; import java.net.URISyntaxException; diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java index d9131d5059..263db1d51c 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfiguration.java @@ -23,7 +23,6 @@ import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.data.neo4j.repository.GraphRepository; @@ -59,7 +58,7 @@ import org.springframework.data.neo4j.repository.support.GraphRepositoryFactoryB Neo4jRepositoryConfigurationExtension.class }) @ConditionalOnProperty(prefix = "spring.data.neo4j.repositories", name = "enabled", havingValue = "true", matchIfMissing = true) @Import(Neo4jRepositoriesAutoConfigureRegistrar.class) -@AutoConfigureAfter(Neo4jAutoConfiguration.class) +@AutoConfigureAfter(Neo4jDataAutoConfiguration.class) public class Neo4jRepositoriesAutoConfiguration { } diff --git a/spring-boot/src/main/java/org/springframework/boot/neo4j/NodeEntityScan.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScan.java similarity index 59% rename from spring-boot/src/main/java/org/springframework/boot/neo4j/NodeEntityScan.java rename to spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScan.java index 5f968f9276..48508f6135 100644 --- a/spring-boot/src/main/java/org/springframework/boot/neo4j/NodeEntityScan.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScan.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.neo4j; +package org.springframework.boot.autoconfigure.domain; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; @@ -22,49 +22,56 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; 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.core.annotation.AliasFor; /** - * Configures the {@link SessionFactory} to scan for Neo4J {@link NodeEntity} classes in - * the classpath. This annotation provides an alternative to manually setting - * {@link SessionFactoryProvider#setPackagesToScan(String...)} and is particularly useful - * if you want to configure entity scanning in a type-safe way, or if your - * {@link SessionFactory} is auto-configured. + * Configures the base packages used by auto-configuration when scanning for entity + * classes. *

- * A {@link SessionFactoryProvider} must be configured within your Spring - * ApplicationContext in order to use entity scanning. Furthermore, any existing - * {@code packagesToScan} setting will be replaced. + * Using {@code @EntityScan} will cause auto-configuration to: + *

    + *
  • Set the + * {@link org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean#setPackagesToScan(String...) + * packages scanned} for JPA entities.
  • + *
  • Set the packages used with Neo4J's {@link org.neo4j.ogm.session.SessionFactory + * SessionFactory}.
  • + *
  • 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.
  • + *
*

* One of {@link #basePackageClasses()}, {@link #basePackages()} or its alias * {@link #value()} may be specified to define specific packages to scan. If specific * packages are not defined scanning will occur from the package of the class with this * annotation. * - * @author Stephane Nicoll + * @author Phillip Webb * @since 1.4.0 + * @see EntityScanPackages */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented -@Import(NodeEntityScanRegistrar.class) -public @interface NodeEntityScan { +@Import(EntityScanPackages.Registrar.class) +public @interface EntityScan { /** * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation - * declarations e.g.: {@code @NodeEntityScan("org.my.pkg")} instead of - * {@code @NodeEntityScan(basePackages="org.my.pkg")}. + * declarations e.g.: {@code @EntityScan("org.my.pkg")} instead of + * {@code @EntityScan(basePackages="org.my.pkg")}. * @return the base packages to scan */ @AliasFor("basePackages") String[] value() default {}; /** - * Base packages to scan for node entities. {@link #value()} is an alias for (and - * mutually exclusive with) this attribute. + * Base packages to scan for entities. {@link #value()} is an alias for (and mutually + * exclusive with) this attribute. *

* Use {@link #basePackageClasses()} for a type-safe alternative to String-based * package names. @@ -75,7 +82,7 @@ public @interface NodeEntityScan { /** * 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. *

* Consider creating a special no-op marker class or interface in each package that * serves no purpose other than being referenced by this attribute. diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScanPackages.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScanPackages.java new file mode 100644 index 0000000000..9c652a1513 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScanPackages.java @@ -0,0 +1,177 @@ +/* + * 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 packageNames; + + EntityScanPackages(String... packageNames) { + List packages = new ArrayList(); + 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 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 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 packageNames) { + String[] existing = (String[]) constructorArguments + .getIndexedArgumentValue(0, String[].class).getValue(); + Set merged = new LinkedHashSet(); + 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 getPackagesToScan(AnnotationMetadata metadata) { + AnnotationAttributes attributes = AnnotationAttributes.fromMap( + metadata.getAnnotationAttributes(EntityScan.class.getName())); + String[] basePackages = attributes.getStringArray("basePackages"); + Class[] basePackageClasses = attributes + .getClassArray("basePackageClasses"); + Set packagesToScan = new LinkedHashSet(); + 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; + } + + } + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScanner.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScanner.java new file mode 100644 index 0000000000..dc1a25ecd1 --- /dev/null +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/EntityScanner.java @@ -0,0 +1,95 @@ +/* + * 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> scan(Class... annotationTypes) + throws ClassNotFoundException { + List packages = getPackages(); + if (packages.isEmpty()) { + return Collections.>emptySet(); + } + Set> entitySet = new HashSet>(); + ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider( + false); + scanner.setEnvironment(this.context.getEnvironment()); + scanner.setResourceLoader(this.context); + for (Class 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 getPackages() { + List packages = EntityScanPackages.get(this.context).getPackageNames(); + if (packages.isEmpty() && AutoConfigurationPackages.has(this.context)) { + packages = AutoConfigurationPackages.get(this.context); + } + return packages; + } + +} diff --git a/spring-boot/src/main/java/org/springframework/boot/neo4j/package-info.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/package-info.java similarity index 85% rename from spring-boot/src/main/java/org/springframework/boot/neo4j/package-info.java rename to spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/package-info.java index b588d49c29..7773c659b4 100644 --- a/spring-boot/src/main/java/org/springframework/boot/neo4j/package-info.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/domain/package-info.java @@ -15,6 +15,6 @@ */ /** - * Neo4j support classes. + * General purpose domain annotations and classes. */ -package org.springframework.boot.neo4j; +package org.springframework.boot.autoconfigure.domain; diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/neo4j/Neo4jAutoConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/neo4j/Neo4jAutoConfiguration.java deleted file mode 100644 index e22a30c366..0000000000 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/neo4j/Neo4jAutoConfiguration.java +++ /dev/null @@ -1,142 +0,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.autoconfigure.neo4j; - -import java.util.List; - -import org.neo4j.ogm.session.Neo4jSession; -import org.neo4j.ogm.session.Session; -import org.neo4j.ogm.session.SessionFactory; - -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.ObjectProvider; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.boot.autoconfigure.AutoConfigurationPackages; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; -import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; -import org.springframework.boot.context.properties.EnableConfigurationProperties; -import org.springframework.boot.neo4j.SessionFactoryProvider; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; -import org.springframework.context.annotation.Scope; -import org.springframework.context.annotation.ScopedProxyMode; -import org.springframework.data.neo4j.config.Neo4jConfiguration; -import org.springframework.data.neo4j.template.Neo4jOperations; -import org.springframework.data.neo4j.template.Neo4jTemplate; - -/** - * {@link EnableAutoConfiguration Auto-configuration} for Spring Data's Neo4j support. - *

- * Registers a {@link Neo4jTemplate} bean if no other bean of the same type is configured. - * - * @author Michael Hunger - * @author Josh Long - * @author Vince Bickers - * @author Stephane Nicoll - * @since 1.4.0 - */ -@Configuration -@ConditionalOnClass({ Neo4jSession.class, Neo4jOperations.class }) -@ConditionalOnMissingBean(Neo4jOperations.class) -@EnableConfigurationProperties(Neo4jProperties.class) -public class Neo4jAutoConfiguration { - - @Configuration - @Import(SessionFactoryProviderConfiguration.class) - public static class SpringBootNeo4jConfiguration extends Neo4jConfiguration { - - private final ObjectProvider sessionFactoryProvider; - - public SpringBootNeo4jConfiguration( - ObjectProvider sessionFactoryProvider) { - this.sessionFactoryProvider = sessionFactoryProvider; - } - - @Override - public SessionFactory getSessionFactory() { - return this.sessionFactoryProvider.getObject().getSessionFactory(); - } - - @Bean - @Scope(scopeName = "${spring.data.neo4j.session.scope:singleton}", proxyMode = ScopedProxyMode.TARGET_CLASS) - @Override - public Session getSession() throws Exception { - return getSessionFactory().openSession(); - } - - } - - @Configuration - @Import(Neo4jConfigurationConfiguration.class) - static class SessionFactoryProviderConfiguration implements BeanFactoryAware { - - private final org.neo4j.ogm.config.Configuration configuration; - - private ConfigurableListableBeanFactory beanFactory; - - SessionFactoryProviderConfiguration( - org.neo4j.ogm.config.Configuration configuration) { - this.configuration = configuration; - } - - @Bean - @ConditionalOnMissingBean - public SessionFactoryProvider sessionFactoryProvider() { - SessionFactoryProvider provider = new SessionFactoryProvider(); - provider.setConfiguration(this.configuration); - provider.setPackagesToScan(getPackagesToScan()); - return provider; - } - - @Override - public void setBeanFactory(BeanFactory beanFactory) throws BeansException { - this.beanFactory = (ConfigurableListableBeanFactory) beanFactory; - } - - protected String[] getPackagesToScan() { - if (AutoConfigurationPackages.has(this.beanFactory)) { - List basePackages = AutoConfigurationPackages - .get(this.beanFactory); - return basePackages.toArray(new String[basePackages.size()]); - } - return new String[0]; - } - - } - - @Configuration - static class Neo4jConfigurationConfiguration { - - private final Neo4jProperties properties; - - Neo4jConfigurationConfiguration(Neo4jProperties properties) { - this.properties = properties; - } - - @Bean - @ConditionalOnMissingBean - public org.neo4j.ogm.config.Configuration configuration() { - return this.properties.createConfiguration(); - } - - } - -} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java index 6763138702..67d1ccbd96 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java @@ -33,6 +33,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.boot.autoconfigure.domain.EntityScanPackages; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.orm.jpa.EntityManagerFactoryBuilder; import org.springframework.context.annotation.Bean; @@ -63,8 +64,6 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter @Import(DataSourceInitializedPublisher.Registrar.class) public abstract class JpaBaseConfiguration implements BeanFactoryAware { - private static final String[] NO_PACKAGES = new String[0]; - private final DataSource dataSource; private final JpaProperties properties; @@ -138,11 +137,12 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware { } protected String[] getPackagesToScan() { - if (AutoConfigurationPackages.has(this.beanFactory)) { - List basePackages = AutoConfigurationPackages.get(this.beanFactory); - return basePackages.toArray(new String[basePackages.size()]); + List packages = EntityScanPackages.get(this.beanFactory) + .getPackageNames(); + if (packages.isEmpty() && AutoConfigurationPackages.has(this.beanFactory)) { + packages = AutoConfigurationPackages.get(this.beanFactory); } - return NO_PACKAGES; + return packages.toArray(new String[packages.size()]); } /** diff --git a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories index 715992b162..5bf76dac0f 100644 --- a/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories +++ b/spring-boot-autoconfigure/src/main/resources/META-INF/spring.factories @@ -31,6 +31,7 @@ org.springframework.boot.autoconfigure.data.elasticsearch.ElasticsearchRepositor org.springframework.boot.autoconfigure.data.jpa.JpaRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.mongo.MongoRepositoriesAutoConfiguration,\ +org.springframework.boot.autoconfigure.data.neo4j.Neo4jDataAutoConfiguration,\ org.springframework.boot.autoconfigure.data.neo4j.Neo4jRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.solr.SolrRepositoriesAutoConfiguration,\ org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\ @@ -70,7 +71,6 @@ org.springframework.boot.autoconfigure.mobile.SitePreferenceAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.embedded.EmbeddedMongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mongo.MongoAutoConfiguration,\ org.springframework.boot.autoconfigure.mustache.MustacheAutoConfiguration,\ -org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration,\ org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration,\ org.springframework.boot.autoconfigure.reactor.ReactorAutoConfiguration,\ org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration,\ diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfigurationTests.java index d7b632c833..bd9b15fd7b 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/cassandra/CassandraDataAutoConfigurationTests.java @@ -16,18 +16,24 @@ package org.springframework.boot.autoconfigure.data.cassandra; +import java.util.Set; + import com.datastax.driver.core.Session; import org.junit.After; import org.junit.Test; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; 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.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; 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.mockito.Mockito.mock; @@ -59,6 +65,21 @@ public class CassandraDataAutoConfigurationTests { .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> initialEntitySet = (Set>) ReflectionTestUtils + .getField(mappingContext, "initialEntitySet"); + assertThat(initialEntitySet).containsOnly(City.class); + } + @Configuration @ComponentScan(excludeFilters = @ComponentScan.Filter(classes = { Session.class }, type = FilterType.ASSIGNABLE_TYPE)) @@ -76,4 +97,10 @@ public class CassandraDataAutoConfigurationTests { } + @Configuration + @EntityScan("org.springframework.boot.autoconfigure.data.cassandra.city") + static class EntityScanConfig { + + } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java index a1752256d6..b379ad6274 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/couchbase/CouchbaseDataAutoConfigurationTests.java @@ -16,6 +16,8 @@ package org.springframework.boot.autoconfigure.data.couchbase; +import java.util.Set; + import javax.validation.Validator; import org.junit.After; @@ -25,6 +27,8 @@ import org.springframework.beans.DirectFieldAccessor; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.couchbase.CouchbaseAutoConfiguration; 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.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; @@ -33,9 +37,11 @@ import org.springframework.context.annotation.Import; import org.springframework.data.couchbase.config.AbstractCouchbaseDataConfiguration; import org.springframework.data.couchbase.config.CouchbaseConfigurer; 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.query.Consistency; 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.mockito.Mockito.mock; @@ -108,6 +114,17 @@ public class CouchbaseDataAutoConfigurationTests { .isEqualTo(Consistency.EVENTUALLY_CONSISTENT); } + @Test + @SuppressWarnings("unchecked") + public void entityScanShouldSetInitialEntitySet() throws Exception { + load(EntityScanConfig.class); + CouchbaseMappingContext mappingContext = this.context + .getBean(CouchbaseMappingContext.class); + Set> initialEntitySet = (Set>) ReflectionTestUtils + .getField(mappingContext, "initialEntitySet"); + assertThat(initialEntitySet).containsOnly(City.class); + } + private void load(Class config, String... environment) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); EnvironmentTestUtils.addEnvironment(context, environment); @@ -146,4 +163,11 @@ public class CouchbaseDataAutoConfigurationTests { } + @Configuration + @EntityScan("org.springframework.boot.autoconfigure.data.couchbase.city") + @Import(CustomCouchbaseConfiguration.class) + static class EntityScanConfig { + + } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MixedMongoRepositoriesAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MixedMongoRepositoriesAutoConfigurationTests.java index c3b5155d9a..efc6fe60d0 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MixedMongoRepositoriesAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MixedMongoRepositoriesAutoConfigurationTests.java @@ -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.mongo.country.Country; 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.mongo.MongoAutoConfiguration; import org.springframework.boot.autoconfigure.mongo.MongoAutoConfigurationTests; 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.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Configuration; @@ -80,6 +80,19 @@ public class MixedMongoRepositoriesAutoConfigurationTests { 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 public void testJpaRepositoryConfigurationWithMongoTemplate() throws Exception { this.context = new AnnotationConfigApplicationContext(); @@ -90,6 +103,18 @@ public class MixedMongoRepositoriesAutoConfigurationTests { 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 public void testJpaRepositoryConfigurationWithMongoOverlap() throws Exception { this.context = new AnnotationConfigApplicationContext(); @@ -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 // Mongo will try and configure the same repositories @Configuration diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java index 3dec3e1f57..1f2349e119 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/mongo/MongoDataAutoConfigurationTests.java @@ -30,6 +30,8 @@ import org.springframework.beans.factory.UnsatisfiedDependencyException; import org.springframework.boot.autoconfigure.AutoConfigurationPackages; import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; 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.test.util.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -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> initialEntitySet = (Set>) ReflectionTestUtils + .getField(mappingContext, "initialEntitySet"); + assertThat(initialEntitySet).containsOnly(City.class, Country.class); + } + public void testFieldNamingStrategy(String strategy, Class expectedType) { this.context = new AnnotationConfigApplicationContext(); @@ -173,6 +190,12 @@ public class MongoDataAutoConfigurationTests { } } + @Configuration + @EntityScan("org.springframework.boot.autoconfigure.data.mongo") + static class EntityScanConfig { + + } + private static class MyConverter implements Converter { @Override diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java index f3cd0c4712..327fdfe078 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/MixedNeo4jRepositoriesAutoConfigurationTests.java @@ -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.neo4j.country.Country; 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.neo4j.Neo4jAutoConfiguration; -import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfigurationTests; import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; -import org.springframework.boot.orm.jpa.EntityScan; import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Configuration; @@ -113,7 +112,7 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests { } @Configuration - @TestAutoConfigurationPackage(Neo4jAutoConfigurationTests.class) + @TestAutoConfigurationPackage(EmptyMarker.class) // Not this package or its parent @EnableNeo4jRepositories(basePackageClasses = Country.class) protected static class TestConfiguration { @@ -121,7 +120,7 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests { } @Configuration - @TestAutoConfigurationPackage(Neo4jAutoConfigurationTests.class) + @TestAutoConfigurationPackage(EmptyMarker.class) @EnableNeo4jRepositories(basePackageClasses = Country.class) @EntityScan(basePackageClasses = City.class) @EnableJpaRepositories(basePackageClasses = CityRepository.class) @@ -130,7 +129,7 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests { } @Configuration - @TestAutoConfigurationPackage(Neo4jAutoConfigurationTests.class) + @TestAutoConfigurationPackage(EmptyMarker.class) @EntityScan(basePackageClasses = City.class) @EnableJpaRepositories(basePackageClasses = CityRepository.class) protected static class JpaConfiguration { @@ -159,7 +158,8 @@ public class MixedNeo4jRepositoriesAutoConfigurationTests { List names = new ArrayList(); for (Class type : new Class[] { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, - JpaRepositoriesAutoConfiguration.class, Neo4jAutoConfiguration.class, + JpaRepositoriesAutoConfiguration.class, + Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class }) { names.add(type.getName()); } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java index 9aa3e52075..e4cb81a0eb 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jDataAutoConfigurationTests.java @@ -21,18 +21,29 @@ import org.junit.After; import org.junit.Rule; import org.junit.Test; 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.PropertyPlaceholderAutoConfiguration; 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.Bean; +import org.springframework.context.annotation.Configuration; 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 Oliver Gierke + * @author Stephane Nicoll + * @author Michael Hunger * @author Vince Bickers */ public class Neo4jDataAutoConfigurationTests { @@ -40,23 +51,79 @@ public class Neo4jDataAutoConfigurationTests { @Rule public final ExpectedException thrown = ExpectedException.none(); - private AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); + private AnnotationConfigApplicationContext context; @After 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 public void usesAutoConfigurationPackageToPickUpDomainTypes() { + this.context = new AnnotationConfigApplicationContext(); String cityPackage = City.class.getPackage().getName(); AutoConfigurationPackages.register(this.context, cityPackage); - this.context.register(Neo4jAutoConfiguration.class); + this.context.register(Neo4jDataAutoConfiguration.class); this.context.refresh(); assertDomainTypesDiscovered(this.context.getBean(Neo4jMappingContext.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, Class... types) { for (Class type : types) { @@ -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; + } + + } + } diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/neo4j/Neo4jPropertiesTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jPropertiesTests.java similarity index 99% rename from spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/neo4j/Neo4jPropertiesTests.java rename to spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jPropertiesTests.java index d4e5edc65d..5e87643512 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/neo4j/Neo4jPropertiesTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jPropertiesTests.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.springframework.boot.autoconfigure.neo4j; +package org.springframework.boot.autoconfigure.data.neo4j; import java.net.URL; import java.net.URLClassLoader; diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java index 80e46f0f64..bfa3470470 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/Neo4jRepositoriesAutoConfigurationTests.java @@ -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.neo4j.city.City; import org.springframework.boot.autoconfigure.data.neo4j.city.CityRepository; -import org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration; import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Configuration; @@ -57,32 +56,27 @@ public class Neo4jRepositoriesAutoConfigurationTests { @Test public void testDefaultRepositoryConfiguration() throws Exception { prepareApplicationContext(TestConfiguration.class); - assertThat(this.context.getBean(CityRepository.class)).isNotNull(); Neo4jMappingContext mappingContext = this.context .getBean(Neo4jMappingContext.class); assertThat(mappingContext.getPersistentEntity(City.class)).isNotNull(); - } @Test public void testNoRepositoryConfiguration() throws Exception { prepareApplicationContext(EmptyConfiguration.class); - assertThat(this.context.getBean(SessionFactory.class)).isNotNull(); } @Test public void doesNotTriggerDefaultRepositoryDetectionIfCustomized() { prepareApplicationContext(CustomizedConfiguration.class); - assertThat(this.context.getBean(CityNeo4jRepository.class)).isNotNull(); } @Test(expected = NoSuchBeanDefinitionException.class) public void autoConfigurationShouldNotKickInEvenIfManualConfigDidNotCreateAnyRepositories() { prepareApplicationContext(SortOfInvalidCustomConfiguration.class); - this.context.getBean(CityRepository.class); } @@ -91,7 +85,8 @@ public class Neo4jRepositoriesAutoConfigurationTests { EnvironmentTestUtils.addEnvironment(this.context, "spring.data.neo4j.uri=http://localhost:9797"); this.context.register(configurationClasses); - this.context.register(Neo4jAutoConfiguration.class, + this.context.register(Neo4jDataAutoConfiguration.class, + Neo4jDataAutoConfiguration.class, Neo4jRepositoriesAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class); this.context.refresh(); diff --git a/spring-boot/src/main/java/org/springframework/boot/context/scan/package-info.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/empty/EmptyMarker.java similarity index 86% rename from spring-boot/src/main/java/org/springframework/boot/context/scan/package-info.java rename to spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/empty/EmptyMarker.java index c6a135a597..9e576fb51f 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/scan/package-info.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/data/neo4j/empty/EmptyMarker.java @@ -14,7 +14,8 @@ * limitations under the License. */ -/** - * Support for component scanning. - */ -package org.springframework.boot.context.scan; +package org.springframework.boot.autoconfigure.data.neo4j.empty; + +public class EmptyMarker { + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/EntityScanPackagesTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/EntityScanPackagesTests.java new file mode 100644 index 0000000000..0310919982 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/EntityScanPackagesTests.java @@ -0,0 +1,191 @@ +/* + * 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.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) 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 { + + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/EntityScannerTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/EntityScannerTests.java new file mode 100644 index 0000000000..f3e899458d --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/EntityScannerTests.java @@ -0,0 +1,109 @@ +/* + * 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> 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> 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 { + + } + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/a/EmbeddableA.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/a/EmbeddableA.java new file mode 100644 index 0000000000..fa31fda6b8 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/a/EmbeddableA.java @@ -0,0 +1,24 @@ +/* + * 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.a; + +import javax.persistence.Embeddable; + +@Embeddable +public class EmbeddableA { + +} diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/neo4j/package-info.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/a/EntityA.java similarity index 82% rename from spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/neo4j/package-info.java rename to spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/a/EntityA.java index e53e6c5214..f4966aaf16 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/neo4j/package-info.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/a/EntityA.java @@ -14,7 +14,11 @@ * limitations under the License. */ -/** - * Auto-configuration for Neo4j. - */ -package org.springframework.boot.autoconfigure.neo4j; +package org.springframework.boot.autoconfigure.domain.scan.a; + +import javax.persistence.Entity; + +@Entity +public class EntityA { + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/b/EmbeddableB.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/b/EmbeddableB.java new file mode 100644 index 0000000000..0dd49e9f2e --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/b/EmbeddableB.java @@ -0,0 +1,24 @@ +/* + * 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 { + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/b/EntityB.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/b/EntityB.java new file mode 100644 index 0000000000..22fd9cbb65 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/b/EntityB.java @@ -0,0 +1,24 @@ +/* + * 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 { + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/c/EmbeddableC.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/c/EmbeddableC.java new file mode 100644 index 0000000000..f2581882dd --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/c/EmbeddableC.java @@ -0,0 +1,24 @@ +/* + * 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 { + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/c/EntityC.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/c/EntityC.java new file mode 100644 index 0000000000..a1678a3024 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/domain/scan/c/EntityC.java @@ -0,0 +1,24 @@ +/* + * 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 { + +} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java index 9307714b15..85bc2ee0a7 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/mongo/MongoAutoConfigurationTests.java @@ -97,7 +97,7 @@ public class MongoAutoConfigurationTests { } @Configuration - protected static class OptionsConfig { + static class OptionsConfig { @Bean public MongoClientOptions mongoOptions() { @@ -107,7 +107,7 @@ public class MongoAutoConfigurationTests { } @Configuration - protected static class SslOptionsConfig { + static class SslOptionsConfig { @Bean public MongoClientOptions mongoClientOptions() { diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/neo4j/Neo4jAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/neo4j/Neo4jAutoConfigurationTests.java deleted file mode 100644 index 990fe6f64a..0000000000 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/neo4j/Neo4jAutoConfigurationTests.java +++ /dev/null @@ -1,130 +0,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.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; - } - - } - -} diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/user/SecurityConfig.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/user/SecurityConfig.java index d4379f6652..37539e8a6d 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/user/SecurityConfig.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/security/user/SecurityConfig.java @@ -16,7 +16,7 @@ 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.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; diff --git a/spring-boot/src/main/java/org/springframework/boot/context/scan/AbstractEntityScanBeanPostProcessor.java b/spring-boot/src/main/java/org/springframework/boot/context/scan/AbstractEntityScanBeanPostProcessor.java deleted file mode 100644 index 7642f66df8..0000000000 --- a/spring-boot/src/main/java/org/springframework/boot/context/scan/AbstractEntityScanBeanPostProcessor.java +++ /dev/null @@ -1,62 +0,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.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; - } - -} diff --git a/spring-boot/src/main/java/org/springframework/boot/neo4j/NodeEntityScanRegistrar.java b/spring-boot/src/main/java/org/springframework/boot/neo4j/NodeEntityScanRegistrar.java deleted file mode 100644 index aaa6b6cf5d..0000000000 --- a/spring-boot/src/main/java/org/springframework/boot/neo4j/NodeEntityScanRegistrar.java +++ /dev/null @@ -1,74 +0,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."); - } - - } - -} diff --git a/spring-boot/src/main/java/org/springframework/boot/neo4j/SessionFactoryProvider.java b/spring-boot/src/main/java/org/springframework/boot/neo4j/SessionFactoryProvider.java deleted file mode 100644 index 19232849e5..0000000000 --- a/spring-boot/src/main/java/org/springframework/boot/neo4j/SessionFactoryProvider.java +++ /dev/null @@ -1,56 +0,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.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); - } - -} diff --git a/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityScan.java b/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityScan.java index 5b53de003c..a5c6cef09b 100644 --- a/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityScan.java +++ b/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityScan.java @@ -43,11 +43,14 @@ import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; * annotation. * * @author Phillip Webb + * @deprecated as of 1.4 in favor of explicit configuration or + * {@code @org.springframework.boot.autoconfigure.domain.EntityScan} */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented -@Import(JpaEntityScanRegistrar.class) +@Import(EntityScanRegistrar.class) +@Deprecated public @interface EntityScan { /** diff --git a/spring-boot/src/main/java/org/springframework/boot/context/scan/AbstractEntityScanRegistrar.java b/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityScanRegistrar.java similarity index 55% rename from spring-boot/src/main/java/org/springframework/boot/context/scan/AbstractEntityScanRegistrar.java rename to spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityScanRegistrar.java index 61d026867c..ba7f04513c 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/scan/AbstractEntityScanRegistrar.java +++ b/spring-boot/src/main/java/org/springframework/boot/orm/jpa/EntityScanRegistrar.java @@ -1,5 +1,5 @@ /* - * 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"); * you may not use this file except in compliance with the License. @@ -14,68 +14,45 @@ * 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.Collections; import java.util.LinkedHashSet; import java.util.Set; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.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.GenericBeanDefinition; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.type.AnnotationMetadata; +import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; +import org.springframework.util.Assert; import org.springframework.util.ClassUtils; /** - * A baseĀ {@link ImportBeanDefinitionRegistrar} used to collect the packages to scan for a - * given component. - *

- * 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}. - *

- * The {@link ImportBeanDefinitionRegistrar} registers a single - * {@link AbstractEntityScanBeanPostProcessor} implementation with the packages to use. + * {@link ImportBeanDefinitionRegistrar} used by {@link EntityScan}. * * @author Phillip Webb * @author Oliver Gierke - * @author Stephane Nicoll - * @since 1.4.0 - * @see AbstractEntityScanBeanPostProcessor + * @deprecated as of 1.4 along with {@link EntityScan} */ -public abstract class AbstractEntityScanRegistrar - implements ImportBeanDefinitionRegistrar { +@Deprecated +class EntityScanRegistrar implements ImportBeanDefinitionRegistrar { - private final Class annotationType; - - private final String beanPostProcessorName; - - private final Class 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 annotationType, - String beanPostProcessorName, - Class beanPostProcessorType) { - this.beanPostProcessorName = beanPostProcessorName; - this.annotationType = annotationType; - this.beanPostProcessorType = beanPostProcessorType; - } + private static final String BEAN_NAME = "entityScanBeanPostProcessor"; @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { Set packagesToScan = getPackagesToScan(importingClassMetadata); - if (!registry.containsBeanDefinition(this.beanPostProcessorName)) { + if (!registry.containsBeanDefinition(BEAN_NAME)) { addEntityScanBeanPostProcessor(registry, packagesToScan); } else { @@ -83,9 +60,9 @@ public abstract class AbstractEntityScanRegistrar } } - protected Set getPackagesToScan(AnnotationMetadata metadata) { + private Set getPackagesToScan(AnnotationMetadata metadata) { AnnotationAttributes attributes = AnnotationAttributes - .fromMap(metadata.getAnnotationAttributes(this.annotationType.getName())); + .fromMap(metadata.getAnnotationAttributes(EntityScan.class.getName())); String[] basePackages = attributes.getStringArray("basePackages"); Class[] basePackageClasses = attributes.getClassArray("basePackageClasses"); Set packagesToScan = new LinkedHashSet(); @@ -103,22 +80,21 @@ public abstract class AbstractEntityScanRegistrar private void addEntityScanBeanPostProcessor(BeanDefinitionRegistry registry, Set packagesToScan) { GenericBeanDefinition beanDefinition = new GenericBeanDefinition(); - beanDefinition.setBeanClass(this.beanPostProcessorType); + beanDefinition.setBeanClass(EntityScanBeanPostProcessor.class); beanDefinition.getConstructorArgumentValues() .addGenericArgumentValue(toArray(packagesToScan)); beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); // We don't need this one to be post processed otherwise it can cause a // cascade of bean instantiation that we would rather avoid. beanDefinition.setSynthetic(true); - registry.registerBeanDefinition(this.beanPostProcessorName, beanDefinition); + registry.registerBeanDefinition(BEAN_NAME, beanDefinition); } private void updateEntityScanBeanPostProcessor(BeanDefinitionRegistry registry, Set packagesToScan) { - BeanDefinition definition = registry - .getBeanDefinition(this.beanPostProcessorName); - ConstructorArgumentValues.ValueHolder constructorArguments = definition - .getConstructorArgumentValues().getGenericArgumentValue(String[].class); + BeanDefinition definition = registry.getBeanDefinition(BEAN_NAME); + ValueHolder constructorArguments = definition.getConstructorArgumentValues() + .getGenericArgumentValue(String[].class); Set mergedPackages = new LinkedHashSet(); mergedPackages.addAll(Arrays.asList((String[]) constructorArguments.getValue())); mergedPackages.addAll(packagesToScan); @@ -129,4 +105,52 @@ public abstract class AbstractEntityScanRegistrar 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; + } + + } + } diff --git a/spring-boot/src/main/java/org/springframework/boot/orm/jpa/JpaEntityScanRegistrar.java b/spring-boot/src/main/java/org/springframework/boot/orm/jpa/JpaEntityScanRegistrar.java deleted file mode 100644 index d7d9ccdeee..0000000000 --- a/spring-boot/src/main/java/org/springframework/boot/orm/jpa/JpaEntityScanRegistrar.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2012-2015 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.boot.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."); - } - - } - -} diff --git a/spring-boot/src/test/java/org/springframework/boot/context/scan/TestEntityScan.java b/spring-boot/src/test/java/org/springframework/boot/context/scan/TestEntityScan.java deleted file mode 100644 index 0e0b5911d8..0000000000 --- a/spring-boot/src/test/java/org/springframework/boot/context/scan/TestEntityScan.java +++ /dev/null @@ -1,47 +0,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.context.scan; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.context.annotation.Import; -import org.springframework.core.annotation.AliasFor; - -/** - * 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 {}; - -} diff --git a/spring-boot/src/test/java/org/springframework/boot/context/scan/TestEntityScanRegistrar.java b/spring-boot/src/test/java/org/springframework/boot/context/scan/TestEntityScanRegistrar.java deleted file mode 100644 index af86af37df..0000000000 --- a/spring-boot/src/test/java/org/springframework/boot/context/scan/TestEntityScanRegistrar.java +++ /dev/null @@ -1,66 +0,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.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; - } - - } - -} diff --git a/spring-boot/src/test/java/org/springframework/boot/context/scan/TestEntityScanTests.java b/spring-boot/src/test/java/org/springframework/boot/context/scan/TestEntityScanTests.java deleted file mode 100644 index 7f60ced3f2..0000000000 --- a/spring-boot/src/test/java/org/springframework/boot/context/scan/TestEntityScanTests.java +++ /dev/null @@ -1,169 +0,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.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 { - - } - -} diff --git a/spring-boot/src/test/java/org/springframework/boot/neo4j/NodeEntityScanTests.java b/spring-boot/src/test/java/org/springframework/boot/neo4j/NodeEntityScanTests.java deleted file mode 100644 index 5f611bfb4f..0000000000 --- a/spring-boot/src/test/java/org/springframework/boot/neo4j/NodeEntityScanTests.java +++ /dev/null @@ -1,105 +0,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.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; - } - - } - -} diff --git a/spring-boot/src/test/java/org/springframework/boot/orm/jpa/EntityScanTests.java b/spring-boot/src/test/java/org/springframework/boot/orm/jpa/EntityScanTests.java index 93101b2d1f..8db0ad6ea3 100644 --- a/spring-boot/src/test/java/org/springframework/boot/orm/jpa/EntityScanTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/orm/jpa/EntityScanTests.java @@ -40,6 +40,7 @@ import static org.mockito.Mockito.mock; * @author Phillip Webb * @author Stephane Nicoll */ +@Deprecated public class EntityScanTests { @Rule @@ -94,16 +95,19 @@ public class EntityScanTests { } @EntityScan("com.mycorp.entity") + @SuppressWarnings("deprecation") static class ValueConfig extends BaseConfig { } @Configuration @EntityScan("com.mycorp.entity") + @SuppressWarnings("deprecation") static class MissingEntityManager { } @Configuration @EntityScan("com.mycorp.entity") + @SuppressWarnings("deprecation") static class BeanPostProcessorConfiguration { protected final EntityManagerFactory entityManagerFactory;