Skip to content

apply the configured number-length limit on the parse path - #95

Merged
pjfanning merged 1 commit into
apache:trunkfrom
pjfanning:max-number-chars-parse-path
Aug 25, 2026
Merged

apply the configured number-length limit on the parse path#95
pjfanning merged 1 commit into
apache:trunkfrom
pjfanning:max-number-chars-parse-path

Conversation

@pjfanning

Copy link
Copy Markdown
Member

Follow-on to #94. XmlOptions.setMaxNumberOfCharsForNumbers is currently honoured in only one place.

The gap

The configured value reaches MathUtil from exactly one production caller — Validator — so it applies only when someone calls XmlObject.validate(options) explicitly. The path that runs on every parse() is lazy value materialization, XmlObjectBase.check_datedupdate_from_wscanon_textset_text in the value holders, and that always used DEFAULT_MAX_NUMBER_CHARS, because no XmlOptions is reachable from a value holder. Raising or lowering the option had no effect there. Several MathUtil and XsTypeConverter methods also had no maxNumberOfChars overload at all, so there was nothing to pass the value to even where it was in scope.

Approach

Carry the limit on the Locale, exactly as _loadStrictFloatingPoint and _loadAllowDecimalExponent are already carried: a default method on XmlLocale, a field copied from the options in the Locale constructor, and a get_max_number_chars() helper on XmlObjectBase so the holders have one place to read it. Two lines of this idiom were already present at JavaDecimalHolder:46 and JavaFloatHolder:55.

Add the missing overloads so there is something to pass the value to — MathUtil.parseAsBigInteger, parseAsLong, toBigInteger, and XsTypeConverter.lexDecimal, lexInteger, lexLong. lexInt/lexShort/lexByte need none: they use the hand-rolled parseIntXsdNumber/parseShort/parseByte, are bounded by the target type, and never call MathUtil.

Wire it through the decimal, integer and long holders, and through XmlObjectBase.getBigIntegerValue().

Validator needs no change — all integer-derived types route through its BTC_DECIMAL case (note the derivedFromInteger(type) check), which is already wired.

Compatibility

Every new overload is additive, and every existing signature keeps defaulting to DEFAULT_MAX_NUMBER_CHARS. Nothing changes for callers who do not set the option. Callers who do set it get the behaviour the setter has always advertised — worth noting as a behaviour change for anyone who set it and, without knowing it, got no effect on the parse path.

New @since tags are 5.4.1, since 5.4.0 is released.

Not in scope

  • GDate / GDuration fractional seconds — the constructors are public API with no options in scope, so wiring them means new public API on two widely-used classes. Still bounded by the 1024 default.
  • XMLStreamReaderExtImpl (rich parser) is built from a bare XMLStreamReader with no options; it can pick up the new overloads later.
  • Tooling, CLI and schema-compiler sites (PrettyPrinter, Inst2Xsd, SampleXmlUtil, StscTranslator, SchemaTypeLoaderBase, SOAPArrayType, XmlCalendar, XPathFactory, QNameCache) — trusted or hardcoded input.

Verification

MaxNumberOfCharsTest parses a 2000-character number and materializes it. With the main-source changes reverted, its 4 configured-limit tests fail and its 3 default-behaviour tests pass — which is exactly the intended split: the option starts working, and unset behaviour is untouched.

Ran misc.checkin.*, impl.util.* and the values tests locally — 112 pass. Leaving the full suite to CI.

🤖 Generated with Claude Code

XmlOptions.setMaxNumberOfCharsForNumbers only reached MathUtil from
Validator, ie only when XmlObject.validate(options) was called explicitly.
The path that runs on every parse - lazy value materialization through
XmlObjectBase.check_dated -> update_from_wscanon_text -> set_text - always
used DEFAULT_MAX_NUMBER_CHARS, because no XmlOptions is reachable from a
value holder. Raising or lowering the option had no effect there.

Carry the limit on the Locale, the way _loadStrictFloatingPoint and
_loadAllowDecimalExponent are already carried: a default method on
XmlLocale, a field copied from the options in the Locale constructor, and
a get_max_number_chars() helper on XmlObjectBase for the holders to use.

Add the maxNumberOfChars overloads that were missing, so there is
something to pass the value to: MathUtil.parseAsBigInteger, parseAsLong
and toBigInteger, and XsTypeConverter.lexDecimal, lexInteger and lexLong.
lexInt/lexShort/lexByte need none - they use the hand-rolled
parseIntXsdNumber and are bounded by the target type.

Wire it through the decimal, integer and long holders. Every new overload
is additive and the existing signatures keep defaulting to
DEFAULT_MAX_NUMBER_CHARS, so behaviour is unchanged unless the option is
set. Validator needs no change: integer-derived types route through its
BTC_DECIMAL case, which is already wired.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@pjfanning
pjfanning merged commit 3f93cbd into apache:trunk Aug 25, 2026
3 checks passed
@pjfanning
pjfanning deleted the max-number-chars-parse-path branch August 25, 2026 13:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant