DATAJPA-265 - Improve implementation of AuditingBeanFactoryPostProcessor.

Polished the implementation of AuditingBeanFactoryPostProcessor to selectively add depends-on clauses to all bean definitions that will result in EntityManagerFactory instances eventually. Added unit tests to verify intended behavior for Java based configuration. Polished newly integrated test cases.

Removed obsolete code from AuditingEntityListener. Added configuration sample snippet. Polished reference documentation.

Original pull request: #50.
This commit is contained in:
Oliver Gierke
2013-11-11 12:25:29 +01:00
parent 44806cb7f1
commit 80e1777a5b
11 changed files with 213 additions and 93 deletions

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2013 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.data.jpa.domain.support;
import static org.mockito.Mockito.*;
import javax.persistence.EntityManagerFactory;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ConfigurationClassPostProcessor;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
/**
* Unit tests to check that the {@link AuditingBeanFactoryPostProcessor} does its job for annotation based
* configuration.
*
* @author Oliver Gierke
*/
public class AnnotationAuditingBeanFactoryPostProcessorUnitTests extends AuditingBeanFactoryPostProcessorUnitTests {
@Configuration
@EnableJpaAuditing
static class TestConfig {
@Bean
public EntityManagerFactory entityManagerFactory() {
return mock(EntityManagerFactory.class);
}
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean() {
return mock(LocalContainerEntityManagerFactoryBean.class);
}
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.domain.support.AuditingBeanFactoryPostProcessorUnitTests#getBeanFactory()
*/
@Override
protected DefaultListableBeanFactory getBeanFactory() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.registerBeanDefinition("testConfig", new RootBeanDefinition(TestConfig.class));
ConfigurationClassPostProcessor processor = new ConfigurationClassPostProcessor();
processor.postProcessBeanDefinitionRegistry(beanFactory);
return beanFactory;
}
}

View File

@@ -15,11 +15,14 @@
*/
package org.springframework.data.jpa.domain.support;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import javax.persistence.EntityManagerFactory;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.core.io.ClassPathResource;
@@ -38,18 +41,23 @@ public class AuditingBeanFactoryPostProcessorUnitTests {
@Before
public void setUp() {
beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource("auditing/" + getConfigFile()));
processor = new AuditingBeanFactoryPostProcessor();
this.beanFactory = getBeanFactory();
this.processor = new AuditingBeanFactoryPostProcessor();
}
protected String getConfigFile() {
return "auditing-bfpp-context.xml";
}
protected DefaultListableBeanFactory getBeanFactory() {
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource("auditing/" + getConfigFile()));
return beanFactory;
}
@Test
public void beanConfigurerAspectShouldBeConfiguredAfterPostProcessing() throws Exception {
@@ -57,4 +65,30 @@ public class AuditingBeanFactoryPostProcessorUnitTests {
assertThat(beanFactory.isBeanNameInUse(AuditingBeanFactoryPostProcessor.BEAN_CONFIGURER_ASPECT_BEAN_NAME), is(true));
}
/**
* @see DATAJPA-265
*/
@Test(expected = IllegalStateException.class)
public void rejectsConfigurationWithoutSpringConfigured() {
processor.postProcessBeanFactory(new DefaultListableBeanFactory());
}
/**
* @see DATAJPA-265
*/
@Test
public void setsDependsOnOnEntityManagerFactory() {
processor.postProcessBeanFactory(beanFactory);
String[] emfDefinitionNames = beanFactory.getBeanNamesForType(EntityManagerFactory.class);
for (String emfDefinitionName : emfDefinitionNames) {
BeanDefinition emfDefinition = beanFactory.getBeanDefinition(emfDefinitionName);
assertThat(emfDefinition, is(notNullValue()));
assertThat(emfDefinition.getDependsOn(),
is(arrayContaining(AuditingBeanFactoryPostProcessor.BEAN_CONFIGURER_ASPECT_BEAN_NAME)));
}
}
}

View File

@@ -38,6 +38,7 @@ import org.springframework.transaction.annotation.Transactional;
* Integration tests for auditing via Java config.
*
* @author Thomas Darimont
* @author Oliver Gierke
*/
@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@@ -54,10 +55,11 @@ public abstract class AbstractAuditingViaJavaConfigRepositoriesTests {
@Before
public void setup() {
AuditableUser auditor = new AuditableUser(null);
auditor.setFirstname("auditor");
this.auditor = this.auditableUserRepository.save(auditor);
this.auditor = this.auditableUserRepository.save(auditor);
doReturn(this.auditor).when(this.auditorAware).getCurrentAuditor();
}
@@ -67,7 +69,6 @@ public abstract class AbstractAuditingViaJavaConfigRepositoriesTests {
}
@Test
@Transactional
public void basicAuditing() throws Exception {
AuditableUser user = new AuditableUser(null);

View File

@@ -76,7 +76,7 @@ public class AuditingBeanDefinitionParserTests {
ShadowingClassLoader scl = new ShadowingClassLoader(getClass().getClassLoader());
scl.excludeClass(AuditingBeanDefinitionParser.AUDITING_ENTITY_LISTENER_CLASS_NAME);
DefaultListableBeanFactory factory = loadFactoryFrom("auditing/auditing-namespace-context.xml", scl);
loadFactoryFrom("auditing/auditing-namespace-context.xml", scl);
}
private void assertSetDatesIsSetTo(String configFile, String value) {

View File

@@ -28,6 +28,7 @@ import org.springframework.test.context.ContextConfiguration;
* Integration tests for auditing via Java config with default configuration.
*
* @author Thomas Darimont
* @author Oliver Gierke
*/
@ContextConfiguration
public class DefaultAuditingViaJavaConfigRepositoriesTests extends AbstractAuditingViaJavaConfigRepositoriesTests {
@@ -38,6 +39,7 @@ public class DefaultAuditingViaJavaConfigRepositoriesTests extends AbstractAudit
static class Config {
@Bean
@SuppressWarnings("unchecked")
public AuditorAware<AuditableUser> auditorProvider() {
return mock(AuditorAware.class);
}

View File

@@ -28,8 +28,8 @@ import org.springframework.test.context.ContextConfiguration;
* Integration tests for auditing via Java config with explicit configuration.
*
* @author Thomas Darimont
* @author Oliver Gierke
*/
@ContextConfiguration
public class ExplicitAuditingViaJavaConfigRepositoriesTests extends AbstractAuditingViaJavaConfigRepositoriesTests {
@@ -39,6 +39,7 @@ public class ExplicitAuditingViaJavaConfigRepositoriesTests extends AbstractAudi
static class Config {
@Bean
@SuppressWarnings("unchecked")
public AuditorAware<AuditableUser> auditorProvider() {
return mock(AuditorAware.class);
}