@ -16,8 +16,8 @@
package org.springframework.boot.orm.jpa ;
package org.springframework.boot.orm.jpa ;
import java.util.ArrayList ;
import java.util.Arrays ;
import java.util.Arrays ;
import java.util.Collections ;
import java.util.LinkedHashSet ;
import java.util.LinkedHashSet ;
import java.util.Set ;
import java.util.Set ;
@ -25,6 +25,7 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.SmartInitializingSingleton ;
import org.springframework.beans.factory.SmartInitializingSingleton ;
import org.springframework.beans.factory.config.BeanDefinition ;
import org.springframework.beans.factory.config.BeanDefinition ;
import org.springframework.beans.factory.config.BeanPostProcessor ;
import org.springframework.beans.factory.config.BeanPostProcessor ;
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder ;
import org.springframework.beans.factory.support.BeanDefinitionRegistry ;
import org.springframework.beans.factory.support.BeanDefinitionRegistry ;
import org.springframework.beans.factory.support.GenericBeanDefinition ;
import org.springframework.beans.factory.support.GenericBeanDefinition ;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar ;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar ;
@ -40,6 +41,7 @@ import org.springframework.util.ObjectUtils;
* { @link ImportBeanDefinitionRegistrar } used by { @link EntityScan } .
* { @link ImportBeanDefinitionRegistrar } used by { @link EntityScan } .
*
*
* @author Phillip Webb
* @author Phillip Webb
* @author Oliver Gierke
* /
* /
class EntityScanRegistrar implements ImportBeanDefinitionRegistrar {
class EntityScanRegistrar implements ImportBeanDefinitionRegistrar {
@ -48,31 +50,25 @@ class EntityScanRegistrar implements ImportBeanDefinitionRegistrar {
@Override
@Override
public void registerBeanDefinitions ( AnnotationMetadata importingClassMetadata ,
public void registerBeanDefinitions ( AnnotationMetadata importingClassMetadata ,
BeanDefinitionRegistry registry ) {
BeanDefinitionRegistry registry ) {
Set < String > packagesToScan = getPackagesToScan ( importingClassMetadata ) ;
if ( ! registry . containsBeanDefinition ( BEAN_NAME ) ) {
if ( ! registry . containsBeanDefinition ( BEAN_NAME ) ) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition ( ) ;
addEntityScanBeanPostProcessor ( registry , packagesToScan ) ;
beanDefinition . setBeanClass ( EntityScanBeanPostProcessor . class ) ;
}
beanDefinition . getConstructorArgumentValues ( ) . addGenericArgumentValue (
else {
getPackagesToScan ( importingClassMetadata ) ) ;
updateEntityScanBeanPostProcessor ( registry , packagesToScan ) ;
beanDefinition . setRole ( BeanDefinition . ROLE_INFRASTRUCTURE ) ;
// We don't need this one to be post processed otherwise it can cause a
// cascade of bean instantiation that we would rather avoid.
beanDefinition . setSynthetic ( true ) ;
registry . registerBeanDefinition ( BEAN_NAME , beanDefinition ) ;
}
}
}
}
private S tring[ ] getPackagesToScan ( AnnotationMetadata metadata ) {
private Set < String > getPackagesToScan ( AnnotationMetadata metadata ) {
AnnotationAttributes attributes = AnnotationAttributes . fromMap ( metadata
AnnotationAttributes attributes = AnnotationAttributes . fromMap ( metadata
. getAnnotationAttributes ( EntityScan . class . getName ( ) ) ) ;
. getAnnotationAttributes ( EntityScan . class . getName ( ) ) ) ;
String [ ] value = attributes . getStringArray ( "value" ) ;
String [ ] value = attributes . getStringArray ( "value" ) ;
String [ ] basePackages = attributes . getStringArray ( "basePackages" ) ;
String [ ] basePackages = attributes . getStringArray ( "basePackages" ) ;
Class < ? > [ ] basePackageClasses = attributes . getClassArray ( "basePackageClasses" ) ;
Class < ? > [ ] basePackageClasses = attributes . getClassArray ( "basePackageClasses" ) ;
if ( ! ObjectUtils . isEmpty ( value ) ) {
if ( ! ObjectUtils . isEmpty ( value ) ) {
Assert . state ( ObjectUtils . isEmpty ( basePackages ) ,
Assert . state ( ObjectUtils . isEmpty ( basePackages ) ,
"@EntityScan basePackages and value attributes are mutually exclusive" ) ;
"@EntityScan basePackages and value attributes are mutually exclusive" ) ;
}
}
Set < String > packagesToScan = new LinkedHashSet < String > ( ) ;
Set < String > packagesToScan = new LinkedHashSet < String > ( ) ;
packagesToScan . addAll ( Arrays . asList ( value ) ) ;
packagesToScan . addAll ( Arrays . asList ( value ) ) ;
packagesToScan . addAll ( Arrays . asList ( basePackages ) ) ;
packagesToScan . addAll ( Arrays . asList ( basePackages ) ) ;
@ -80,10 +76,38 @@ class EntityScanRegistrar implements ImportBeanDefinitionRegistrar {
packagesToScan . add ( ClassUtils . getPackageName ( basePackageClass ) ) ;
packagesToScan . add ( ClassUtils . getPackageName ( basePackageClass ) ) ;
}
}
if ( packagesToScan . isEmpty ( ) ) {
if ( packagesToScan . isEmpty ( ) ) {
return new String [ ] { ClassUtils . getPackageName ( metadata . getClassName ( ) ) } ;
return Collections . singleton ( ClassUtils . getPackageName ( metadata
. getClassName ( ) ) ) ;
}
}
return new ArrayList < String > ( packagesToScan ) . toArray ( new String [ packagesToScan
return packagesToScan ;
. size ( ) ] ) ;
}
private void addEntityScanBeanPostProcessor ( BeanDefinitionRegistry registry ,
Set < String > packagesToScan ) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition ( ) ;
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 ( BEAN_NAME , beanDefinition ) ;
}
private void updateEntityScanBeanPostProcessor ( BeanDefinitionRegistry registry ,
Set < String > packagesToScan ) {
BeanDefinition definition = registry . getBeanDefinition ( BEAN_NAME ) ;
ValueHolder constructorArguments = definition . getConstructorArgumentValues ( )
. getGenericArgumentValue ( String [ ] . class ) ;
Set < String > mergedPackages = new LinkedHashSet < String > ( ) ;
mergedPackages . addAll ( Arrays . asList ( ( String [ ] ) constructorArguments . getValue ( ) ) ) ;
mergedPackages . addAll ( packagesToScan ) ;
constructorArguments . setValue ( toArray ( mergedPackages ) ) ;
}
private String [ ] toArray ( Set < String > set ) {
return set . toArray ( new String [ set . size ( ) ] ) ;
}
}
/ * *
/ * *