From d39a8360b77a26086613eb067f7043a04ea5025a Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Sat, 28 Dec 2013 13:34:45 +0100 Subject: [PATCH] Added support to allow manually declaring a EntityManagerFactoryBean. Added the necessary @ConditionalOnMissingBean annotations to allow selectively declaring an EntityManagerFactoryBean, a JpaVendorAdapter or a PlatformTransactionManager. Especially the first one might be necessary to make sure the persistence provider evaluates an orm.xml. This unfortunately rules out using the packages to scan feature of Spring's LCEMFB. I've filed https://jira.springsource.org/browse/SPR-11260 to potentially remove the need for this workaround in Spring itself. --- .../orm/jpa/JpaBaseConfiguration.java | 11 +++- .../AbstractJpaAutoConfigurationTests.java | 64 ++++++++++++++++++- .../test/resources/META-INF/persistence.xml | 7 ++ 3 files changed, 76 insertions(+), 6 deletions(-) create mode 100644 spring-boot-autoconfigure/src/test/resources/META-INF/persistence.xml diff --git a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java index d73aa5f696e..f5127fbae73 100644 --- a/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java +++ b/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/orm/jpa/JpaBaseConfiguration.java @@ -34,6 +34,7 @@ import org.springframework.context.EnvironmentAware; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; +import org.springframework.orm.jpa.EntityManagerFactoryInfo; import org.springframework.orm.jpa.JpaTransactionManager; import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; @@ -51,6 +52,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter * * @author Phillip Webb * @author Dave Syer + * @author Oliver Gierke */ public abstract class JpaBaseConfiguration implements BeanFactoryAware, EnvironmentAware { @@ -64,14 +66,16 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware, Environm } @Bean + @ConditionalOnMissingBean(PlatformTransactionManager.class) public PlatformTransactionManager transactionManager() { - return new JpaTransactionManager(entityManagerFactory().getObject()); + return new JpaTransactionManager(); } @Bean - public LocalContainerEntityManagerFactoryBean entityManagerFactory() { + @ConditionalOnMissingBean(EntityManagerFactoryInfo.class) + public LocalContainerEntityManagerFactoryBean entityManagerFactory(JpaVendorAdapter jpaVendorAdapter) { LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = new LocalContainerEntityManagerFactoryBean(); - entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter()); + entityManagerFactoryBean.setJpaVendorAdapter(jpaVendorAdapter); entityManagerFactoryBean.setDataSource(getDataSource()); entityManagerFactoryBean.setPackagesToScan(getPackagesToScan()); entityManagerFactoryBean.getJpaPropertyMap().putAll( @@ -81,6 +85,7 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware, Environm } @Bean + @ConditionalOnMissingBean(JpaVendorAdapter.class) public JpaVendorAdapter jpaVendorAdapter() { AbstractJpaVendorAdapter adapter = createJpaVendorAdapter(); adapter.setShowSql(this.environment.getProperty("show-sql", Boolean.class, true)); diff --git a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java index e3bfcfae4d3..106957b7ffb 100644 --- a/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java +++ b/spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/orm/jpa/AbstractJpaAutoConfigurationTests.java @@ -16,6 +16,7 @@ package org.springframework.boot.autoconfigure.orm.jpa; +import java.util.Collections; import java.util.Map; import javax.sql.DataSource; @@ -27,6 +28,7 @@ import org.springframework.boot.autoconfigure.ComponentScanDetectorConfiguration import org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.AbstractJpaAutoConfigurationTests.TestConfigurationWithTransactionManager.CustomJpaTransactionManager; import org.springframework.boot.autoconfigure.orm.jpa.test.City; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -34,11 +36,14 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.orm.jpa.JpaTransactionManager; +import org.springframework.orm.jpa.JpaVendorAdapter; import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean; import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter; import org.springframework.orm.jpa.support.OpenEntityManagerInViewInterceptor; +import org.springframework.transaction.PlatformTransactionManager; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; +import static org.hamcrest.CoreMatchers.*; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -130,9 +135,35 @@ public abstract class AbstractJpaAutoConfigurationTests { assertThat(map.get("a"), equalTo((Object) "b")); assertThat(map.get("c"), equalTo((Object) "d")); } + + @Test + public void usesManuallyDefinedEntityManagerFactoryBeanIfAvailable() { + + setupTestConfiguration(TestConfigurationWithEntityManagerFactory.class); + this.context.refresh(); + + LocalContainerEntityManagerFactoryBean factoryBean = this.context.getBean(LocalContainerEntityManagerFactoryBean.class); + Map map = factoryBean.getJpaPropertyMap(); + assertThat(map.get("configured"), is((Object) "manually")); + } + + @Test + public void usesManuallyDefinedTransactionManagerBeanIfAvailable() { + + setupTestConfiguration(TestConfigurationWithTransactionManager.class); + this.context.refresh(); + + PlatformTransactionManager txManager = this.context.getBean(PlatformTransactionManager.class); + assertThat(txManager, is(instanceOf(CustomJpaTransactionManager.class))); + } protected void setupTestConfiguration() { - this.context.register(TestConfiguration.class, + setupTestConfiguration(TestConfiguration.class); + } + + protected void setupTestConfiguration(Class configClass) { + + this.context.register(configClass, ComponentScanDetectorConfiguration.class, EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); @@ -156,7 +187,34 @@ public abstract class AbstractJpaAutoConfigurationTests { public OpenEntityManagerInViewFilter openEntityManagerInViewFilter() { return new OpenEntityManagerInViewFilter(); } - } - + + @Configuration + protected static class TestConfigurationWithEntityManagerFactory extends TestConfiguration { + + @Bean + public LocalContainerEntityManagerFactoryBean entityManagerFactory(DataSource dataSource, JpaVendorAdapter adapter) { + + LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); + factoryBean.setJpaVendorAdapter(adapter); + factoryBean.setDataSource(dataSource); + factoryBean.setPersistenceUnitName("manually-configured"); + factoryBean.setJpaPropertyMap(Collections.singletonMap("configured", "manually")); + return factoryBean; + } + } + + @Configuration + @ComponentScan(basePackageClasses = { City.class }) + protected static class TestConfigurationWithTransactionManager { + + @Bean + public PlatformTransactionManager transactionManager() { + return new CustomJpaTransactionManager(); + } + + static class CustomJpaTransactionManager extends JpaTransactionManager { + + } + } } diff --git a/spring-boot-autoconfigure/src/test/resources/META-INF/persistence.xml b/spring-boot-autoconfigure/src/test/resources/META-INF/persistence.xml new file mode 100644 index 00000000000..1607abfb578 --- /dev/null +++ b/spring-boot-autoconfigure/src/test/resources/META-INF/persistence.xml @@ -0,0 +1,7 @@ + + + + org.springframework.boot.autoconfigure.orm.jpa.test.City + true + +