Java
Why 5.0 Wasn't an Integer in Apicurio's Prompt Templates
By Lokesh Ram Chand · · 2 min read
- Java
- Apicurio Registry
- Jackson
- Open Source
- Debugging
This is my second PR to Apicurio Registry, after the XSD compatibility fix. It's PR #10017, closing #10016, and it's been merged.
The bug
Apicurio has prompt templates where each variable declares a type and can have a default. Imagine a template author writes:
type: integer
default: 5.0
That's a reasonable thing to write. But it failed with:
Type mismatch: expected integer but got number
The caller never even touched that variable. The template's own default was rejecting itself.
Why
Two things combined:
- Jackson always deserializes a YAML or JSON decimal literal as a
Double.5.0becomes aDouble, even though it's a whole number. validateType()only acceptedIntegerorLongfortype: integer.
On top of that, validateAppliedDefaults() (added in #9309) runs the type check against every default that gets filled in. So the strictness that was meant to catch bad defaults also caught a good one.
I wanted to see exactly what Jackson produced, so I wrote a small standalone repro against the project's own Jackson/YAML versions:
default: 5 -> Integer = 5
default: 5.0 -> Double = 5.0 (previously failed integer type check)
default: 1000000000000 -> Long = 1000000000000
The fix
In applyDefaults(), when a variable's declared type is integer and its default is a whole-number Double or Float, I convert it to Long. A genuinely fractional default like 5.5 is left as-is and still gets rejected, which is correct. number-typed defaults aren't touched.
SonarCloud flagged the repeated "integer" and "string" literals in PromptRenderingService, so I moved them into named constants in the same PR.
Getting the tests to run locally
The app module depends on the reactor's java-sdk module, which needs the Kiota code generator, which needs a working .NET runtime with libicu. My environment didn't have it, so at first I couldn't run the tests locally. I installed libicu-dev, and then:
./mvnw test -pl app -Dtest=PromptRenderingServiceTest -Dlocal
All 60 passed, including the 3 new regression tests. checkstyle:check had zero violations, and every commit has a DCO sign-off. Before opening the PR, I also checked the project's "Tried & Rejected" discussion list and made sure no other open PR covered this issue.
What I took from it
"Integer" means different things at different layers. To a person writing YAML, 5.0 is five. To Jackson, it's a Double. To the validator, it's the wrong class. The fix belongs at the point where values cross from parsing into validation, and it should only change the cases that are clearly whole numbers.