1515 */
1616package org .springframework .data .mongodb .core ;
1717
18- import static org .assertj .core .api .Assertions .*;
19- import static org .springframework .data .mongodb .core .query .Criteria .*;
20- import static org .springframework .data .mongodb .core .query .Query .*;
21- import static org .springframework .data .mongodb .core .query .Update .*;
18+ import static org .assertj .core .api .Assertions .assertThat ;
19+ import static org .assertj .core .api .Assertions .assertThatExceptionOfType ;
20+ import static org .assertj .core .api .Assertions .assertThatIllegalArgumentException ;
21+ import static org .assertj .core .api .Assertions .fail ;
22+ import static org .springframework .data .mongodb .core .query .Criteria .expr ;
23+ import static org .springframework .data .mongodb .core .query .Criteria .where ;
24+ import static org .springframework .data .mongodb .core .query .Query .query ;
25+ import static org .springframework .data .mongodb .core .query .Update .update ;
2226
2327import java .lang .reflect .InvocationTargetException ;
2428import java .math .BigDecimal ;
2832import java .time .LocalDateTime ;
2933import java .time .ZoneId ;
3034import java .time .temporal .ChronoUnit ;
31- import java .util .*;
35+ import java .util .ArrayList ;
36+ import java .util .Arrays ;
37+ import java .util .Calendar ;
38+ import java .util .Collections ;
39+ import java .util .Date ;
40+ import java .util .HashMap ;
41+ import java .util .Iterator ;
42+ import java .util .LinkedHashMap ;
43+ import java .util .List ;
44+ import java .util .Locale ;
45+ import java .util .Map ;
46+ import java .util .Objects ;
47+ import java .util .UUID ;
3248import java .util .concurrent .atomic .AtomicReference ;
3349import java .util .stream .Collectors ;
3450import java .util .stream .IntStream ;
3551import java .util .stream .Stream ;
3652
53+ import org .bson .codecs .configuration .CodecConfigurationException ;
3754import org .bson .types .ObjectId ;
3855import org .jspecify .annotations .Nullable ;
3956import org .junit .jupiter .api .AfterEach ;
4057import org .junit .jupiter .api .Test ;
41-
4258import org .springframework .context .ConfigurableApplicationContext ;
4359import org .springframework .context .support .GenericApplicationContext ;
4460import org .springframework .core .convert .ConversionFailedException ;
6985import org .springframework .data .mongodb .core .convert .LazyLoadingProxy ;
7086import org .springframework .data .mongodb .core .convert .MappingMongoConverter ;
7187import org .springframework .data .mongodb .core .convert .MongoCustomConversions ;
88+ import org .springframework .data .mongodb .core .convert .MongoCustomConversions .BigDecimalRepresentation ;
7289import org .springframework .data .mongodb .core .convert .MongoCustomConversions .MongoConverterConfigurationAdapter ;
7390import org .springframework .data .mongodb .core .convert .NoOpDbRefResolver ;
7491import org .springframework .data .mongodb .core .geo .GeoJsonPoint ;
@@ -144,6 +161,12 @@ public class MongoTemplateTests {
144161 it .defaultDb (DB_NAME );
145162 });
146163
164+ cfg .configureConversion (it -> {
165+ it .customConverters (adapter -> {
166+ adapter .bigDecimal (BigDecimalRepresentation .DECIMAL128 );
167+ });
168+ });
169+
147170 cfg .configureMappingContext (it -> {
148171 it .autocreateIndex (false );
149172 it .initialEntitySet (AuditablePerson .class );
@@ -170,7 +193,10 @@ public class MongoTemplateTests {
170193 });
171194
172195 cfg .configureConversion (it -> {
173- it .customConverters (DateToDateTimeConverter .INSTANCE , DateTimeToDateConverter .INSTANCE );
196+ it .customConverters (adapter -> {
197+ adapter .registerConverters (List .of (DateToDateTimeConverter .INSTANCE , DateTimeToDateConverter .INSTANCE ))
198+ .bigDecimal (BigDecimalRepresentation .DECIMAL128 );
199+ });
174200 });
175201
176202 cfg .configureMappingContext (it -> {
@@ -732,7 +758,7 @@ public void testDistinct() {
732758 .containsExactlyInAnyOrder (person1 .getName (), person2 .getName ());
733759 assertThat (template .findDistinct (new BasicQuery ("{'address.state' : 'PA'}" ), "name" ,
734760 template .getCollectionName (MyPerson .class ), MyPerson .class , String .class ))
735- .containsExactlyInAnyOrder (person1 .getName (), person2 .getName ());
761+ .containsExactlyInAnyOrder (person1 .getName (), person2 .getName ());
736762 }
737763
738764 @ Test // DATAMONGO-1761
@@ -876,7 +902,7 @@ public void testUsingAnInQueryWithLongId() throws Exception {
876902 }
877903
878904 @ Test // DATAMONGO-602, GH-4920
879- public void testUsingAnInQueryWithBigIntegerId () throws Exception {
905+ public void testUsingAnInQueryWithBigIntegerId () {
880906
881907 template .remove (new Query (), PersonWithIdPropertyOfTypeBigInteger .class );
882908
@@ -887,6 +913,34 @@ public void testUsingAnInQueryWithBigIntegerId() throws Exception {
887913 assertThatExceptionOfType (ConversionFailedException .class ).isThrownBy (() -> template .insert (p1 ));
888914 }
889915
916+ @ Test // GH-5037
917+ public void errorsIfNoBigNumberFormatDefined () {
918+
919+ template = new MongoTestTemplate (cfg -> {
920+
921+ cfg .configureDatabaseFactory (it -> {
922+
923+ it .client (client );
924+ it .defaultDb (DB_NAME );
925+ });
926+
927+ cfg .configureConversion (it -> {
928+ it .customConverters (adapter -> {
929+ // no numeric conversion
930+ });
931+ });
932+
933+ });
934+
935+ template .remove (new Query (), PersonWithIdPropertyOfTypeBigInteger .class );
936+
937+ PersonWithIdPropertyOfTypeBigInteger p1 = new PersonWithIdPropertyOfTypeBigInteger ();
938+ p1 .setFirstName ("Sven" );
939+ p1 .setAge (11 );
940+ p1 .setId (new BigInteger ("2666666666666666665" ));
941+ assertThatExceptionOfType (CodecConfigurationException .class ).isThrownBy (() -> template .insert (p1 ));
942+ }
943+
890944 @ Test
891945 public void testUsingAnInQueryWithPrimitiveIntId () throws Exception {
892946
@@ -2561,16 +2615,15 @@ public void shouldReadNestedProjection() {
25612615 walter .address = new Address ("spring" , "data" );
25622616 template .save (walter );
25632617
2564- PersonPWA result = template .query (MyPerson .class )
2565- .as (PersonPWA .class )
2566- .matching (where ("id" ).is (walter .id ))
2618+ PersonPWA result = template .query (MyPerson .class ).as (PersonPWA .class ).matching (where ("id" ).is (walter .id ))
25672619 .firstValue ();
25682620
25692621 assertThat (result .getAddress ().getCity ()).isEqualTo ("data" );
25702622 }
25712623
25722624 interface PersonPWA {
25732625 String getName ();
2626+
25742627 AdressProjection getAddress ();
25752628 }
25762629
@@ -2823,7 +2876,7 @@ public void testFindAllAndRemoveFullyReturnsAndRemovesDocuments() {
28232876
28242877 assertThat (template .getDb ().getCollection ("sample" ).countDocuments (
28252878 new org .bson .Document ("field" , new org .bson .Document ("$in" , Arrays .asList ("spring" , "mongodb" )))))
2826- .isEqualTo (0L );
2879+ .isEqualTo (0L );
28272880 assertThat (template .getDb ().getCollection ("sample" ).countDocuments (new org .bson .Document ("field" , "data" )))
28282881 .isEqualTo (1L );
28292882 }
@@ -3935,7 +3988,8 @@ void saveEntityWithDotInFieldName() {
39353988
39363989 template .save (source );
39373990
3938- org .bson .Document raw = template .execute (WithFieldNameContainingDots .class , collection -> collection .find (new org .bson .Document ("_id" , source .id )).first ());
3991+ org .bson .Document raw = template .execute (WithFieldNameContainingDots .class ,
3992+ collection -> collection .find (new org .bson .Document ("_id" , source .id )).first ());
39393993 assertThat (raw ).containsEntry ("field.name.with.dots" , "v1" );
39403994 }
39413995
@@ -3954,13 +4008,17 @@ void queryEntityWithDotInFieldNameUsingExpr() {
39544008 template .save (source );
39554009 template .save (source2 );
39564010
3957- WithFieldNameContainingDots loaded = template .query (WithFieldNameContainingDots .class ) // with property -> fieldname mapping
3958- .matching (expr (ComparisonOperators .valueOf (ObjectOperators .getValueOf ("value" )).equalToValue ("v1" ))).firstValue ();
4011+ WithFieldNameContainingDots loaded = template .query (WithFieldNameContainingDots .class ) // with property -> fieldname
4012+ // mapping
4013+ .matching (expr (ComparisonOperators .valueOf (ObjectOperators .getValueOf ("value" )).equalToValue ("v1" )))
4014+ .firstValue ();
39594015
39604016 assertThat (loaded ).isEqualTo (source );
39614017
39624018 loaded = template .query (WithFieldNameContainingDots .class ) // using raw fieldname
3963- .matching (expr (ComparisonOperators .valueOf (ObjectOperators .getValueOf ("field.name.with.dots" )).equalToValue ("v1" ))).firstValue ();
4019+ .matching (
4020+ expr (ComparisonOperators .valueOf (ObjectOperators .getValueOf ("field.name.with.dots" )).equalToValue ("v1" )))
4021+ .firstValue ();
39644022
39654023 assertThat (loaded ).isEqualTo (source );
39664024 }
@@ -3975,20 +4033,20 @@ void updateEntityWithDotInFieldNameUsingAggregations() {
39754033
39764034 template .save (source );
39774035
3978- template .update (WithFieldNameContainingDots .class )
3979- .matching (where ("id" ).is (source .id ))
3980- .apply (AggregationUpdate .newUpdate (ReplaceWithOperation .replaceWithValue (ObjectOperators .setValueTo ("value" , "changed" ))))
3981- .first ();
4036+ template .update (WithFieldNameContainingDots .class ).matching (where ("id" ).is (source .id )).apply (AggregationUpdate
4037+ .newUpdate (ReplaceWithOperation .replaceWithValue (ObjectOperators .setValueTo ("value" , "changed" )))).first ();
39824038
3983- org .bson .Document raw = template .execute (WithFieldNameContainingDots .class , collection -> collection .find (new org .bson .Document ("_id" , source .id )).first ());
4039+ org .bson .Document raw = template .execute (WithFieldNameContainingDots .class ,
4040+ collection -> collection .find (new org .bson .Document ("_id" , source .id )).first ());
39844041 assertThat (raw ).containsEntry ("field.name.with.dots" , "changed" );
39854042
3986- template .update (WithFieldNameContainingDots .class )
3987- .matching ( where ( "id" ). is ( source . id ))
3988- . apply ( AggregationUpdate . newUpdate ( ReplaceWithOperation .replaceWithValue (ObjectOperators .setValueTo ("field.name.with.dots" , "changed-again" ))))
4043+ template .update (WithFieldNameContainingDots .class ). matching ( where ( "id" ). is ( source . id ))
4044+ .apply ( AggregationUpdate . newUpdate (
4045+ ReplaceWithOperation .replaceWithValue (ObjectOperators .setValueTo ("field.name.with.dots" , "changed-again" ))))
39894046 .first ();
39904047
3991- raw = template .execute (WithFieldNameContainingDots .class , collection -> collection .find (new org .bson .Document ("_id" , source .id )).first ());
4048+ raw = template .execute (WithFieldNameContainingDots .class ,
4049+ collection -> collection .find (new org .bson .Document ("_id" , source .id )).first ());
39924050 assertThat (raw ).containsEntry ("field.name.with.dots" , "changed-again" );
39934051 }
39944052
@@ -4013,9 +4071,8 @@ void savesMapWithDotInKey() {
40134071 org .bson .Document raw = template .execute (WithFieldNameContainingDots .class ,
40144072 collection -> collection .find (new org .bson .Document ("_id" , source .id )).first ());
40154073
4016- assertThat (raw .get ("mapValue" , org .bson .Document .class ))
4017- .containsEntry ("k1" , "v1" )
4018- .containsEntry ("map.key.with.dot" , "v2" );
4074+ assertThat (raw .get ("mapValue" , org .bson .Document .class )).containsEntry ("k1" , "v1" ).containsEntry ("map.key.with.dot" ,
4075+ "v2" );
40194076 }
40204077
40214078 @ Test // GH-4464
@@ -4031,16 +4088,13 @@ void readsMapWithDotInKey() {
40314088 MongoTemplate template = new MongoTemplate (new SimpleMongoClientDatabaseFactory (client , DB_NAME ), converter );
40324089
40334090 Map <String , String > sourceMap = Map .of ("k1" , "v1" , "sourceMap.key.with.dot" , "v2" );
4034- template .execute (WithFieldNameContainingDots .class ,
4035- collection -> {
4036- collection .insertOne (new org .bson .Document ("_id" , "id-1" ).append ("mapValue" , sourceMap ));
4037- return null ;
4038- }
4039- );
4091+ template .execute (WithFieldNameContainingDots .class , collection -> {
4092+ collection .insertOne (new org .bson .Document ("_id" , "id-1" ).append ("mapValue" , sourceMap ));
4093+ return null ;
4094+ });
40404095
40414096 WithFieldNameContainingDots loaded = template .query (WithFieldNameContainingDots .class )
4042- .matching (where ("id" ).is ("id-1" ))
4043- .firstValue ();
4097+ .matching (where ("id" ).is ("id-1" )).firstValue ();
40444098
40454099 assertThat (loaded .mapValue ).isEqualTo (sourceMap );
40464100 }
@@ -5015,8 +5069,7 @@ static class WithFieldNameContainingDots {
50155069
50165070 String id ;
50175071
5018- @ Field (value = "field.name.with.dots" , nameType = Type .KEY )
5019- String value ;
5072+ @ Field (value = "field.name.with.dots" , nameType = Type .KEY ) String value ;
50205073
50215074 Map <String , String > mapValue ;
50225075
@@ -5034,7 +5087,8 @@ public boolean equals(Object o) {
50345087 return false ;
50355088 }
50365089 WithFieldNameContainingDots withFieldNameContainingDots = (WithFieldNameContainingDots ) o ;
5037- return Objects .equals (id , withFieldNameContainingDots .id ) && Objects .equals (value , withFieldNameContainingDots .value )
5090+ return Objects .equals (id , withFieldNameContainingDots .id )
5091+ && Objects .equals (value , withFieldNameContainingDots .value )
50385092 && Objects .equals (mapValue , withFieldNameContainingDots .mapValue );
50395093 }
50405094
0 commit comments