From 0d6376d6d87603ce6584da8b8b6cc671693bc5d1 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Wed, 25 Jan 2017 11:35:33 +0100 Subject: [PATCH] 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. --- .../data/jpa/util/BeanDefinitionUtils.java | 3 +- ...nitionRegistratPostProcessorUnitTests.java | 40 +++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/springframework/data/jpa/util/BeanDefinitionUtils.java b/src/main/java/org/springframework/data/jpa/util/BeanDefinitionUtils.java index f93c8d75d..c54a8e499 100644 --- a/src/main/java/org/springframework/data/jpa/util/BeanDefinitionUtils.java +++ b/src/main/java/org/springframework/data/jpa/util/BeanDefinitionUtils.java @@ -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; } diff --git a/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistratPostProcessorUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistratPostProcessorUnitTests.java index 3abf39cf1..d46d4ffce 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistratPostProcessorUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/EntityManagerBeanDefinitionRegistratPostProcessorUnitTests.java @@ -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; @@ -45,4 +49,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 emfType; + + public StubEntityManagerFactoryBean(Class emfType) { + this.emfType = emfType; + } + + @Override + public Class getObjectType() { + return emfType; + } + + @Override + protected EntityManagerFactory createEntityManagerFactoryProxy(EntityManagerFactory emf) { + return mock(emfType); + } + } }