Browse Source

Polishing.

Add autowriting support to auditing handler properties.

See: #3177
Original pull request: #3385
pull/3394/head
Mark Paluch 2 months ago
parent
commit
6c3e1ace7d
No known key found for this signature in database
GPG Key ID: 55BC6374BAA9D973
  1. 5
      src/main/antora/modules/ROOT/pages/auditing.adoc
  2. 10
      src/main/java/org/springframework/data/auditing/AuditingHandler.java
  3. 10
      src/main/java/org/springframework/data/auditing/ReactiveAuditingHandler.java
  4. 8
      src/main/java/org/springframework/data/auditing/config/AuditingBeanDefinitionRegistrarSupport.java
  5. 51
      src/test/java/org/springframework/data/auditing/config/AuditingBeanDefinitionRegistrarSupportUnitTests.java

5
src/main/antora/modules/ROOT/pages/auditing.adoc

@ -3,13 +3,16 @@ @@ -3,13 +3,16 @@
[[auditing.basics]]
== Basics
Spring Data provides sophisticated support to transparently keep track of who created or changed an entity and when the change happened.To benefit from that functionality, you have to equip your entity classes with auditing metadata that can be defined either using annotations or by implementing an interface.
Spring Data provides sophisticated support to transparently keep track of who created or changed an entity and when the change happened.
To benefit from that functionality, you have to equip your entity classes with auditing metadata that can be defined either using annotations or by implementing an interface.
Additionally, auditing has to be enabled either through Annotation configuration or XML configuration to register the required infrastructure components.
Please refer to the store-specific section for configuration samples.
[NOTE]
====
Applications that only track creation and modification dates are not required do make their entities implement <<auditing.auditor-aware,`AuditorAware`>>.
If no `AuditorAware` or `DateTimeProvider` bean is configured, `AuditingHandler` will use Spring's autowiring to detect a matching bean if beans of the corresponding type are available in the application context.
====
[[auditing.annotations]]

10
src/main/java/org/springframework/data/auditing/AuditingHandler.java

