DATAJPA-1005 - Improved lookup of EntityManagerFactory bean definitions for constructor injectability.

Our bean definition check for EntityManagerFactory instances previously expected the type prediction to return exactly EntityManagerFactory. That should theoretically always be the case as the component inspecting the beans is a BeanFactoryPostProcessor, i.e. running before any of the beans should have been instantiated.

If however an EntityManagerFactoryBean is already in creation and the EntityManagerFactory backing it is already available, the factory bean will return the concrete factory's type (see AbstractEntityManagerFactoryBean.getObjectType()) so that we have to accept subtypes of EntityManagerFactory in our selection process.

Related ticket: DATAJPA-1045.
This commit is contained in:
Oliver Gierke
2017-01-25 11:35:33 +01:00
parent 6bd2d9eabe
commit 9c6a6a750b
2 changed files with 42 additions and 1 deletions

View File

@@ -127,7 +127,8 @@ public class BeanDefinitionUtils {
if (!EntityManagerFactory.class.getName().equals(definition.getPropertyValues().get("expectedType"))) {
return;
}
} else if (!EntityManagerFactory.class.equals(beanFactory.getType(name))) {
} else if (beanFactory.getType(name) == null
|| !EntityManagerFactory.class.isAssignableFrom(beanFactory.getType(name))) {
return;
}

View File

@@ -17,10 +17,14 @@ package org.springframework.data.jpa.repository.support;
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import javax.persistence.EntityManagerFactory;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@@ -48,4 +52,40 @@ public class EntityManagerBeanDefinitionRegistratPostProcessorUnitTests {
assertThat(beanFactory.getBeanDefinitionCount(), is(2));
}
@Test // DATAJPA-1005, DATAJPA-1045
public void discoversFactoryBeanReturningConcreteEntityManagerFactoryType() {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(StubEntityManagerFactoryBean.class);
builder.addConstructorArgValue(SpecialEntityManagerFactory.class);
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("factory", builder.getBeanDefinition());
BeanFactoryPostProcessor processor = new EntityManagerBeanDefinitionRegistrarPostProcessor();
processor.postProcessBeanFactory(beanFactory);
assertThat(beanFactory.getBeanDefinitionCount(), is(2));
}
interface SpecialEntityManagerFactory extends EntityManagerFactory {}
static class StubEntityManagerFactoryBean extends LocalContainerEntityManagerFactoryBean {
private final Class<? extends EntityManagerFactory> emfType;
public StubEntityManagerFactoryBean(Class<? extends EntityManagerFactory> emfType) {
this.emfType = emfType;
}
@Override
public Class<? extends EntityManagerFactory> getObjectType() {
return emfType;
}
@Override
protected EntityManagerFactory createEntityManagerFactoryProxy(EntityManagerFactory emf) {
return mock(emfType);
}
}
}