18
18
import static java .util .Arrays .*;
19
19
import static java .util .Collections .*;
20
20
import static org .assertj .core .api .Assertions .*;
21
- import static org .mockito .ArgumentMatchers .*;
21
+ import static org .mockito .ArgumentMatchers .any ;
22
+ import static org .mockito .ArgumentMatchers .eq ;
22
23
import static org .mockito .Mockito .*;
23
24
24
25
import lombok .AllArgsConstructor ;
26
+ import lombok .EqualsAndHashCode ;
27
+ import lombok .NoArgsConstructor ;
25
28
import lombok .RequiredArgsConstructor ;
29
+ import lombok .SneakyThrows ;
26
30
import lombok .Value ;
27
31
import lombok .experimental .Wither ;
28
32
@@ -301,6 +305,101 @@ public void simpleImmutableEmbeddedGetsProperlyExtracted() throws SQLException {
301
305
.containsExactly (ID_FOR_ENTITY_NOT_REFERENCING_MAP , new ImmutableValue ("ru'Ha'" ));
302
306
}
303
307
308
+ @ Test // DATAJDBC-370
309
+ @ SneakyThrows
310
+ public void simplePrimitiveImmutableEmbeddedGetsProperlyExtracted () {
311
+
312
+ ResultSet rs = mockResultSet (asList ("id" , "value" ), //
313
+ ID_FOR_ENTITY_NOT_REFERENCING_MAP , 24 );
314
+ rs .next ();
315
+
316
+ WithPrimitiveImmutableValue extracted = createRowMapper (WithPrimitiveImmutableValue .class ).mapRow (rs , 1 );
317
+
318
+ assertThat (extracted ) //
319
+ .isNotNull () //
320
+ .extracting (e -> e .id , e -> e .embeddedImmutablePrimitiveValue ) //
321
+ .containsExactly (ID_FOR_ENTITY_NOT_REFERENCING_MAP , new ImmutablePrimitiveValue (24 ));
322
+ }
323
+
324
+ @ Test // DATAJDBC-370
325
+ public void simpleImmutableEmbeddedShouldBeNullIfAllOfTheEmbeddableAreNull () throws SQLException {
326
+
327
+ ResultSet rs = mockResultSet (asList ("id" , "value" ), //
328
+ ID_FOR_ENTITY_NOT_REFERENCING_MAP , null );
329
+ rs .next ();
330
+
331
+ WithImmutableValue extracted = createRowMapper (WithImmutableValue .class ).mapRow (rs , 1 );
332
+
333
+ assertThat (extracted ) //
334
+ .isNotNull () //
335
+ .extracting (e -> e .id , e -> e .embeddedImmutableValue ) //
336
+ .containsExactly (ID_FOR_ENTITY_NOT_REFERENCING_MAP , null );
337
+ }
338
+
339
+ @ Test // DATAJDBC-370
340
+ @ SneakyThrows
341
+ public void embeddedShouldBeNullWhenFieldsAreNull () {
342
+
343
+ ResultSet rs = mockResultSet (asList ("id" , "name" , "prefix_id" , "prefix_name" ), //
344
+ ID_FOR_ENTITY_NOT_REFERENCING_MAP , "alpha" , null , null );
345
+ rs .next ();
346
+
347
+ EmbeddedEntity extracted = createRowMapper (EmbeddedEntity .class ).mapRow (rs , 1 );
348
+
349
+ assertThat (extracted ) //
350
+ .isNotNull () //
351
+ .extracting (e -> e .id , e -> e .name , e -> e .children ) //
352
+ .containsExactly (ID_FOR_ENTITY_NOT_REFERENCING_MAP , "alpha" , null );
353
+ }
354
+
355
+ @ Test // DATAJDBC-370
356
+ @ SneakyThrows
357
+ public void embeddedShouldNotBeNullWhenAtLeastOneFieldIsNotNull () {
358
+
359
+ ResultSet rs = mockResultSet (asList ("id" , "name" , "prefix_id" , "prefix_name" ), //
360
+ ID_FOR_ENTITY_NOT_REFERENCING_MAP , "alpha" , 24 , null );
361
+ rs .next ();
362
+
363
+ EmbeddedEntity extracted = createRowMapper (EmbeddedEntity .class ).mapRow (rs , 1 );
364
+
365
+ assertThat (extracted ) //
366
+ .isNotNull () //
367
+ .extracting (e -> e .id , e -> e .name , e -> e .children ) //
368
+ .containsExactly (ID_FOR_ENTITY_NOT_REFERENCING_MAP , "alpha" , new Trivial (24L , null ));
369
+ }
370
+
371
+ @ Test // DATAJDBC-370
372
+ @ SneakyThrows
373
+ public void primitiveEmbeddedShouldBeNullWhenNoValuePresent () {
374
+
375
+ ResultSet rs = mockResultSet (asList ("id" , "value" ), //
376
+ ID_FOR_ENTITY_NOT_REFERENCING_MAP , null );
377
+ rs .next ();
378
+
379
+ WithPrimitiveImmutableValue extracted = createRowMapper (WithPrimitiveImmutableValue .class ).mapRow (rs , 1 );
380
+
381
+ assertThat (extracted ) //
382
+ .isNotNull () //
383
+ .extracting (e -> e .id , e -> e .embeddedImmutablePrimitiveValue ) //
384
+ .containsExactly (ID_FOR_ENTITY_NOT_REFERENCING_MAP , null );
385
+ }
386
+
387
+ @ Test // DATAJDBC-370
388
+ @ SneakyThrows
389
+ public void deepNestedEmbeddable () {
390
+
391
+ ResultSet rs = mockResultSet (asList ("id" , "level0" , "level1_value" , "level1_level2_value" ), //
392
+ ID_FOR_ENTITY_NOT_REFERENCING_MAP , "0" , "1" , "2" );
393
+ rs .next ();
394
+
395
+ WithDeepNestedEmbeddable extracted = createRowMapper (WithDeepNestedEmbeddable .class ).mapRow (rs , 1 );
396
+
397
+ assertThat (extracted ) //
398
+ .isNotNull () //
399
+ .extracting (e -> e .id , e -> extracted .level0 , e -> e .level1 .value , e -> e .level1 .level2 .value ) //
400
+ .containsExactly (ID_FOR_ENTITY_NOT_REFERENCING_MAP , "0" , "1" , "2" );
401
+ }
402
+
304
403
// Model classes to be used in tests
305
404
306
405
@ Wither
@@ -311,6 +410,9 @@ static class TrivialImmutable {
311
410
private final String name ;
312
411
}
313
412
413
+ @ EqualsAndHashCode
414
+ @ NoArgsConstructor
415
+ @ AllArgsConstructor
314
416
static class Trivial {
315
417
316
418
@ Id Long id ;
@@ -432,11 +534,35 @@ static class WithImmutableValue {
432
534
@ Embedded ImmutableValue embeddedImmutableValue ;
433
535
}
434
536
537
+ static class WithPrimitiveImmutableValue {
538
+
539
+ @ Id Long id ;
540
+ @ Embedded ImmutablePrimitiveValue embeddedImmutablePrimitiveValue ;
541
+ }
542
+
435
543
@ Value
436
544
static class ImmutableValue {
437
545
Object value ;
438
546
}
439
547
548
+ @ Value
549
+ static class ImmutablePrimitiveValue {
550
+ int value ;
551
+ }
552
+
553
+ static class WithDeepNestedEmbeddable {
554
+
555
+ @ Id Long id ;
556
+ String level0 ;
557
+ @ Embedded ("level1_" ) EmbeddedWithEmbedded level1 ;
558
+ }
559
+
560
+ static class EmbeddedWithEmbedded {
561
+
562
+ Object value ;
563
+ @ Embedded ("level2_" ) ImmutableValue level2 ;
564
+ }
565
+
440
566
// Infrastructure for assertions and constructing mocks
441
567
442
568
private <T > FixtureBuilder <T > buildFixture () {
@@ -454,22 +580,23 @@ private <T> EntityRowMapper<T> createRowMapper(Class<T> type, NamingStrategy nam
454
580
DataAccessStrategy accessStrategy = mock (DataAccessStrategy .class );
455
581
456
582
// the ID of the entity is used to determine what kind of ResultSet is needed for subsequent selects.
457
- doReturn (new HashSet <>(asList (new Trivial (), new Trivial ()))).when (accessStrategy )
583
+ doReturn (new HashSet <>(asList (new Trivial (1L , "one" ), new Trivial (2L , "two" )))).when (accessStrategy )
458
584
.findAllByProperty (eq (ID_FOR_ENTITY_NOT_REFERENCING_MAP ), any (RelationalPersistentProperty .class ));
459
585
460
586
doReturn (new HashSet <>(asList ( //
461
- new SimpleEntry <>("one" , new Trivial ()), //
462
- new SimpleEntry <>("two" , new Trivial ()) //
587
+ new SimpleEntry <>("one" , new Trivial (1L , "one" )), //
588
+ new SimpleEntry <>("two" , new Trivial (2L , "two" )) //
463
589
))).when (accessStrategy ).findAllByProperty (eq (ID_FOR_ENTITY_REFERENCING_MAP ),
464
590
any (RelationalPersistentProperty .class ));
465
591
466
592
doReturn (new HashSet <>(asList ( //
467
- new SimpleEntry <>(1 , new Trivial ()), //
468
- new SimpleEntry <>(2 , new Trivial ()) //
593
+ new SimpleEntry <>(1 , new Trivial (1L , "one" )), //
594
+ new SimpleEntry <>(2 , new Trivial (2L , "tow" )) //
469
595
))).when (accessStrategy ).findAllByProperty (eq (ID_FOR_ENTITY_REFERENCING_LIST ),
470
596
any (RelationalPersistentProperty .class ));
471
597
472
- JdbcConverter converter = new BasicJdbcConverter (context , new JdbcCustomConversions ());
598
+ JdbcConverter converter = new BasicJdbcConverter (context , new JdbcCustomConversions (),
599
+ JdbcTypeFactory .unsupported ());
473
600
474
601
return new EntityRowMapper <>( //
475
602
(RelationalPersistentEntity <T >) context .getRequiredPersistentEntity (type ), //
0 commit comments