From a977d260bd115d6b4fdcbd6d65968e93eadc4c54 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Fri, 5 Sep 2025 10:39:24 +0100 Subject: [PATCH] Add a property for Data MongoDB's BigDecimal representation Closes gh-47041 --- .../autoconfigure/DataMongoProperties.java | 24 +++++++++++++++++++ .../autoconfigure/MongoDataConfiguration.java | 18 ++++++++------ .../DataMongoPropertiesTests.java | 15 ++++++++++++ .../MongoDataAutoConfigurationTests.java | 20 ++++++++++++++++ 4 files changed, 70 insertions(+), 7 deletions(-) diff --git a/module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoProperties.java b/module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoProperties.java index a2de313f1d8..7f8f3491264 100644 --- a/module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoProperties.java +++ b/module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoProperties.java @@ -19,6 +19,7 @@ package org.springframework.boot.data.mongodb.autoconfigure; import org.jspecify.annotations.Nullable; import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.data.mongodb.core.convert.MongoCustomConversions.BigDecimalRepresentation; /** * Configuration properties for Spring Data MongoDB. @@ -41,6 +42,8 @@ public class DataMongoProperties { private final Gridfs gridfs = new Gridfs(); + private final Representation representation = new Representation(); + public @Nullable Boolean isAutoIndexCreation() { return this.autoIndexCreation; } @@ -61,6 +64,10 @@ public class DataMongoProperties { return this.gridfs; } + public Representation getRepresentation() { + return this.representation; + } + public static class Gridfs { /** @@ -91,4 +98,21 @@ public class DataMongoProperties { } + public static class Representation { + + /** + * Representation to use when converting a BigDecimal. + */ + private BigDecimalRepresentation bigDecimal = BigDecimalRepresentation.DECIMAL128; + + public BigDecimalRepresentation getBigDecimal() { + return this.bigDecimal; + } + + public void setBigDecimal(BigDecimalRepresentation bigDecimal) { + this.bigDecimal = bigDecimal; + } + + } + } diff --git a/module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/MongoDataConfiguration.java b/module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/MongoDataConfiguration.java index a9a43bcfd1f..1a1f3a6f256 100644 --- a/module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/MongoDataConfiguration.java +++ b/module/spring-boot-data-mongodb/src/main/java/org/springframework/boot/data/mongodb/autoconfigure/MongoDataConfiguration.java @@ -16,8 +16,6 @@ package org.springframework.boot.data.mongodb.autoconfigure; -import java.util.Collections; - import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; @@ -48,6 +46,12 @@ import org.springframework.data.mongodb.core.mapping.MongoMappingContext; @Configuration(proxyBeanMethods = false) class MongoDataConfiguration { + private final DataMongoProperties properties; + + MongoDataConfiguration(DataMongoProperties properties) { + this.properties = properties; + } + @Bean @ConditionalOnMissingBean static MongoManagedTypes mongoManagedTypes(ApplicationContext applicationContext) throws ClassNotFoundException { @@ -56,13 +60,12 @@ class MongoDataConfiguration { @Bean @ConditionalOnMissingBean - MongoMappingContext mongoMappingContext(DataMongoProperties properties, MongoCustomConversions conversions, - MongoManagedTypes managedTypes) { + MongoMappingContext mongoMappingContext(MongoCustomConversions conversions, MongoManagedTypes managedTypes) { PropertyMapper map = PropertyMapper.get().alwaysApplyingWhenNonNull(); MongoMappingContext context = new MongoMappingContext(); - map.from(properties.isAutoIndexCreation()).to(context::setAutoIndexCreation); + map.from(this.properties.isAutoIndexCreation()).to(context::setAutoIndexCreation); context.setManagedTypes(managedTypes); - Class strategyClass = properties.getFieldNamingStrategy(); + Class strategyClass = this.properties.getFieldNamingStrategy(); if (strategyClass != null) { context.setFieldNamingStrategy((FieldNamingStrategy) BeanUtils.instantiateClass(strategyClass)); } @@ -73,7 +76,8 @@ class MongoDataConfiguration { @Bean @ConditionalOnMissingBean MongoCustomConversions mongoCustomConversions() { - return new MongoCustomConversions(Collections.emptyList()); + return MongoCustomConversions + .create((configurer) -> configurer.bigDecimal(this.properties.getRepresentation().getBigDecimal())); } @Bean diff --git a/module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoPropertiesTests.java b/module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoPropertiesTests.java index 22ca3eb6082..e72ca1ea71f 100644 --- a/module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoPropertiesTests.java +++ b/module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/DataMongoPropertiesTests.java @@ -20,6 +20,9 @@ import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.data.mongodb.core.convert.MongoCustomConversions.BigDecimalRepresentation; +import org.springframework.data.mongodb.core.convert.MongoCustomConversions.MongoConverterConfigurationAdapter; +import org.springframework.test.util.ReflectionTestUtils; import static org.assertj.core.api.Assertions.assertThat; @@ -40,4 +43,16 @@ class DataMongoPropertiesTests { }); } + @Test + void defaultBigDecimalRepresentationIsAlignedWithSpringData() { + BigDecimalRepresentation springDataDefault = springDataDefaultBigDecimalRepresentation(); + BigDecimalRepresentation springBootDefault = new DataMongoProperties().getRepresentation().getBigDecimal(); + assertThat(springBootDefault).isEqualTo(springDataDefault); + } + + private BigDecimalRepresentation springDataDefaultBigDecimalRepresentation() { + return (BigDecimalRepresentation) ReflectionTestUtils.getField(new MongoConverterConfigurationAdapter(), + "bigDecimals"); + } + } diff --git a/module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/MongoDataAutoConfigurationTests.java b/module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/MongoDataAutoConfigurationTests.java index 7f00f0a8938..ed0a389bc1d 100644 --- a/module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/MongoDataAutoConfigurationTests.java +++ b/module/spring-boot-data-mongodb/src/test/java/org/springframework/boot/data/mongodb/autoconfigure/MongoDataAutoConfigurationTests.java @@ -118,6 +118,26 @@ class MongoDataAutoConfigurationTests { }); } + @Test + void customBigDecimalRepresentation() { + this.contextRunner.withPropertyValues("spring.data.mongodb.representation.big-decimal=string") + .run((context) -> assertThat(context.getBean(MongoCustomConversions.class)).extracting("converters") + .asInstanceOf(InstanceOfAssertFactories.LIST) + .map((converter) -> converter.getClass().getName()) + .anySatisfy((className) -> assertThat(className).contains("BigDecimalToStringConverter")) + .anySatisfy((className) -> assertThat(className).contains("BigIntegerToStringConverter"))); + } + + @Test + void defaultBigDecimalRepresentation() { + this.contextRunner + .run((context) -> assertThat(context.getBean(MongoCustomConversions.class)).extracting("converters") + .asInstanceOf(InstanceOfAssertFactories.LIST) + .map((converter) -> converter.getClass().getName()) + .noneSatisfy((className) -> assertThat(className).contains("BigDecimalToStringConverter")) + .noneSatisfy((className) -> assertThat(className).contains("BigIntegerToStringConverter"))); + } + @Test void usesAutoConfigurationPackageToPickUpDocumentTypes() { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();