Skip to content

Commit 6c3e1ac

Browse files
committed
Polishing.
Add autowriting support to auditing handler properties. See: #3177 Original pull request: #3385
1 parent 038eae6 commit 6c3e1ac

File tree

5 files changed

+58
-26
lines changed

5 files changed

+58
-26
lines changed

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,16 @@
33

44
[[auditing.basics]]
55
== Basics
6-
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.
6+
7+
Spring Data provides sophisticated support to transparently keep track of who created or changed an entity and when the change happened.
8+
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.
79
Additionally, auditing has to be enabled either through Annotation configuration or XML configuration to register the required infrastructure components.
810
Please refer to the store-specific section for configuration samples.
911

1012
[NOTE]
1113
====
1214
Applications that only track creation and modification dates are not required do make their entities implement <<auditing.auditor-aware,`AuditorAware`>>.
15+
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.
1316
====
1417

1518
[[auditing.annotations]]

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919

2020
import org.apache.commons.logging.Log;
2121
import org.apache.commons.logging.LogFactory;
22+
import org.jspecify.annotations.Nullable;
23+
2224
import org.springframework.beans.factory.InitializingBean;
2325
import org.springframework.data.domain.AuditorAware;
2426
import org.springframework.data.mapping.context.MappingContext;
@@ -66,12 +68,10 @@ public static AuditingHandler from(MappingContext<?, ?> mappingContext) {
6668
/**
6769
* Setter to inject a {@code AuditorAware} component to retrieve the current auditor.
6870
*
69-
* @param auditorAware must not be {@literal null}.
71+
* @param auditorAware can be {@literal null} if no auditor-aware is available.
7072
*/
71-
public void setAuditorAware(AuditorAware<?> auditorAware) {
72-
73-
Assert.notNull(auditorAware, "AuditorAware must not be null");
74-
this.auditorAware = Optional.of(auditorAware);
73+
public void setAuditorAware(@Nullable AuditorAware<?> auditorAware) {
74+
this.auditorAware = Optional.ofNullable(auditorAware);
7575
}
7676

7777
/**

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
import reactor.core.publisher.Mono;
1919

20+
import org.jspecify.annotations.Nullable;
21+
2022
import org.springframework.data.domain.ReactiveAuditorAware;
2123
import org.springframework.data.mapping.context.MappingContext;
2224
import org.springframework.data.mapping.context.PersistentEntities;
@@ -56,12 +58,10 @@ public static ReactiveAuditingHandler from(MappingContext<?, ?> mappingContext)
5658
/**
5759
* Setter to inject a {@link ReactiveAuditorAware} component to retrieve the current auditor.
5860
*
59-
* @param auditorAware must not be {@literal null}.
61+
* @param auditorAware can be {@literal null}.
6062
*/
61-
public void setAuditorAware(ReactiveAuditorAware<?> auditorAware) {
62-
63-
Assert.notNull(auditorAware, "AuditorAware must not be null");
64-
this.auditorAware = auditorAware;
63+
public void setAuditorAware(@Nullable ReactiveAuditorAware<?> auditorAware) {
64+
this.auditorAware = auditorAware == null ? Mono::empty : auditorAware;
6565
}
6666

6767
/**

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -116,19 +116,23 @@ protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingCon
116116
protected BeanDefinitionBuilder configureDefaultAuditHandlerAttributes(AuditingConfiguration configuration,
117117
BeanDefinitionBuilder builder) {
118118

119-
builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
120-
121119
if (StringUtils.hasText(configuration.getAuditorAwareRef())) {
122120
builder.addPropertyValue(AUDITOR_AWARE,
123121
createLazyInitTargetSourceBeanDefinition(configuration.getAuditorAwareRef()));
124122
}
123+
else {
124+
builder.addAutowiredProperty(AUDITOR_AWARE);
125+
}
125126

126127
builder.addPropertyValue(SET_DATES, configuration.isSetDates());
127128
builder.addPropertyValue(MODIFY_ON_CREATE, configuration.isModifyOnCreate());
128129

129130
if (StringUtils.hasText(configuration.getDateTimeProviderRef())) {
130131
builder.addPropertyReference(DATE_TIME_PROVIDER, configuration.getDateTimeProviderRef());
131132
}
133+
else {
134+
builder.addAutowiredProperty(DATE_TIME_PROVIDER);
135+
}
132136

133137
builder.setRole(AbstractBeanDefinition.ROLE_INFRASTRUCTURE);
134138

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

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,19 +20,23 @@
2020
import static org.mockito.Mockito.*;
2121

2222
import java.lang.annotation.Annotation;
23+
import java.util.Optional;
2324

2425
import org.junit.jupiter.api.Test;
2526
import org.junit.jupiter.api.extension.ExtendWith;
2627
import org.mockito.Mock;
2728
import org.mockito.junit.jupiter.MockitoExtension;
2829

30+
import org.springframework.beans.factory.config.AutowiredPropertyMarker;
2931
import org.springframework.beans.factory.config.BeanDefinition;
3032
import org.springframework.beans.factory.support.AbstractBeanDefinition;
3133
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
3234
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
35+
import org.springframework.context.support.GenericApplicationContext;
3336
import org.springframework.core.type.AnnotationMetadata;
3437
import org.springframework.data.auditing.AuditingHandler;
3538
import org.springframework.data.auditing.EnableAuditing;
39+
import org.springframework.data.mapping.context.PersistentEntities;
3640

3741
/**
3842
* Unit tests for {@link AuditingBeanDefinitionRegistrarSupport}.
@@ -42,6 +46,7 @@
4246
* @author Oliver Gierke
4347
* @author Francisco Soler
4448
* @author Jaeyeon Kim
49+
* @author Mark Paluch
4550
*/
4651
@ExtendWith(MockitoExtension.class)
4752
class AuditingBeanDefinitionRegistrarSupportUnitTests {
@@ -77,13 +82,28 @@ void rejectsNullRegistry() {
7782
.isThrownBy(() -> registrar.registerBeanDefinitions(metadata, null));
7883
}
7984

80-
@Test // DATACMNS-3177
85+
@Test // GH-3177
8186
void setsAuditorAwareAndDateTimeProviderIfConfigured() {
8287

88+
AuditingConfiguration configuration = new DummyAuditingBeanDefinitionRegistrarSupport().getConfiguration(null);
89+
90+
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(AuditingHandler.class);
91+
DummyAuditingBeanDefinitionRegistrarSupport registrar = new DummyAuditingBeanDefinitionRegistrarSupport();
92+
93+
BeanDefinitionBuilder result = registrar.configureDefaultAuditHandlerAttributes(configuration, builder);
94+
AbstractBeanDefinition beanDefinition = result.getBeanDefinition();
95+
96+
assertThat(beanDefinition.getPropertyValues().contains("auditorAware")).isTrue();
97+
assertThat(beanDefinition.getPropertyValues().contains("dateTimeProvider")).isTrue();
98+
}
99+
100+
@Test // GH-3177
101+
void doesNotSetAuditorAwareAndDateTimeProviderIfNotConfigured() {
102+
83103
AuditingConfiguration configuration = new AuditingConfiguration() {
84104
@Override
85105
public String getAuditorAwareRef() {
86-
return "auditorAwareBean";
106+
return "";
87107
}
88108

89109
@Override
@@ -93,7 +113,7 @@ public boolean isSetDates() {
93113

94114
@Override
95115
public String getDateTimeProviderRef() {
96-
return "dateTimeProviderBean";
116+
return "";
97117
}
98118

99119
@Override
@@ -108,13 +128,12 @@ public boolean isModifyOnCreate() {
108128
BeanDefinitionBuilder result = registrar.configureDefaultAuditHandlerAttributes(configuration, builder);
109129
AbstractBeanDefinition beanDefinition = result.getBeanDefinition();
110130

111-
assertThat(beanDefinition.getAutowireMode()).isEqualTo(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
112-
assertThat(beanDefinition.getPropertyValues().contains("auditorAware")).isTrue();
113-
assertThat(beanDefinition.getPropertyValues().contains("dateTimeProvider")).isTrue();
131+
assertThat(beanDefinition.getPropertyValues().get("auditorAware")).isEqualTo(AutowiredPropertyMarker.INSTANCE);
132+
assertThat(beanDefinition.getPropertyValues().get("dateTimeProvider")).isEqualTo(AutowiredPropertyMarker.INSTANCE);
114133
}
115134

116-
@Test // DATACMNS-3177
117-
void doesNotSetAuditorAwareAndDateTimeProviderIfNotConfigured() {
135+
@Test // GH-3177
136+
void optionalAutowiringShouldConsiderOptionalProperties() {
118137

119138
AuditingConfiguration configuration = new AuditingConfiguration() {
120139
@Override
@@ -133,18 +152,24 @@ public String getDateTimeProviderRef() {
133152
}
134153

135154
@Override
136-
public boolean isModifyOnCreate() { return true; }
155+
public boolean isModifyOnCreate() {
156+
return true;
157+
}
137158
};
138159

139160
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(AuditingHandler.class);
161+
builder.addConstructorArgValue(PersistentEntities.of());
140162
DummyAuditingBeanDefinitionRegistrarSupport registrar = new DummyAuditingBeanDefinitionRegistrarSupport();
141163

142164
BeanDefinitionBuilder result = registrar.configureDefaultAuditHandlerAttributes(configuration, builder);
143-
AbstractBeanDefinition beanDefinition = result.getBeanDefinition();
144165

145-
assertThat(beanDefinition.getAutowireMode()).isEqualTo(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
146-
assertThat(beanDefinition.getPropertyValues().contains("auditorAware")).isFalse();
147-
assertThat(beanDefinition.getPropertyValues().contains("dateTimeProvider")).isFalse();
166+
GenericApplicationContext context = new GenericApplicationContext();
167+
context.registerBeanDefinition("auditingHandler", result.getBeanDefinition());
168+
context.refresh();
169+
170+
AuditingHandler handler = context.getBean(AuditingHandler.class);
171+
172+
assertThat(handler).extracting("auditorAware").isEqualTo(Optional.empty());
148173
}
149174

150175
static class SampleConfig {}

0 commit comments

Comments
 (0)