@ -19,6 +19,8 @@ import java.util.Optional; @@ -19,6 +19,8 @@ import java.util.Optional;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jspecify.annotations.Nullable;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.data.domain.AuditorAware;
import org.springframework.data.mapping.context.MappingContext;
@ -66,12 +68,10 @@ public class AuditingHandler extends AuditingHandlerSupport implements Initializ @@ -66,12 +68,10 @@ public class AuditingHandler extends AuditingHandlerSupport implements Initializ
/**
* Setter to inject a {@code AuditorAware} component to retrieve the current auditor.
*
* @param auditorAware must not be {@literal null}.
* @param auditorAware can be {@literal null} if no auditor-aware is available.
*/
public void setAuditorAware(AuditorAware<?> auditorAware) {
Assert.notNull(auditorAware, "AuditorAware must not be null");
this.auditorAware = Optional.of(auditorAware);
public void setAuditorAware(@Nullable AuditorAware<?> auditorAware) {
this.auditorAware = Optional.ofNullable(auditorAware);
}
/**

10
src/main/java/org/springframework/data/auditing/ReactiveAuditingHandler.java

@ -17,6 +17,8 @@ package org.springframework.data.auditing; @@ -17,6 +17,8 @@ package org.springframework.data.auditing;
import reactor.core.publisher.Mono;
import org.jspecify.annotations.Nullable;
import org.springframework.data.domain.ReactiveAuditorAware;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.PersistentEntities;
@ -56,12 +58,10 @@ public class ReactiveAuditingHandler extends AuditingHandlerSupport { @@ -56,12 +58,10 @@ public class ReactiveAuditingHandler extends AuditingHandlerSupport {
/**
* Setter to inject a {@link ReactiveAuditorAware} component to retrieve the current auditor.
*
* @param auditorAware must not be {@literal null}.
* @param auditorAware can be {@literal null}.
*/
public void setAuditorAware(ReactiveAuditorAware<?> auditorAware) {
Assert.notNull(auditorAware, "AuditorAware must not be null");
this.auditorAware = auditorAware;
public void setAuditorAware(@Nullable ReactiveAuditorAware<?> auditorAware) {
this.auditorAware = auditorAware == null ? Mono::empty : auditorAware;
}
/**

8
src/main/java/org/springframework/data/auditing/config/AuditingBeanDefinitionRegistrarSupport.java

@ -116,12 +116,13 @@ public abstract class AuditingBeanDefinitionRegistrarSupport implements ImportBe @@ -116,12 +116,13 @@ public abstract class AuditingBeanDefinitionRegistrarSupport implements ImportBe
protected BeanDefinitionBuilder configureDefaultAuditHandlerAttributes(AuditingConfiguration configuration,
BeanDefinitionBuilder builder) {
builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
if (StringUtils.hasText(configuration.getAuditorAwareRef())) {
builder.addPropertyValue(AUDITOR_AWARE,
createLazyInitTargetSourceBeanDefinition(configuration.getAuditorAwareRef()));
}
else {
builder.addAutowiredProperty(AUDITOR_AWARE);
}
builder.addPropertyValue(SET_DATES, configuration.isSetDates());
builder.addPropertyValue(MODIFY_ON_CREATE, configuration.isModifyOnCreate());
@ -129,6 +130,9 @@ public abstract class AuditingBeanDefinitionRegistrarSupport implements ImportBe @@ -129,6 +130,9 @@ public abstract class AuditingBeanDefinitionRegistrarSupport implements ImportBe
if (StringUtils.hasText(configuration.getDateTimeProviderRef())) {
builder.addPropertyReference(DATE_TIME_PROVIDER, configuration.getDateTimeProviderRef());
}
else {
builder.addAutowiredProperty(DATE_TIME_PROVIDER);
}
builder.setRole(AbstractBeanDefinition.ROLE_INFRASTRUCTURE);

51
src/test/java/org/springframework/data/auditing/config/AuditingBeanDefinitionRegistrarSupportUnitTests.java

@ -20,19 +20,23 @@ import static org.mockito.ArgumentMatchers.*; @@ -20,19 +20,23 @@ import static org.mockito.ArgumentMatchers.*;
import static org.mockito.Mockito.*;
import java.lang.annotation.Annotation;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.config.AutowiredPropertyMarker;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.support.GenericApplicationContext;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.data.auditing.AuditingHandler;
import org.springframework.data.auditing.EnableAuditing;
import org.springframework.data.mapping.context.PersistentEntities;
/**
* Unit tests for {@link AuditingBeanDefinitionRegistrarSupport}.
@ -42,6 +46,7 @@ import org.springframework.data.auditing.EnableAuditing; @@ -42,6 +46,7 @@ import org.springframework.data.auditing.EnableAuditing;
* @author Oliver Gierke
* @author Francisco Soler
* @author Jaeyeon Kim
* @author Mark Paluch
*/
@ExtendWith(MockitoExtension.class)
class AuditingBeanDefinitionRegistrarSupportUnitTests {
@ -77,13 +82,28 @@ class AuditingBeanDefinitionRegistrarSupportUnitTests { @@ -77,13 +82,28 @@ class AuditingBeanDefinitionRegistrarSupportUnitTests {
.isThrownBy(() -> registrar.registerBeanDefinitions(metadata, null));
}
@Test // DATACMNS-3177
@Test // GH-3177
void setsAuditorAwareAndDateTimeProviderIfConfigured() {
AuditingConfiguration configuration = new DummyAuditingBeanDefinitionRegistrarSupport().getConfiguration(null);
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(AuditingHandler.class);
DummyAuditingBeanDefinitionRegistrarSupport registrar = new DummyAuditingBeanDefinitionRegistrarSupport();
BeanDefinitionBuilder result = registrar.configureDefaultAuditHandlerAttributes(configuration, builder);
AbstractBeanDefinition beanDefinition = result.getBeanDefinition();
assertThat(beanDefinition.getPropertyValues().contains("auditorAware")).isTrue();
assertThat(beanDefinition.getPropertyValues().contains("dateTimeProvider")).isTrue();
}
@Test // GH-3177
void doesNotSetAuditorAwareAndDateTimeProviderIfNotConfigured() {
AuditingConfiguration configuration = new AuditingConfiguration() {
@Override
public String getAuditorAwareRef() {
return "auditorAwareBean";
return "";
}
@Override
@ -93,7 +113,7 @@ class AuditingBeanDefinitionRegistrarSupportUnitTests { @@ -93,7 +113,7 @@ class AuditingBeanDefinitionRegistrarSupportUnitTests {
@Override
public String getDateTimeProviderRef() {
return "dateTimeProviderBean";
return "";
}
@Override
@ -108,13 +128,12 @@ class AuditingBeanDefinitionRegistrarSupportUnitTests { @@ -108,13 +128,12 @@ class AuditingBeanDefinitionRegistrarSupportUnitTests {
BeanDefinitionBuilder result = registrar.configureDefaultAuditHandlerAttributes(configuration, builder);
AbstractBeanDefinition beanDefinition = result.getBeanDefinition();
assertThat(beanDefinition.getAutowireMode()).isEqualTo(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
assertThat(beanDefinition.getPropertyValues().contains("auditorAware")).isTrue();
assertThat(beanDefinition.getPropertyValues().contains("dateTimeProvider")).isTrue();
assertThat(beanDefinition.getPropertyValues().get("auditorAware")).isEqualTo(AutowiredPropertyMarker.INSTANCE);
assertThat(beanDefinition.getPropertyValues().get("dateTimeProvider")).isEqualTo(AutowiredPropertyMarker.INSTANCE);
}
@Test // DATACMNS-3177
void doesNotSetAuditorAwareAndDateTimeProviderIfNotConfigured() {
@Test // GH-3177
void optionalAutowiringShouldConsiderOptionalProperties() {
AuditingConfiguration configuration = new AuditingConfiguration() {
@Override
@ -133,18 +152,24 @@ class AuditingBeanDefinitionRegistrarSupportUnitTests { @@ -133,18 +152,24 @@ class AuditingBeanDefinitionRegistrarSupportUnitTests {
}
@Override
public boolean isModifyOnCreate() { return true; }
public boolean isModifyOnCreate() {
return true;
}
};
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(AuditingHandler.class);
builder.addConstructorArgValue(PersistentEntities.of());
DummyAuditingBeanDefinitionRegistrarSupport registrar = new DummyAuditingBeanDefinitionRegistrarSupport();
BeanDefinitionBuilder result = registrar.configureDefaultAuditHandlerAttributes(configuration, builder);
AbstractBeanDefinition beanDefinition = result.getBeanDefinition();
assertThat(beanDefinition.getAutowireMode()).isEqualTo(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
assertThat(beanDefinition.getPropertyValues().contains("auditorAware")).isFalse();
assertThat(beanDefinition.getPropertyValues().contains("dateTimeProvider")).isFalse();
GenericApplicationContext context = new GenericApplicationContext();
context.registerBeanDefinition("auditingHandler", result.getBeanDefinition());
context.refresh();
AuditingHandler handler = context.getBean(AuditingHandler.class);
assertThat(handler).extracting("auditorAware").isEqualTo(Optional.empty());
}
static class SampleConfig {}

Loading…
Cancel
Save