/* * Copyright 2012-2017 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.boot.autoconfigure.orm.jpa; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; import javax.persistence.EntityManagerFactory; import javax.sql.DataSource; import org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform; import org.junit.After; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.springframework.beans.factory.BeanCreationException; import org.springframework.boot.autoconfigure.TestAutoConfigurationPackage; import org.springframework.boot.autoconfigure.context.PropertyPlaceholderAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.EmbeddedDataSourceConfiguration; import org.springframework.boot.autoconfigure.orm.jpa.test.City; import org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration; import org.springframework.boot.context.properties.source.ConfigurationPropertySources; import org.springframework.boot.test.util.EnvironmentTestUtils; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.Bean; 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.persistenceunit.DefaultPersistenceUnitManager; import org.springframework.orm.jpa.persistenceunit.PersistenceUnitManager; 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.assertj.core.api.Assertions.assertThat; /** * Base for JPA tests and tests for {@link JpaBaseConfiguration}. * * @author Phillip Webb * @author Dave Syer */ public abstract class AbstractJpaAutoConfigurationTests { @Rule public ExpectedException expected = ExpectedException.none(); protected AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(); @After public void close() { this.context.close(); } protected abstract Class<?> getAutoConfigureClass(); @Test public void testNoDataSource() throws Exception { this.context.register(PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); this.expected.expect(BeanCreationException.class); this.expected.expectMessage("No qualifying bean"); this.expected.expectMessage("DataSource"); this.context.refresh(); } @Test public void testEntityManagerCreated() throws Exception { setupTestConfiguration(); this.context.refresh(); assertThat(this.context.getBean(DataSource.class)).isNotNull(); assertThat(this.context.getBean(JpaTransactionManager.class)).isNotNull(); } @Test public void testDataSourceTransactionManagerNotCreated() throws Exception { this.context.register(DataSourceTransactionManagerAutoConfiguration.class); setupTestConfiguration(); this.context.refresh(); assertThat(this.context.getBean(DataSource.class)).isNotNull(); assertThat(this.context.getBean("transactionManager")) .isInstanceOf(JpaTransactionManager.class); } @Test public void testOpenEntityManagerInViewInterceptorCreated() throws Exception { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(TestConfiguration.class, EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); context.refresh(); assertThat(context.getBean(OpenEntityManagerInViewInterceptor.class)).isNotNull(); context.close(); } @Test public void testOpenEntityManagerInViewInterceptorNotRegisteredWhenFilterPresent() throws Exception { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); context.register(TestFilterConfiguration.class, EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); context.refresh(); assertThat(getInterceptorBeans(context).length).isEqualTo(0); context.close(); } @Test public void testOpenEntityManagerInViewInterceptorNotRegisteredWhenExplicitlyOff() throws Exception { AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext(); EnvironmentTestUtils.addEnvironment(context, "spring.jpa.open_in_view:false"); context.register(TestConfiguration.class, EmbeddedDataSourceConfiguration.class, PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); ConfigurationPropertySources.attach(context.getEnvironment()); context.refresh(); assertThat(getInterceptorBeans(context).length).isEqualTo(0); context.close(); } @Test public void customJpaProperties() throws Exception { EnvironmentTestUtils.addEnvironment(this.context, "spring.jpa.properties.a:b", "spring.jpa.properties.a.b:c", "spring.jpa.properties.c:d"); setupTestConfiguration(); this.context.refresh(); LocalContainerEntityManagerFactoryBean bean = this.context .getBean(LocalContainerEntityManagerFactoryBean.class); Map<String, Object> map = bean.getJpaPropertyMap(); assertThat(map.get("a")).isEqualTo("b"); assertThat(map.get("c")).isEqualTo("d"); assertThat(map.get("a.b")).isEqualTo("c"); } @Test public void usesManuallyDefinedLocalContainerEntityManagerFactoryBeanIfAvailable() { EnvironmentTestUtils.addEnvironment(this.context, "spring.datasource.initialize:false"); setupTestConfiguration( TestConfigurationWithLocalContainerEntityManagerFactoryBean.class); this.context.refresh(); LocalContainerEntityManagerFactoryBean factoryBean = this.context .getBean(LocalContainerEntityManagerFactoryBean.class); Map<String, Object> map = factoryBean.getJpaPropertyMap(); assertThat(map.get("configured")).isEqualTo("manually"); } @Test public void usesManuallyDefinedEntityManagerFactoryIfAvailable() { EnvironmentTestUtils.addEnvironment(this.context, "spring.datasource.initialize:false"); setupTestConfiguration(TestConfigurationWithEntityManagerFactory.class); this.context.refresh(); EntityManagerFactory factoryBean = this.context .getBean(EntityManagerFactory.class); Map<String, Object> map = factoryBean.getProperties(); assertThat(map.get("configured")).isEqualTo("manually"); } @Test public void usesManuallyDefinedTransactionManagerBeanIfAvailable() { setupTestConfiguration(TestConfigurationWithTransactionManager.class); this.context.refresh(); PlatformTransactionManager txManager = this.context .getBean(PlatformTransactionManager.class); assertThat(txManager).isInstanceOf(CustomJpaTransactionManager.class); } @Test public void customPersistenceUnitManager() throws Exception { setupTestConfiguration(TestConfigurationWithCustomPersistenceUnitManager.class); this.context.refresh(); LocalContainerEntityManagerFactoryBean entityManagerFactoryBean = this.context .getBean(LocalContainerEntityManagerFactoryBean.class); Field field = LocalContainerEntityManagerFactoryBean.class .getDeclaredField("persistenceUnitManager"); field.setAccessible(true); assertThat(field.get(entityManagerFactoryBean)) .isEqualTo(this.context.getBean(PersistenceUnitManager.class)); } protected void setupTestConfiguration() { setupTestConfiguration(TestConfiguration.class); } protected void setupTestConfiguration(Class<?> configClass) { this.context.register(configClass, EmbeddedDataSourceConfiguration.class, DataSourceAutoConfiguration.class, TransactionAutoConfiguration.class, PropertyPlaceholderAutoConfiguration.class, getAutoConfigureClass()); } private String[] getInterceptorBeans(ApplicationContext context) { return context.getBeanNamesForType(OpenEntityManagerInViewInterceptor.class); } @Configuration @TestAutoConfigurationPackage(City.class) protected static class TestConfiguration { } @Configuration @TestAutoConfigurationPackage(City.class) protected static class TestFilterConfiguration { @Bean public OpenEntityManagerInViewFilter openEntityManagerInViewFilter() { return new OpenEntityManagerInViewFilter(); } } @Configuration protected static class TestConfigurationWithLocalContainerEntityManagerFactoryBean extends TestConfiguration { @Bean public LocalContainerEntityManagerFactoryBean entityManagerFactory( DataSource dataSource, JpaVendorAdapter adapter) { LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); factoryBean.setJpaVendorAdapter(adapter); factoryBean.setDataSource(dataSource); factoryBean.setPersistenceUnitName("manually-configured"); Map<String, Object> properties = new HashMap<>(); properties.put("configured", "manually"); properties.put("hibernate.transaction.jta.platform", NoJtaPlatform.INSTANCE); factoryBean.setJpaPropertyMap(properties); return factoryBean; } } @Configuration protected static class TestConfigurationWithEntityManagerFactory extends TestConfiguration { @Bean public EntityManagerFactory entityManagerFactory(DataSource dataSource, JpaVendorAdapter adapter) { LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean(); factoryBean.setJpaVendorAdapter(adapter); factoryBean.setDataSource(dataSource); factoryBean.setPersistenceUnitName("manually-configured"); Map<String, Object> properties = new HashMap<>(); properties.put("configured", "manually"); properties.put("hibernate.transaction.jta.platform", NoJtaPlatform.INSTANCE); factoryBean.setJpaPropertyMap(properties); factoryBean.afterPropertiesSet(); return factoryBean.getObject(); } @Bean public PlatformTransactionManager transactionManager(EntityManagerFactory emf) { JpaTransactionManager transactionManager = new JpaTransactionManager(); transactionManager.setEntityManagerFactory(emf); return transactionManager; } } @Configuration @TestAutoConfigurationPackage(City.class) protected static class TestConfigurationWithTransactionManager { @Bean public PlatformTransactionManager transactionManager() { return new CustomJpaTransactionManager(); } } @Configuration @TestAutoConfigurationPackage(AbstractJpaAutoConfigurationTests.class) public static class TestConfigurationWithCustomPersistenceUnitManager { private final DataSource dataSource; public TestConfigurationWithCustomPersistenceUnitManager(DataSource dataSource) { this.dataSource = dataSource; } @Bean public PersistenceUnitManager persistenceUnitManager() { DefaultPersistenceUnitManager persistenceUnitManager = new DefaultPersistenceUnitManager(); persistenceUnitManager.setDefaultDataSource(this.dataSource); persistenceUnitManager.setPackagesToScan(City.class.getPackage().getName()); return persistenceUnitManager; } } @SuppressWarnings("serial") static class CustomJpaTransactionManager extends JpaTransactionManager { } }