1
0

Part 4: SimpleModule on the builder, and the BigDecimal scale trap

This commit is contained in:
2026-08-04 17:31:45 +00:00
parent 3ac9163232
commit 1f6f6fd855

View File

@@ -0,0 +1,57 @@
package com.ankurm.jackson3.part4custom;
import tools.jackson.databind.DeserializationFeature;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.databind.module.SimpleModule;
import java.math.BigDecimal;
/**
* Post: Custom Serialisers and Mix-ins — https://ankurm.com/jackson-custom-serializer-mixin/
* Section: "Registering the Serialiser and Deserialiser via SimpleModule"
*
* Jackson 3 differences:
* 1. SimpleModule moved to tools.jackson.databind.module.
* 2. The Version-taking constructor from the post is gone; pass just a name.
* 3. The module is attached with builder.addModule(...), not mapper.registerModule(...),
* because a built mapper is immutable.
*/
public class E03SimpleModuleRegistration {
public static void main(String[] args) {
SimpleModule moneyModule = new SimpleModule("MoneyModule");
moneyModule.addSerializer(Money.class, new E01MoneyValueSerializer());
moneyModule.addDeserializer(Money.class, new E02MoneyValueDeserializer());
JsonMapper mapper = JsonMapper.builder()
.addModule(moneyModule)
.build();
// Serialise: note the rounding and the upper-casing done by the serialiser.
Money price = new Money(new BigDecimal("19.999"), "usd");
System.out.println("serialised : " + mapper.writeValueAsString(price));
// Deserialise. NOTE: the scale is NOT preserved by default — Jackson parses
// 20.00 as a double first, so you get 20.0 and not 20.00. The blog post claims
// 20.00; that only holds if you turn on USE_BIG_DECIMAL_FOR_FLOATS, below.
Money restored = mapper.readValue("{\"amount\":20.00,\"currency\":\"USD\"}", Money.class);
System.out.println("amount : " + restored.amount() + " (scale lost)");
JsonMapper exact = JsonMapper.builder()
.addModule(moneyModule)
.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS)
.build();
System.out.println("amount exact : "
+ exact.readValue("{\"amount\":20.00,\"currency\":\"USD\"}", Money.class).amount()
+ " (scale preserved)");
// The path()-based deserialiser tolerates a missing field; the post's get()
// version would throw NullPointerException here.
Money partial = mapper.readValue("{\"currency\":\"EUR\"}", Money.class);
System.out.println("missing field: " + partial);
// Without the module the record would serialise structurally instead.
JsonMapper plain = JsonMapper.builder().build();
System.out.println("no module : " + plain.writeValueAsString(price));
}
}