2828import java .math .BigDecimal ;
2929import java .math .BigInteger ;
3030import java .net .URL ;
31+ import java .nio .ByteBuffer ;
3132import java .time .LocalDate ;
3233import java .time .LocalDateTime ;
3334import java .time .temporal .ChronoUnit ;
3435import java .util .*;
3536
37+ import org .assertj .core .data .Percentage ;
38+ import org .bson .BsonUndefined ;
3639import org .bson .types .Binary ;
3740import org .bson .types .Code ;
3841import org .bson .types .Decimal128 ;
@@ -125,7 +128,8 @@ class MappingMongoConverterUnitTests {
125128 @ BeforeEach
126129 void beforeEach () {
127130
128- MongoCustomConversions conversions = new MongoCustomConversions ();
131+ MongoCustomConversions conversions = new MongoCustomConversions (
132+ Arrays .asList (new ByteBufferToDoubleHolderConverter ()));
129133
130134 mappingContext = new MongoMappingContext ();
131135 mappingContext .setApplicationContext (context );
@@ -1437,7 +1441,7 @@ void shouldWriteEntityWithGeoCircleCorrectly() {
14371441 assertThat (document .get ("circle" )).isInstanceOf (org .bson .Document .class );
14381442 assertThat (document .get ("circle" )).isEqualTo ((Object ) new org .bson .Document ("center" ,
14391443 new org .bson .Document ("x" , circle .getCenter ().getX ()).append ("y" , circle .getCenter ().getY ()))
1440- .append ("radius" , radius .getNormalizedValue ()).append ("metric" , radius .getMetric ().toString ()));
1444+ .append ("radius" , radius .getNormalizedValue ()).append ("metric" , radius .getMetric ().toString ()));
14411445 }
14421446
14431447 @ Test // DATAMONGO-858
@@ -1470,7 +1474,7 @@ void shouldWriteEntityWithGeoSphereCorrectly() {
14701474 assertThat (document .get ("sphere" )).isInstanceOf (org .bson .Document .class );
14711475 assertThat (document .get ("sphere" )).isEqualTo ((Object ) new org .bson .Document ("center" ,
14721476 new org .bson .Document ("x" , sphere .getCenter ().getX ()).append ("y" , sphere .getCenter ().getY ()))
1473- .append ("radius" , radius .getNormalizedValue ()).append ("metric" , radius .getMetric ().toString ()));
1477+ .append ("radius" , radius .getNormalizedValue ()).append ("metric" , radius .getMetric ().toString ()));
14741478 }
14751479
14761480 @ Test // DATAMONGO-858
@@ -1488,7 +1492,7 @@ void shouldWriteEntityWithGeoSphereWithMetricDistanceCorrectly() {
14881492 assertThat (document .get ("sphere" )).isInstanceOf (org .bson .Document .class );
14891493 assertThat (document .get ("sphere" )).isEqualTo ((Object ) new org .bson .Document ("center" ,
14901494 new org .bson .Document ("x" , sphere .getCenter ().getX ()).append ("y" , sphere .getCenter ().getY ()))
1491- .append ("radius" , radius .getNormalizedValue ()).append ("metric" , radius .getMetric ().toString ()));
1495+ .append ("radius" , radius .getNormalizedValue ()).append ("metric" , radius .getMetric ().toString ()));
14921496 }
14931497
14941498 @ Test // DATAMONGO-858
@@ -1521,7 +1525,7 @@ void shouldWriteEntityWithGeoShapeCorrectly() {
15211525 assertThat (document .get ("shape" )).isInstanceOf (org .bson .Document .class );
15221526 assertThat (document .get ("shape" )).isEqualTo ((Object ) new org .bson .Document ("center" ,
15231527 new org .bson .Document ("x" , sphere .getCenter ().getX ()).append ("y" , sphere .getCenter ().getY ()))
1524- .append ("radius" , radius .getNormalizedValue ()).append ("metric" , radius .getMetric ().toString ()));
1528+ .append ("radius" , radius .getNormalizedValue ()).append ("metric" , radius .getMetric ().toString ()));
15251529 }
15261530
15271531 @ Test // DATAMONGO-858
@@ -2531,8 +2535,8 @@ void usesCustomConverterForPropertiesUsingTypesImplementingMapOnRead() {
25312535 converter .afterPropertiesSet ();
25322536
25332537 org .bson .Document source = new org .bson .Document ("typeImplementingMap" ,
2534- new org .bson .Document ("1st" , "one" ).append ("2nd" , 2 )). append ( "_class" ,
2535- TypeWrappingTypeImplementingMap .class .getName ());
2538+ new org .bson .Document ("1st" , "one" ).append ("2nd" , 2 ))
2539+ . append ( "_class" , TypeWrappingTypeImplementingMap .class .getName ());
25362540
25372541 TypeWrappingTypeImplementingMap target = converter .read (TypeWrappingTypeImplementingMap .class , source );
25382542
@@ -2720,8 +2724,8 @@ void projectShouldReadNestedInterfaceProjection() {
27202724 .and ((target , underlyingType ) -> !converter .conversions .isSimpleType (target )),
27212725 mappingContext );
27222726
2723- EntityProjection <WithNestedInterfaceProjection , Person > projection = introspector . introspect ( WithNestedInterfaceProjection . class ,
2724- Person .class );
2727+ EntityProjection <WithNestedInterfaceProjection , Person > projection = introspector
2728+ . introspect ( WithNestedInterfaceProjection . class , Person .class );
27252729 WithNestedInterfaceProjection person = converter .project (projection , source );
27262730
27272731 assertThat (person .getFirstname ()).isEqualTo ("spring" );
@@ -2739,14 +2743,35 @@ void projectShouldReadNestedDtoProjection() {
27392743 .and ((target , underlyingType ) -> !converter .conversions .isSimpleType (target )),
27402744 mappingContext );
27412745
2742- EntityProjection <WithNestedDtoProjection , Person > projection = introspector . introspect ( WithNestedDtoProjection . class ,
2743- Person .class );
2746+ EntityProjection <WithNestedDtoProjection , Person > projection = introspector
2747+ . introspect ( WithNestedDtoProjection . class , Person .class );
27442748 WithNestedDtoProjection person = converter .project (projection , source );
27452749
27462750 assertThat (person .getFirstname ()).isEqualTo ("spring" );
27472751 assertThat (person .getAddress ().getStreet ()).isEqualTo ("data" );
27482752 }
27492753
2754+ @ Test // GH-4626
2755+ void projectShouldReadDtoProjectionPropertiesOnlyOnce () {
2756+
2757+ ByteBuffer number = ByteBuffer .allocate (8 );
2758+ number .putDouble (1.2d );
2759+ number .flip ();
2760+
2761+ org .bson .Document source = new org .bson .Document ("number" , number );
2762+
2763+ EntityProjectionIntrospector introspector = EntityProjectionIntrospector .create (converter .getProjectionFactory (),
2764+ EntityProjectionIntrospector .ProjectionPredicate .typeHierarchy ()
2765+ .and ((target , underlyingType ) -> !converter .conversions .isSimpleType (target )),
2766+ mappingContext );
2767+
2768+ EntityProjection <DoubleHolderDto , WithDoubleHolder > projection = introspector .introspect (DoubleHolderDto .class ,
2769+ WithDoubleHolder .class );
2770+ DoubleHolderDto result = converter .project (projection , source );
2771+
2772+ assertThat (result .number .number ).isCloseTo (1.2 , Percentage .withPercentage (1 ));
2773+ }
2774+
27502775 @ Test // GH-2860
27512776 void projectShouldReadProjectionWithNestedEntity () {
27522777
@@ -3022,11 +3047,13 @@ interface WithNestedProjection {
30223047
30233048 interface WithNestedInterfaceProjection {
30243049 String getFirstname ();
3050+
30253051 AddressProjection getAddress ();
30263052 }
30273053
30283054 interface WithNestedDtoProjection {
30293055 String getFirstname ();
3056+
30303057 AddressDto getAddress ();
30313058 }
30323059
@@ -3925,4 +3952,30 @@ static class ComplexIdAndNoAnnotation {
39253952 ComplexId id ;
39263953 String value ;
39273954 }
3955+
3956+ @ ReadingConverter
3957+ static class ByteBufferToDoubleHolderConverter implements Converter <ByteBuffer , DoubleHolder > {
3958+
3959+ @ Override
3960+ public DoubleHolder convert (ByteBuffer source ) {
3961+ return new DoubleHolder (source .getDouble ());
3962+ }
3963+ }
3964+
3965+ record DoubleHolder (double number ) {
3966+
3967+ }
3968+
3969+ static class WithDoubleHolder {
3970+ DoubleHolder number ;
3971+ }
3972+
3973+ static class DoubleHolderDto {
3974+ DoubleHolder number ;
3975+
3976+ public DoubleHolderDto (DoubleHolder number ) {
3977+ this .number = number ;
3978+ }
3979+ }
3980+
39283981}
0 commit comments