fix: widen YAML-loaded numbers to the declared numeric field type - #3068
Merged
Conversation
YAML types a number by how it is written: 20 loads as Integer and 20.0 as Double, regardless of the declared field type. A double field written without a decimal point reached the setter as an Integer; inside a collection, generic erasure hid the mismatch until the first read threw ClassCastException far from the cause. Replace the ad-hoc Integer-to-Long promotion in deserialize() with a widen() helper covering Long, Double and Float targets. Widening only: a decimal written against an int or long field is a config mistake, so it is left alone to fail visibly rather than silently truncated (the long branch is gated on integral sources). The float switch arm in deserializeValue now accepts the boxed Float that widen() produces via Number.floatValue() instead of casting to Double, which would throw ClassCastException for every primitive float field. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XkVFZoe4hB2Req885z5ea7
|
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What this fixes
YAML types a number by how it is written:
20loads asIntegerand20.0asDouble, regardless of the declared field type. Adoubleconfig field written without a decimal point reached the setter as anInteger; inside a collection, generic erasure hid the mismatch until the first read threwClassCastException— a long way from the cause.Changes
deserialize()with awiden()helper coveringLong,DoubleandFloattargets (boxed and primitive).intorlongfield is a config mistake, so it is left alone to fail visibly in the deserialize log rather than being silently truncated. Thelongbranch is gated on integral sources for this reason. Double→float is the one accepted narrowing, since YAML always types decimals asDoubleand afloatfield must still load."float"switch arm indeserializeValuenow usesNumber.floatValue()instead of casting toDouble—widen()delivers a boxedFloatthere, and the old cast would have thrownClassCastExceptionfor every primitivefloatfield.Tests
New unit tests cover Integer→Double/Float/Long widening, the refusal to narrow Double→Integer and Double→Long, non-numeric targets being left untouched, and a
loadObjectround-trip on a primitivefloatfield written both with and without a decimal point (the case that exercises the switch arm).🤖 Generated with Claude Code
https://claude.ai/code/session_01XkVFZoe4hB2Req885z5ea7