diff --git a/src/main/java/org/springframework/data/jdbc/domain/support/JdbcAuditingEventListener.java b/src/main/java/org/springframework/data/jdbc/domain/support/JdbcAuditingEventListener.java index f500e9b6..bdb31ee2 100644 --- a/src/main/java/org/springframework/data/jdbc/domain/support/JdbcAuditingEventListener.java +++ b/src/main/java/org/springframework/data/jdbc/domain/support/JdbcAuditingEventListener.java @@ -19,30 +19,22 @@ import org.springframework.beans.factory.ObjectFactory; import org.springframework.context.ApplicationListener; import org.springframework.data.auditing.AuditingHandler; import org.springframework.data.jdbc.mapping.event.BeforeSaveEvent; +import org.springframework.data.jdbc.repository.config.EnableJdbcAuditing; import org.springframework.lang.Nullable; import org.springframework.util.Assert; /** * Spring JDBC event listener to capture auditing information on persisting and updating entities. *
- * You can enable this class just a matter of activating auditing using {@link org.springframework.data.jdbc.repository.config.EnableJdbcAuditing} in your Spring config: - * - *
- * @Configuration
- * @EnableJdbcRepositories
- * @EnableJdbcAuditing
- * class JdbcRepositoryConfig {
- * }
- *
+ * An instance of this class gets registered when you apply {@link EnableJdbcAuditing} to your Spring config.
*
* @author Kazuki Shimizu
- * @see org.springframework.data.jdbc.repository.config.EnableJdbcAuditing
+ * @see EnableJdbcAuditing
* @since 1.0
*/
public class JdbcAuditingEventListener implements ApplicationListener- * Note: This feature cannot use to a entity that implements {@link org.springframework.data.domain.Auditable} - * because the Spring Data JDBC does not support an {@link java.util.Optional} property yet. - *
- * * @see EnableJdbcRepositories * @author Kazuki Shimizu * @since 1.0 diff --git a/src/main/java/org/springframework/data/jdbc/repository/config/JdbcAuditingRegistrar.java b/src/main/java/org/springframework/data/jdbc/repository/config/JdbcAuditingRegistrar.java index a734592f..41e6a87a 100644 --- a/src/main/java/org/springframework/data/jdbc/repository/config/JdbcAuditingRegistrar.java +++ b/src/main/java/org/springframework/data/jdbc/repository/config/JdbcAuditingRegistrar.java @@ -27,7 +27,8 @@ import org.springframework.data.config.ParsingUtils; import org.springframework.data.jdbc.domain.support.JdbcAuditingEventListener; /** - * {@link ImportBeanDefinitionRegistrar} to enable {@link EnableJdbcAuditing} annotation. + * {@link ImportBeanDefinitionRegistrar} which registers additional beans in order to enable auditing via the + * {@link EnableJdbcAuditing} annotation. * * @see EnableJdbcAuditing * @author Kazuki Shimizu @@ -37,8 +38,9 @@ class JdbcAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport { /** * {@inheritDoc} + * * @return return the {@link EnableJdbcAuditing} - * @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAnnotation() + * @see AuditingBeanDefinitionRegistrarSupport#getAnnotation() */ @Override protected Class extends Annotation> getAnnotation() { @@ -47,8 +49,9 @@ class JdbcAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport { /** * {@inheritDoc} + * * @return return "{@literal jdbcAuditingHandler}" - * @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAuditingHandlerBeanName() + * @see AuditingBeanDefinitionRegistrarSupport#getAuditingHandlerBeanName() */ @Override protected String getAuditingHandlerBeanName() { @@ -61,22 +64,25 @@ class JdbcAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport { */ @Override protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) { + BeanDefinitionBuilder builder = super.getAuditHandlerBeanDefinitionBuilder(configuration); return builder.addConstructorArgReference("jdbcMappingContext"); } /** - * Register the bean definition of {@link JdbcAuditingEventListener}. - * {@inheritDoc} - * @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#registerAuditListenerBeanDefinition(BeanDefinition, BeanDefinitionRegistry) + * Register the bean definition of {@link JdbcAuditingEventListener}. {@inheritDoc} + * + * @see AuditingBeanDefinitionRegistrarSupport#registerAuditListenerBeanDefinition(BeanDefinition, + * BeanDefinitionRegistry) */ @Override protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandlerDefinition, - BeanDefinitionRegistry registry) { + BeanDefinitionRegistry registry) { + Class> listenerClass = JdbcAuditingEventListener.class; BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(listenerClass); builder.addPropertyValue("auditingHandler", - ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), null)); + ParsingUtils.getObjectFactoryBeanDefinition(getAuditingHandlerBeanName(), null)); registerInfrastructureBeanWithId(builder.getRawBeanDefinition(), listenerClass.getName(), registry); } diff --git a/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java b/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java index e685cc55..24b8b0b4 100644 --- a/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java +++ b/src/test/java/org/springframework/data/jdbc/repository/config/EnableJdbcAuditingHsqlIntegrationTests.java @@ -15,7 +15,17 @@ */ package org.springframework.data.jdbc.repository.config; +import static org.assertj.core.api.Assertions.*; + import lombok.Data; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Optional; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import org.assertj.core.api.SoftAssertions; import org.junit.Test; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; @@ -32,144 +42,178 @@ import org.springframework.data.domain.AuditorAware; import org.springframework.data.jdbc.mapping.model.NamingStrategy; import org.springframework.data.repository.CrudRepository; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.util.Optional; -import java.util.concurrent.TimeUnit; - -import static org.assertj.core.api.Assertions.assertThat; - /** * Tests the {@link EnableJdbcAuditing} annotation. * * @author Kazuki Shimizu + * @author Jens Schauder */ public class EnableJdbcAuditingHsqlIntegrationTests { + SoftAssertions softly = new SoftAssertions(); + @Test - public void auditForAnnotatedEntity() throws InterruptedException { - try (ConfigurableApplicationContext context = - new AnnotationConfigApplicationContext(TestConfiguration.class, AuditingConfiguration.class)) { + public void auditForAnnotatedEntity() { - AuditingAnnotatedDummyEntityRepository repository = context.getBean(AuditingAnnotatedDummyEntityRepository.class); + configureRepositoryWith( // + AuditingAnnotatedDummyEntityRepository.class, // + TestConfiguration.class, // + AuditingConfiguration.class) // + .accept(repository -> { - AuditingConfiguration.currentAuditor = "user01"; - LocalDateTime now = LocalDateTime.now(); + AuditingConfiguration.currentAuditor = "user01"; + LocalDateTime now = LocalDateTime.now(); - AuditingAnnotatedDummyEntity entity = new AuditingAnnotatedDummyEntity(); - entity.setName("Spring Data"); - repository.save(entity); + AuditingAnnotatedDummyEntity entity = repository.save(new AuditingAnnotatedDummyEntity()); - assertThat(entity.id).isNotNull(); - assertThat(entity.getCreatedBy()).isEqualTo("user01"); - assertThat(entity.getCreatedDate()).isAfter(now); - assertThat(entity.getLastModifiedBy()).isEqualTo("user01"); - assertThat(entity.getLastModifiedDate()).isAfterOrEqualTo(entity.getCreatedDate()); - assertThat(entity.getLastModifiedDate()).isAfter(now); - assertThat(repository.findById(entity.id).get()).isEqualTo(entity); + softly.assertThat(entity.id).isNotNull(); + softly.assertThat(entity.getCreatedBy()).isEqualTo("user01"); + softly.assertThat(entity.getCreatedDate()).isAfter(now); + softly.assertThat(entity.getLastModifiedBy()).isEqualTo("user01"); + softly.assertThat(entity.getLastModifiedDate()).isAfterOrEqualTo(entity.getCreatedDate()); + softly.assertThat(entity.getLastModifiedDate()).isAfter(now); + softly.assertThat(repository.findById(entity.id).get()).isEqualTo(entity); - LocalDateTime beforeCreatedDate = entity.getCreatedDate(); - LocalDateTime beforeLastModifiedDate = entity.getLastModifiedDate(); + LocalDateTime beforeCreatedDate = entity.getCreatedDate(); + LocalDateTime beforeLastModifiedDate = entity.getLastModifiedDate(); - TimeUnit.MILLISECONDS.sleep(100); - AuditingConfiguration.currentAuditor = "user02"; + softly.assertAll(); - entity.setName("Spring Data JDBC"); - repository.save(entity); + sleepMillis(10); - assertThat(entity.getCreatedBy()).isEqualTo("user01"); - assertThat(entity.getCreatedDate()).isEqualTo(beforeCreatedDate); - assertThat(entity.getLastModifiedBy()).isEqualTo("user02"); - assertThat(entity.getLastModifiedDate()).isAfter(beforeLastModifiedDate); - assertThat(repository.findById(entity.id).get()).isEqualTo(entity); - } + AuditingConfiguration.currentAuditor = "user02"; + + entity = repository.save(entity); + + softly.assertThat(entity.getCreatedBy()).isEqualTo("user01"); + softly.assertThat(entity.getCreatedDate()).isEqualTo(beforeCreatedDate); + softly.assertThat(entity.getLastModifiedBy()).isEqualTo("user02"); + softly.assertThat(entity.getLastModifiedDate()).isAfter(beforeLastModifiedDate); + softly.assertThat(repository.findById(entity.id).get()).isEqualTo(entity); + }); } @Test public void noAnnotatedEntity() { - try (ConfigurableApplicationContext context = - new AnnotationConfigApplicationContext(TestConfiguration.class, AuditingConfiguration.class)) { - DummyEntityRepository repository = context.getBean(DummyEntityRepository.class); + configureRepositoryWith( // + DummyEntityRepository.class, // + TestConfiguration.class, // + AuditingConfiguration.class) // + .accept(repository -> { - DummyEntity entity = new DummyEntity(); - entity.setName("Spring Data"); - repository.save(entity); + DummyEntity entity = repository.save(new DummyEntity()); - assertThat(entity.id).isNotNull(); - assertThat(repository.findById(entity.id).get()).isEqualTo(entity); + softly.assertThat(entity.id).isNotNull(); + softly.assertThat(repository.findById(entity.id).get()).isEqualTo(entity); - entity.setName("Spring Data JDBC"); - repository.save(entity); + softly.assertAll(); - assertThat(repository.findById(entity.id).get()).isEqualTo(entity); - } + entity = repository.save(entity); + + assertThat(repository.findById(entity.id).get()).isEqualTo(entity); + }); } @Test - public void customizeEnableJdbcAuditingAttributes() { - // Test for 'auditorAwareRef', 'dateTimeProviderRef' and 'modifyOnCreate' - try (ConfigurableApplicationContext context = - new AnnotationConfigApplicationContext(TestConfiguration.class, CustomizeAuditingConfiguration1.class)) { - AuditingAnnotatedDummyEntityRepository repository = context.getBean(AuditingAnnotatedDummyEntityRepository.class); + public void customDateTimeProvider() { - LocalDateTime currentDateTime = LocalDate.of(2018, 4, 14).atStartOfDay(); - CustomizeAuditingConfiguration1.currentDateTime = currentDateTime; + configureRepositoryWith( // + AuditingAnnotatedDummyEntityRepository.class, // + TestConfiguration.class, // + CustomizeAuditorAwareAndDateTimeProvider.class) // + .accept(repository -> { - AuditingAnnotatedDummyEntity entity = new AuditingAnnotatedDummyEntity(); - entity.setName("Spring Data JDBC"); - repository.save(entity); + LocalDateTime currentDateTime = LocalDate.of(2018, 4, 14).atStartOfDay(); + CustomizeAuditorAwareAndDateTimeProvider.currentDateTime = currentDateTime; - assertThat(entity.id).isNotNull(); - assertThat(entity.getCreatedBy()).isEqualTo("custom user"); - assertThat(entity.getCreatedDate()).isEqualTo(currentDateTime); - assertThat(entity.getLastModifiedBy()).isNull(); - assertThat(entity.getLastModifiedDate()).isNull(); - } - // Test for 'setDates' - try (ConfigurableApplicationContext context = - new AnnotationConfigApplicationContext(TestConfiguration.class, CustomizeAuditingConfiguration2.class)) { - AuditingAnnotatedDummyEntityRepository repository = context.getBean(AuditingAnnotatedDummyEntityRepository.class); + AuditingAnnotatedDummyEntity entity = repository.save(new AuditingAnnotatedDummyEntity()); - AuditingAnnotatedDummyEntity entity = new AuditingAnnotatedDummyEntity(); - entity.setName("Spring Data JDBC"); - repository.save(entity); + softly.assertThat(entity.id).isNotNull(); + softly.assertThat(entity.getCreatedBy()).isEqualTo("custom user"); + softly.assertThat(entity.getCreatedDate()).isEqualTo(currentDateTime); + softly.assertThat(entity.getLastModifiedBy()).isNull(); + softly.assertThat(entity.getLastModifiedDate()).isNull(); + }); + } - assertThat(entity.id).isNotNull(); - assertThat(entity.getCreatedBy()).isEqualTo("user"); - assertThat(entity.getCreatedDate()).isNull(); - assertThat(entity.getLastModifiedBy()).isEqualTo("user"); - assertThat(entity.getLastModifiedDate()).isNull(); - } + @Test + public void customAuditorAware() { + + configureRepositoryWith( // + AuditingAnnotatedDummyEntityRepository.class, // + TestConfiguration.class, // + CustomizeAuditorAware.class) // + .accept(repository -> { + + AuditingAnnotatedDummyEntity entity = repository.save(new AuditingAnnotatedDummyEntity()); + + softly.assertThat(entity.id).isNotNull(); + softly.assertThat(entity.getCreatedBy()).isEqualTo("user"); + softly.assertThat(entity.getCreatedDate()).isNull(); + softly.assertThat(entity.getLastModifiedBy()).isEqualTo("user"); + softly.assertThat(entity.getLastModifiedDate()).isNull(); + }); + } + + /** + * Usage looks like this: + *
+ * {@code configure(MyRepository.class, MyConfiguration) .accept(repository -> { // perform tests on repository here
+ * }); }
+ *
+ * @param repositoryType the type of repository you want to perform tests on.
+ * @param configurationClasses the classes containing the configuration for the
+ * {@link org.springframework.context.ApplicationContext}.
+ * @param