Commit b1833097 authored by Andy Wilkinson's avatar Andy Wilkinson

Stop a BeanPostProcessor from preventing config of packages to scan

Previously, if a BeanPostProcessor bean was declared in a configuration
class that depended on the persistence context, packages to scan would
not be configured on the LocalContainerEntityManagerFactoryBean. This
was due to the BeanPostProcessor bean triggering the early instantiation
of the LCEMFB before EntityScanBeanPostProcessor, the BeanPostProcessor,
that applies the @EntityScan configuration, had been given a chance to
configure it.

This commit updates EntityScanBeanPostProcessor to implement Ordered
with an order of zero. This ensures that its ordering is predictable
and that it will be driven before any unordered BeanPostProcessor. This
means that, unless the user has specifically ordered their
BeanPostProcessor to run before EntityScanBeanPostProcessor, 
LCEMFB’s packages to scan will be configured as expected.

Fixes gh-2478
parent 1035e5b0
...@@ -28,6 +28,7 @@ import org.springframework.beans.factory.config.BeanPostProcessor; ...@@ -28,6 +28,7 @@ import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition; import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.core.type.AnnotationMetadata; import org.springframework.core.type.AnnotationMetadata;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
...@@ -91,7 +92,7 @@ class EntityScanRegistrar implements ImportBeanDefinitionRegistrar { ...@@ -91,7 +92,7 @@ class EntityScanRegistrar implements ImportBeanDefinitionRegistrar {
* on an {@link EntityScan} annotation. * on an {@link EntityScan} annotation.
*/ */
static class EntityScanBeanPostProcessor implements BeanPostProcessor, static class EntityScanBeanPostProcessor implements BeanPostProcessor,
SmartInitializingSingleton { SmartInitializingSingleton, Ordered {
private final String[] packagesToScan; private final String[] packagesToScan;
...@@ -125,6 +126,11 @@ class EntityScanRegistrar implements ImportBeanDefinitionRegistrar { ...@@ -125,6 +126,11 @@ class EntityScanRegistrar implements ImportBeanDefinitionRegistrar {
+ "ensure an appropriate bean is registered."); + "ensure an appropriate bean is registered.");
} }
@Override
public int getOrder() {
return 0;
}
} }
} }
...@@ -22,6 +22,9 @@ import javax.persistence.PersistenceException; ...@@ -22,6 +22,9 @@ import javax.persistence.PersistenceException;
import org.junit.Rule; import org.junit.Rule;
import org.junit.Test; import org.junit.Test;
import org.junit.rules.ExpectedException; import org.junit.rules.ExpectedException;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
...@@ -99,6 +102,13 @@ public class EntityScanTests { ...@@ -99,6 +102,13 @@ public class EntityScanTests {
this.context = new AnnotationConfigApplicationContext(MissingEntityManager.class); this.context = new AnnotationConfigApplicationContext(MissingEntityManager.class);
} }
@Test
public void userDeclaredBeanPostProcessorWithEntityManagerDependencyDoesNotPreventConfigurationOfPackagesToScan() {
this.context = new AnnotationConfigApplicationContext(
BeanPostProcessorConfiguration.class, BaseConfig.class);
assertSetPackagesToScan("com.mycorp.entity");
}
private void assertSetPackagesToScan(String... expected) { private void assertSetPackagesToScan(String... expected) {
String[] actual = this.context.getBean( String[] actual = this.context.getBean(
TestLocalContainerEntityManagerFactoryBean.class).getPackagesToScan(); TestLocalContainerEntityManagerFactoryBean.class).getPackagesToScan();
...@@ -148,6 +158,33 @@ public class EntityScanTests { ...@@ -148,6 +158,33 @@ public class EntityScanTests {
static class MissingEntityManager { static class MissingEntityManager {
} }
@Configuration
@EntityScan("com.mycorp.entity")
static class BeanPostProcessorConfiguration {
@Autowired
private EntityManagerFactory entityManagerFactory;
@Bean
public BeanPostProcessor beanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
};
}
}
private static class TestLocalContainerEntityManagerFactoryBean extends private static class TestLocalContainerEntityManagerFactoryBean extends
LocalContainerEntityManagerFactoryBean { LocalContainerEntityManagerFactoryBean {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment