For you Kotlin lovers, I implemented this BigDecimal ContextualSerializer where the number of decimal places can be configured using an annotation. Although it is strange place to introduce rounding in the serializer, for my case this was not an issue. Check for yourselves if rounding can be an issue.
The Serializer class:
class CustomBigDecimalSerializer(private val decimalPlaces: Int = 2) : StdSerializer<BigDecimal>(BigDecimal::class.java),
ContextualSerializer {
override fun serialize(value: BigDecimal?, jsonGenerator: JsonGenerator?, serializerProvider: SerializerProvider?) {
if (value != null) {
jsonGenerator?.writeNumber(value.setScale(decimalPlaces, RoundingMode.HALF_UP))
} else {
jsonGenerator?.writeNull()
}
}
override fun createContextual(provider: SerializerProvider?, property: BeanProperty?): JsonSerializer<*> {
val decimalPlaces = property?.getAnnotation(DecimalPlaces::class.java)
return CustomBigDecimalSerializer(decimalPlaces?.numberOfDigits ?: 2)
}
}
The annotation that can be used to configure the number of decimal places:
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class DecimalPlaces(val numberOfDigits: Int)
And finally the usage of it in this 'unit test':
class CustomBigDecimalSerializerTest {
@Test
fun serializeBigDecimals(){
val objectMapper: ObjectMapper = ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT)
val container = BigDecimalContainer(BigDecimal(Math.PI))
// no assertions, just print the serialized container
println(objectMapper.writeValueAsString(container))
}
data class BigDecimalContainer(val rawValue: BigDecimal){
@JsonSerialize(using = CustomBigDecimalSerializer::class)
val defaultDecimalPlaces = rawValue
@JsonSerialize(using = CustomBigDecimalSerializer::class)
@DecimalPlaces(numberOfDigits = 1)
val oneDecimalPlaces = rawValue
@JsonSerialize(using = CustomBigDecimalSerializer::class)
@DecimalPlaces(numberOfDigits = 2)
val twoDecimalPlaces = rawValue
@JsonSerialize(using = CustomBigDecimalSerializer::class)
@DecimalPlaces(numberOfDigits = 3)
val threeDecimalPlaces = rawValue
@JsonSerialize(using = CustomBigDecimalSerializer::class)
@DecimalPlaces(numberOfDigits = 10)
val tenDecimalPlaces = rawValue
}
}
The output of the test is:
{
"rawValue" : 3.141592653589793115997963468544185161590576171875,
"defaultDecimalPlaces" : 3.14,
"oneDecimalPlaces" : 3.1,
"twoDecimalPlaces" : 3.14,
"threeDecimalPlaces" : 3.142,
"tenDecimalPlaces" : 3.1415926536
}
Have fun with it!