-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Description
Search before asking
- I searched in the issues and found nothing similar.
Describe the bug
When using JsonMapper.Builder to create multiple mappers, calling modules(a, b, c, d).build(); then modules(e, f, g, h).build(); will always register only the first set (a, b, c, d) in both mappers, even though the builder API appears mutable. The internal 'saveStateApplyModules' in MapperBuilder prevents subsequent changes from taking effect after the first build(). This is misleading and dangerous: the expectation is that the builder’s current configuration is used with each build(), but instead, changes to modules(...) after the initial build() are ignored.
This breaks dev expectations around Builder API predictability, can lead to silent and confusing bugs, and forces all users to create new Builder instances for every configuration — even if they want only a minor difference. Ideally, the API should either throw a ConfigurationException on reused builders, or else reliably reflect the latest modules provided to modules(...).
Version Information
Jackson 3.0.0 and 3.1.x (tested on 3.1.2)
Reproduction
Minimal Kotlin snippet:
val builder = JsonMapper.Builder().modules(a, b, c, d)
val m1 = builder.build()
val m2 = builder.modules(e, f, g, h).build()
println(m2.registeredModules())
// outputs a, b, c, d
// (should output a, b, c, d, e, f, g, h)
// (or should fail)Expected: m2 should register only e, f, g, h.
Actual: m2 registers the initial modules from first build().
Expected behavior
Expected:
- subsequent calls to modules(...) after build() should reflect the latest modules in each new build()
- Or: changing modules after build() should throw a ConfigurationException (fail fast) to avoid subtle bugs
Actual:
- Only the initial configuration 'sticks', later calls are silently ignored
- leads to wasted debugging time and accidental misconfiguration
Additional context
This is a major pitfall for anyone using the JsonMapper Builder to create slightly different configurations, e.g. when your company uses different PropertyNamingStrategies accross the org. The API appears mutable and chainable, so the current behavior violates least-surprise and causes buggy production deployments.