Search code examples
kotlinfasterxml

InvalidFormatException when deserializing String to BigDecimal


Trying to deserialize a String to BigDecimal with a different format. The standard format, e.g. "1,000.20" works. However, in my csv the decimal delimiter and group separator are the other way round. So "1.000,20" would be the number one thousand with 20 as the two decimal places.

data class Record(
    @field:JsonProperty("Amount")
    val amount: BigDecimal,
)

The mapper is created with

val csvMapper = CsvMapper().apply {
    registerModule(KotlinModule.Builder().build())
    registerModule(JavaTimeModule())
    enable(CsvParser.Feature.TRIM_SPACES)
    enable(CsvParser.Feature.SKIP_EMPTY_LINES)
}

The file is read with

InputStreamReader(file.inputStream).use { reader ->
    csvMapper.readerFor(Record::class.java)
        .with(CsvSchema.emptySchema().withHeader().withColumnSeparator(';'))
        .readValues<Record>(reader)
        .readAll()
        .toList();

Exception:

com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.math.BigDecimal` from String "-1,23": not a valid representation
 at [Source: (InputStreamReader); line: 2, column: 53] (through reference chain: org.abc.Record["Amount"])

How can the format be specified?


Solution

  • Just found a question on stackoverflow including the solution to my question. The following works for me

    class BigDecimalCustomDeserializer : JsonDeserializer<BigDecimal>() {
    
        val dec = DecimalFormat("###,###,##0.0#", DecimalFormatSymbols(Locale.MYLOCALE))
    
        override fun deserialize(parser: JsonParser, context: DeserializationContext?): BigDecimal? {
            return if (parser.text != null && parser.text.isNotEmpty())
                dec.parse(parser.text).toString().toBigDecimal()
            else null
        }
    
    }
    

    with

    @field:JsonDeserialize(using = BigDecimalCustomDeserializer::class)
    val amount: BigDecimal,