From 9c6a6a750bdbccce999d25e67c4934d9b3bb8b36 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 c9833a4a6..daa454493 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; @@ -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 emfType; + + public StubEntityManagerFactoryBean(Class emfType) { + this.emfType = emfType; + } + + @Override + public Class getObjectType() { + return emfType; + } + + @Override + protected EntityManagerFactory createEntityManagerFactoryProxy(EntityManagerFactory emf) { + return mock(emfType); + } + } }