4444import org .springframework .data .jdbc .testing .IntegrationTest ;
4545import org .springframework .data .jdbc .testing .TestClass ;
4646import org .springframework .data .jdbc .testing .TestConfiguration ;
47+ import org .springframework .data .relational .core .mapping .Embedded ;
4748import org .springframework .data .relational .core .mapping .NamingStrategy ;
4849import org .springframework .data .relational .core .mapping .event .BeforeConvertCallback ;
4950import org .springframework .data .relational .core .mapping .event .BeforeSaveEvent ;
@@ -68,50 +69,50 @@ public void auditForAnnotatedEntity() {
6869 AuditingAnnotatedDummyEntityRepository .class , //
6970 Config .class , //
7071 AuditingConfiguration .class ) //
71- .accept (repository -> {
72+ .accept (repository -> {
7273
73- AuditingConfiguration .currentAuditor = "user01" ;
74- LocalDateTime now = LocalDateTime .now ();
74+ AuditingConfiguration .currentAuditor = "user01" ;
75+ LocalDateTime now = LocalDateTime .now ();
7576
76- AuditingAnnotatedDummyEntity entity = repository .save (new AuditingAnnotatedDummyEntity ());
77+ AuditingAnnotatedDummyEntity entity = repository .save (new AuditingAnnotatedDummyEntity ());
7778
78- assertThat (entity .id ).as ("id not null" ).isNotNull ();
79- assertThat (entity .getCreatedBy ()).as ("created by set" ).isEqualTo ("user01" );
80- assertThat (entity .getCreatedDate ()).as ("created date set" ).isAfter (now );
81- assertThat (entity .getLastModifiedBy ()).as ("modified by set" ).isEqualTo ("user01" );
82- assertThat (entity .getLastModifiedDate ()).as ("modified date set" )
83- .isAfterOrEqualTo (entity .getCreatedDate ());
84- assertThat (entity .getLastModifiedDate ()).as ("modified date after instance creation" ).isAfter (now );
79+ assertThat (entity .id ).as ("id not null" ).isNotNull ();
80+ assertThat (entity .getCreatedBy ()).as ("created by set" ).isEqualTo ("user01" );
81+ assertThat (entity .getCreatedDate ()).as ("created date set" ).isAfter (now );
82+ assertThat (entity .getLastModifiedBy ()).as ("modified by set" ).isEqualTo ("user01" );
83+ assertThat (entity .getLastModifiedDate ()).as ("modified date set" )
84+ .isAfterOrEqualTo (entity .getCreatedDate ());
85+ assertThat (entity .getLastModifiedDate ()).as ("modified date after instance creation" ).isAfter (now );
8586
86- AuditingAnnotatedDummyEntity reloaded = repository .findById (entity .id ).get ();
87+ AuditingAnnotatedDummyEntity reloaded = repository .findById (entity .id ).get ();
8788
88- assertThat (reloaded .getCreatedBy ()).as ("reload created by" ).isNotNull ();
89- assertThat (reloaded .getCreatedDate ()).as ("reload created date" ).isNotNull ();
90- assertThat (reloaded .getLastModifiedBy ()).as ("reload modified by" ).isNotNull ();
91- assertThat (reloaded .getLastModifiedDate ()).as ("reload modified date" ).isNotNull ();
89+ assertThat (reloaded .getCreatedBy ()).as ("reload created by" ).isNotNull ();
90+ assertThat (reloaded .getCreatedDate ()).as ("reload created date" ).isNotNull ();
91+ assertThat (reloaded .getLastModifiedBy ()).as ("reload modified by" ).isNotNull ();
92+ assertThat (reloaded .getLastModifiedDate ()).as ("reload modified date" ).isNotNull ();
9293
93- LocalDateTime beforeCreatedDate = entity .getCreatedDate ();
94- LocalDateTime beforeLastModifiedDate = entity .getLastModifiedDate ();
94+ LocalDateTime beforeCreatedDate = entity .getCreatedDate ();
95+ LocalDateTime beforeLastModifiedDate = entity .getLastModifiedDate ();
9596
96- sleepMillis (10 );
97+ sleepMillis (10 );
9798
98- AuditingConfiguration .currentAuditor = "user02" ;
99+ AuditingConfiguration .currentAuditor = "user02" ;
99100
100- entity = repository .save (entity );
101+ entity = repository .save (entity );
101102
102- assertThat (entity .getCreatedBy ()).as ("created by unchanged" ).isEqualTo ("user01" );
103- assertThat (entity .getCreatedDate ()).as ("created date unchanged" ).isEqualTo (beforeCreatedDate );
104- assertThat (entity .getLastModifiedBy ()).as ("modified by updated" ).isEqualTo ("user02" );
105- assertThat (entity .getLastModifiedDate ()).as ("modified date updated" )
106- .isAfter (beforeLastModifiedDate );
103+ assertThat (entity .getCreatedBy ()).as ("created by unchanged" ).isEqualTo ("user01" );
104+ assertThat (entity .getCreatedDate ()).as ("created date unchanged" ).isEqualTo (beforeCreatedDate );
105+ assertThat (entity .getLastModifiedBy ()).as ("modified by updated" ).isEqualTo ("user02" );
106+ assertThat (entity .getLastModifiedDate ()).as ("modified date updated" )
107+ .isAfter (beforeLastModifiedDate );
107108
108- reloaded = repository .findById (entity .id ).get ();
109+ reloaded = repository .findById (entity .id ).get ();
109110
110- assertThat (reloaded .getCreatedBy ()).as ("2. reload created by" ).isNotNull ();
111- assertThat (reloaded .getCreatedDate ()).as ("2. reload created date" ).isNotNull ();
112- assertThat (reloaded .getLastModifiedBy ()).as ("2. reload modified by" ).isNotNull ();
113- assertThat (reloaded .getLastModifiedDate ()).as ("2. reload modified date" ).isNotNull ();
114- });
111+ assertThat (reloaded .getCreatedBy ()).as ("2. reload created by" ).isNotNull ();
112+ assertThat (reloaded .getCreatedDate ()).as ("2. reload created date" ).isNotNull ();
113+ assertThat (reloaded .getLastModifiedBy ()).as ("2. reload modified by" ).isNotNull ();
114+ assertThat (reloaded .getLastModifiedDate ()).as ("2. reload modified date" ).isNotNull ();
115+ });
115116 }
116117
117118 @ Test // DATAJDBC-204
@@ -121,17 +122,17 @@ public void noAnnotatedEntity() {
121122 DummyEntityRepository .class , //
122123 Config .class , //
123124 AuditingConfiguration .class ) //
124- .accept (repository -> {
125+ .accept (repository -> {
125126
126- DummyEntity entity = repository .save (new DummyEntity ());
127+ DummyEntity entity = repository .save (new DummyEntity ());
127128
128- assertThat (entity .id ).isNotNull ();
129- assertThat (repository .findById (entity .id ).get ()).isEqualTo (entity );
129+ assertThat (entity .id ).isNotNull ();
130+ assertThat (repository .findById (entity .id ).get ()).isEqualTo (entity );
130131
131- entity = repository .save (entity );
132+ entity = repository .save (entity );
132133
133- assertThat (repository .findById (entity .id )).contains (entity );
134- });
134+ assertThat (repository .findById (entity .id )).contains (entity );
135+ });
135136 }
136137
137138 @ Test // DATAJDBC-204
@@ -141,19 +142,19 @@ public void customDateTimeProvider() {
141142 AuditingAnnotatedDummyEntityRepository .class , //
142143 Config .class , //
143144 CustomizeAuditorAwareAndDateTimeProvider .class ) //
144- .accept (repository -> {
145+ .accept (repository -> {
145146
146- LocalDateTime currentDateTime = LocalDate .of (2018 , 4 , 14 ).atStartOfDay ();
147- CustomizeAuditorAwareAndDateTimeProvider .currentDateTime = currentDateTime ;
147+ LocalDateTime currentDateTime = LocalDate .of (2018 , 4 , 14 ).atStartOfDay ();
148+ CustomizeAuditorAwareAndDateTimeProvider .currentDateTime = currentDateTime ;
148149
149- AuditingAnnotatedDummyEntity entity = repository .save (new AuditingAnnotatedDummyEntity ());
150+ AuditingAnnotatedDummyEntity entity = repository .save (new AuditingAnnotatedDummyEntity ());
150151
151- assertThat (entity .id ).isNotNull ();
152- assertThat (entity .getCreatedBy ()).isEqualTo ("custom user" );
153- assertThat (entity .getCreatedDate ()).isEqualTo (currentDateTime );
154- assertThat (entity .getLastModifiedBy ()).isNull ();
155- assertThat (entity .getLastModifiedDate ()).isNull ();
156- });
152+ assertThat (entity .id ).isNotNull ();
153+ assertThat (entity .getCreatedBy ()).isEqualTo ("custom user" );
154+ assertThat (entity .getCreatedDate ()).isEqualTo (currentDateTime );
155+ assertThat (entity .getLastModifiedBy ()).isNull ();
156+ assertThat (entity .getLastModifiedDate ()).isNull ();
157+ });
157158 }
158159
159160 @ Test // DATAJDBC-204
@@ -163,16 +164,16 @@ public void customAuditorAware() {
163164 AuditingAnnotatedDummyEntityRepository .class , //
164165 Config .class , //
165166 CustomizeAuditorAware .class ) //
166- .accept (repository -> {
167+ .accept (repository -> {
167168
168- AuditingAnnotatedDummyEntity entity = repository .save (new AuditingAnnotatedDummyEntity ());
169+ AuditingAnnotatedDummyEntity entity = repository .save (new AuditingAnnotatedDummyEntity ());
169170
170- assertThat (entity .id ).isNotNull ();
171- assertThat (entity .getCreatedBy ()).isEqualTo ("user" );
172- assertThat (entity .getCreatedDate ()).isNull ();
173- assertThat (entity .getLastModifiedBy ()).isEqualTo ("user" );
174- assertThat (entity .getLastModifiedDate ()).isNull ();
175- });
171+ assertThat (entity .id ).isNotNull ();
172+ assertThat (entity .getCreatedBy ()).isEqualTo ("user" );
173+ assertThat (entity .getCreatedDate ()).isNull ();
174+ assertThat (entity .getLastModifiedBy ()).isEqualTo ("user" );
175+ assertThat (entity .getLastModifiedDate ()).isNull ();
176+ });
176177 }
177178
178179 @ Test // DATAJDBC-390
@@ -193,21 +194,97 @@ public void auditingListenerTriggersBeforeDefaultListener() {
193194 });
194195 }
195196
197+
198+ @ Test // DATAJDBC-1694
199+ public void auditEmbeddedRecord () {
200+
201+ configureRepositoryWith ( //
202+ DummyEntityWithEmbeddedRecordRepository .class , //
203+ Config .class , //
204+ AuditingConfiguration .class ) //
205+ .accept (repository -> {
206+
207+ AuditingConfiguration .currentAuditor = "user01" ;
208+ LocalDateTime now = LocalDateTime .now ();
209+
210+ DummyEntityWithEmbeddedRecord entity = repository .save (new DummyEntityWithEmbeddedRecord (null , new EmbeddedAuditing (null , null , null , null )));
211+
212+ assertThat (entity .id ).as ("id not null" ).isNotNull ();
213+ assertThat (entity .auditing .createdBy ).as ("created by set" ).isEqualTo ("user01" );
214+ assertThat (entity .auditing .createdDate ()).as ("created date set" ).isAfter (now );
215+ assertThat (entity .auditing .lastModifiedBy ()).as ("modified by set" ).isEqualTo ("user01" );
216+ assertThat (entity .auditing .lastModifiedDate ()).as ("modified date set" )
217+ .isAfterOrEqualTo (entity .auditing .createdDate ());
218+ assertThat (entity .auditing .lastModifiedDate ()).as ("modified date after instance creation" ).isAfter (now );
219+
220+ DummyEntityWithEmbeddedRecord reloaded = repository .findById (entity .id ).get ();
221+
222+ assertThat (reloaded .auditing .createdBy ()).as ("reload created by" ).isNotNull ();
223+ assertThat (reloaded .auditing .createdDate ()).as ("reload created date" ).isNotNull ();
224+ assertThat (reloaded .auditing .lastModifiedBy ()).as ("reload modified by" ).isNotNull ();
225+ assertThat (reloaded .auditing .lastModifiedDate ()).as ("reload modified date" ).isNotNull ();
226+
227+ LocalDateTime beforeCreatedDate = entity .auditing ().createdDate ;
228+ LocalDateTime beforeLastModifiedDate = entity .auditing ().lastModifiedDate ;
229+
230+ sleepMillis (10 );
231+
232+ AuditingConfiguration .currentAuditor = "user02" ;
233+
234+ entity = repository .save (entity );
235+
236+ assertThat (entity .auditing .createdBy ()).as ("created by unchanged" ).isEqualTo ("user01" );
237+ assertThat (entity .auditing .createdDate ()).as ("created date unchanged" ).isEqualTo (beforeCreatedDate );
238+ assertThat (entity .auditing .lastModifiedBy ()).as ("modified by updated" ).isEqualTo ("user02" );
239+ assertThat (entity .auditing .lastModifiedDate ()).as ("modified date updated" )
240+ .isAfter (beforeLastModifiedDate );
241+
242+ reloaded = repository .findById (entity .id ).get ();
243+
244+ assertThat (reloaded .auditing .createdBy ()).as ("2. reload created by" ).isNotNull ();
245+ assertThat (reloaded .auditing .createdDate ()).as ("2. reload created date" ).isNotNull ();
246+ assertThat (reloaded .auditing .lastModifiedBy ()).as ("2. reload modified by" ).isNotNull ();
247+ assertThat (reloaded .auditing .lastModifiedDate ()).as ("2. reload modified date" ).isNotNull ();
248+ });
249+ }
250+ @ Test // DATAJDBC-1694
251+ public void auditEmbeddedNullRecordStaysNull () {
252+
253+ configureRepositoryWith ( //
254+ DummyEntityWithEmbeddedRecordRepository .class , //
255+ Config .class , //
256+ AuditingConfiguration .class ) //
257+ .accept (repository -> {
258+
259+ AuditingConfiguration .currentAuditor = "user01" ;
260+
261+ DummyEntityWithEmbeddedRecord entity = repository .save (new DummyEntityWithEmbeddedRecord (null , null ));
262+
263+ assertThat (entity .id ).as ("id not null" ).isNotNull ();
264+ assertThat (entity .auditing ).isNull ();
265+
266+ DummyEntityWithEmbeddedRecord reloaded = repository .findById (entity .id ).get ();
267+
268+ assertThat (reloaded .auditing ).isNull ();
269+ });
270+ }
271+
272+
196273 /**
197274 * Usage looks like this:
198275 * <p>
199276 * {@code configure(MyRepository.class, MyConfiguration) .accept(repository -> { // perform tests on repository here
200277 * }); }
201278 *
202- * @param repositoryType the type of repository you want to perform tests on.
279+ * @param repositoryType the type of repository you want to perform tests on.
203280 * @param configurationClasses the classes containing the configuration for the
204- * {@link org.springframework.context.ApplicationContext}.
205- * @param <T> type of the entity managed by the repository.
206- * @param <R> type of the repository.
281+ * {@link org.springframework.context.ApplicationContext}.
282+ * @param <T> type of the entity managed by the repository.
283+ * @param <R> type of the repository.
207284 * @return a Consumer for repositories of type {@code R}.
208285 */
209286 private <T , R extends CrudRepository <T , Long >> Consumer <Consumer <R >> configureRepositoryWith (Class <R > repositoryType ,
210- Class ... configurationClasses ) {
287+ Class ... configurationClasses ) {
211288
212289 return (Consumer <R > test ) -> {
213290
@@ -228,15 +305,21 @@ private void sleepMillis(int timeout) {
228305 }
229306 }
230307
231- interface AuditingAnnotatedDummyEntityRepository extends CrudRepository <AuditingAnnotatedDummyEntity , Long > {}
308+ interface AuditingAnnotatedDummyEntityRepository extends CrudRepository <AuditingAnnotatedDummyEntity , Long > {
309+ }
232310
233311 static class AuditingAnnotatedDummyEntity {
234312
235- @ Id long id ;
236- @ CreatedBy String createdBy ;
237- @ CreatedDate LocalDateTime createdDate ;
238- @ LastModifiedBy String lastModifiedBy ;
239- @ LastModifiedDate LocalDateTime lastModifiedDate ;
313+ @ Id
314+ long id ;
315+ @ CreatedBy
316+ String createdBy ;
317+ @ CreatedDate
318+ LocalDateTime createdDate ;
319+ @ LastModifiedBy
320+ String lastModifiedBy ;
321+ @ LastModifiedDate
322+ LocalDateTime lastModifiedDate ;
240323
241324 public long getId () {
242325 return this .id ;
@@ -279,11 +362,13 @@ public void setLastModifiedDate(LocalDateTime lastModifiedDate) {
279362 }
280363 }
281364
282- interface DummyEntityRepository extends CrudRepository <DummyEntity , Long > {}
365+ interface DummyEntityRepository extends CrudRepository <DummyEntity , Long > {
366+ }
283367
284368 static class DummyEntity {
285369
286- @ Id private Long id ;
370+ @ Id
371+ private Long id ;
287372 // not actually used, exists just to avoid empty value list during insert.
288373 String name ;
289374
@@ -319,6 +404,22 @@ public int hashCode() {
319404 }
320405 }
321406
407+ record DummyEntityWithEmbeddedRecord (
408+ @ Id Long id ,
409+ @ Embedded .Nullable EmbeddedAuditing auditing
410+ ) {
411+ }
412+
413+ record EmbeddedAuditing (
414+ @ CreatedBy String createdBy ,
415+ @ CreatedDate LocalDateTime createdDate ,
416+ @ LastModifiedBy String lastModifiedBy ,
417+ @ LastModifiedDate LocalDateTime lastModifiedDate
418+ ) {
419+ }
420+ interface DummyEntityWithEmbeddedRecordRepository extends CrudRepository <DummyEntityWithEmbeddedRecord , Long > {
421+ }
422+
322423 @ Configuration
323424 @ EnableJdbcRepositories (considerNestedRepositories = true )
324425 @ Import (TestConfiguration .class )
0 commit comments