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 + +