|
29 | 29 | import reactor.core.publisher.Mono;
|
30 | 30 | import reactor.test.StepVerifier;
|
31 | 31 |
|
| 32 | +import java.nio.ByteBuffer; |
32 | 33 | import java.time.LocalDateTime;
|
33 | 34 | import java.util.ArrayList;
|
34 | 35 | import java.util.Collections;
|
|
43 | 44 | import org.springframework.data.annotation.LastModifiedDate;
|
44 | 45 | import org.springframework.data.annotation.Version;
|
45 | 46 | import org.springframework.data.auditing.ReactiveIsNewAwareAuditingHandler;
|
| 47 | +import org.springframework.data.convert.ReadingConverter; |
46 | 48 | import org.springframework.data.domain.Sort;
|
47 | 49 | import org.springframework.data.mapping.callback.ReactiveEntityCallbacks;
|
48 | 50 | import org.springframework.data.mapping.context.PersistentEntities;
|
@@ -91,7 +93,7 @@ void before() {
|
91 | 93 | .bindMarkers(PostgresDialect.INSTANCE.getBindMarkersFactory()).build();
|
92 | 94 |
|
93 | 95 | R2dbcCustomConversions conversions = R2dbcCustomConversions.of(PostgresDialect.INSTANCE, new MoneyConverter(),
|
94 |
| - new RowConverter(), new RowDocumentConverter()); |
| 96 | + new RowConverter(), new RowDocumentConverter(), new PkConverter()); |
95 | 97 |
|
96 | 98 | entityTemplate = new R2dbcEntityTemplate(client, PostgresDialect.INSTANCE,
|
97 | 99 | new MappingR2dbcConverter(new R2dbcMappingContext(), conversions));
|
@@ -632,6 +634,53 @@ void shouldConsiderRowConverter() {
|
632 | 634 | }).verifyComplete();
|
633 | 635 | }
|
634 | 636 |
|
| 637 | + @Test // GH-1725 |
| 638 | + void projectDtoShouldReadPropertiesOnce() { |
| 639 | + |
| 640 | + MockRowMetadata metadata = MockRowMetadata.builder() |
| 641 | + .columnMetadata(MockColumnMetadata.builder().name("number").type(R2dbcType.BINARY).build()).build(); |
| 642 | + |
| 643 | + ByteBuffer byteBuffer = ByteBuffer.allocate(8); |
| 644 | + byteBuffer.putDouble(1.2); |
| 645 | + byteBuffer.flip(); |
| 646 | + |
| 647 | + MockResult result = MockResult.builder() |
| 648 | + .row(MockRow.builder().identified("number", Object.class, byteBuffer).metadata(metadata).build()).build(); |
| 649 | + |
| 650 | + recorder.addStubbing(s -> s.startsWith("SELECT"), result); |
| 651 | + |
| 652 | + entityTemplate.select(WithDoubleHolder.class).as(DoubleHolderProjection.class).all().as(StepVerifier::create) // |
| 653 | + .assertNext(actual -> { |
| 654 | + assertThat(actual.number.number).isCloseTo(1.2d, withinPercentage(1d)); |
| 655 | + }).verifyComplete(); |
| 656 | + } |
| 657 | + |
| 658 | + @ReadingConverter |
| 659 | + static class PkConverter implements Converter<ByteBuffer, DoubleHolder> { |
| 660 | + |
| 661 | + @Nullable |
| 662 | + @Override |
| 663 | + public DoubleHolder convert(ByteBuffer source) { |
| 664 | + return new DoubleHolder(source.getDouble()); |
| 665 | + } |
| 666 | + } |
| 667 | + |
| 668 | + static class WithDoubleHolder { |
| 669 | + DoubleHolder number; |
| 670 | + } |
| 671 | + |
| 672 | + static class DoubleHolderProjection { |
| 673 | + DoubleHolder number; |
| 674 | + |
| 675 | + public DoubleHolderProjection(DoubleHolder number) { |
| 676 | + this.number = number; |
| 677 | + } |
| 678 | + } |
| 679 | + |
| 680 | + record DoubleHolder(double number) { |
| 681 | + |
| 682 | + } |
| 683 | + |
635 | 684 | @Test // GH-1696
|
636 | 685 | void shouldConsiderRowDocumentConverter() {
|
637 | 686 |
|
|
0 commit comments