Skip to content

fix(controller): render null XML values and coerce null date-select values (#4638) - #4650

Merged
bpamiri merged 4 commits into
developfrom
fix/4638-xml-null-rendering
Oct 28, 2026
Merged

bpamiri merged 4 commits into
developfrom
fix/4638-xml-null-rendering

Conversation

@bpamiri

@bpamiri bpamiri commented Oct 28, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Fixes #4638 — the follow-ups r2's review of #4633 called out. #4633 made renderWith()'s JSON branch null-safe and guarded the date/time helpers, but XML rendering of a null value still threw, and a null could still reach the date-select renderers. This PR closes both gaps.

Changes (r2's patches 3 + 5)

  • vendor/wheels/vendor/toXml/toXML.cfc — $arrayToXML, $queryToXML, $structToXML and $objectToXML guard every value with isNull(...) (the only portable read form when the engine has null support off) and emit <name type="null"/> instead of recursing into toXML() with null. $objectToXML checks null before IsCustomFunction().
  • vendor/wheels/global/util.cfm — $toXml() returns a well-formed <?xml version="1.0" encoding="UTF-8"?><data type="null"/> document for a null top-level value instead of passing it to the required data argument (an xml-typed function cannot return an empty string).
  • vendor/wheels/view/formsdate.cfc — after $dateOrTimeSelectNormalizeValue(), a null value is coerced to "" before $dateOrTimeSelectRender(), so no null reaches the select renderers or child helpers.
  • Changelog — changelog.d/4638-xml-null-rendering.fixed.md (JSON-only claim from fix(controller): handle null values in renderWith() and date form helpers #4633 is now backed by the XML/formsdate fixes).

Regression specs

  • controller/renderingSpec.cfc — "renders null struct values as json without throwing" (r2 patch 4; already passed on this head thanks to fix(controller): handle null values in renderWith() and date form helpers #4633 — kept as the JSON regression) and "renders null struct values as xml without throwing", which asserts toBeXML() and <data type="null"/>. The XML spec errors on the parent commit and passes here; with the production diff stashed the suite is 93 passed / 1 error.
  • view/formsdateobjectSpec.cfc — "renders the select when the bound date property is null": injects a user model whose birthday is javaCast("null", "") into the controller's variables scope under a distinct object name and asserts the select renders. The null is placed in a struct/model property, not passed to a required argument (that is not portable: required args reject null and optional args take the default on Lucee-null-off/RustCFML).

Engine notes

  • Lucee 7 with null support off and RustCFML: a null-valued key reads as absent/isNull() true, so the JSON spec is vacuous on RustCFML and the formsdate test exercises the empty-value path; the XML failure is real on both engines. On Adobe/BoxLang (and Lucee with null support on) the same specs exercise the true null path; the adobe2023/boxlang CI legs cover them.
  • Lucee 7 with null support enabled is not configured in this repo/CI (no nullSupport setting), so the exact reporter configuration is inferred from IsSimpleValue(null)=false and the unguarded toXML reads, as r2 documented.

Verification

Fixes #4638

Final head (1483eb9): adds tests/specs/global/toXmlRootNullSpec.cfc covering the root-null path plus the source pin, and strengthens the formsdate assertion. The live root-null test now probes null-argument support separately so it fails on null-capable engines if the guard regresses (see next commit).

Follow-up to #4633 (#4638). renderWith()'s JSON branch is null-safe, but the XML
branch still passed null struct/array/query/component values into toXML, whose
required data argument rejects null and whose branches read it directly. Guard
each recursion with isNull() and emit a type="null" element; a null top-level
value renders as empty output in $toXml(). The date-select helpers also coerce
a null bound value to "" before rendering, so no null reaches the select
renderers.

Regression specs cover renderWith() JSON and XML with null struct values (JSON
already passed on this head; XML failed before this change) and dateSelect()
with a null bound property. Add a changelog fragment.

Signed-off-by: Peter Amiri <peter@alurium.com>
BoxLang indents the generated XML differently, so match type="null" with a
format-agnostic FindNoCase instead of a contiguous element string.

Signed-off-by: Peter Amiri <peter@alurium.com>
$toXml() is declared xml, so returning "" for a null root value throws
"Cannot cast String [] to a value of type [xml]" on null-capable engines. Return
a well-formed null document instead (mirroring the nested toXML element) and
keep the changelog wording accurate.

Cover it with a root-null spec that skips where a null cannot be passed to a
required argument (Lucee null support off, RustCFML), plus a source guard that
always checks the declared document shape. Strengthen the formsdate spec so a
null bound property must render exactly like an empty value and produce the
full 12-option month select.

Signed-off-by: Peter Amiri <peter@alurium.com>
The root-null spec wrapped $toXml in try/catch and skipped on any exception,
so a regression on a null-capable engine (the xml-cast error) would be skipped
rather than fail. Probe null-argument support with an unrelated helper, skip
only when the engine cannot pass null, then call $toXml outside any try/catch
and assert toBeXML() + the null element. Keep the static source guard as the
cross-engine pin.

Signed-off-by: Peter Amiri <peter@alurium.com>
@bpamiri
bpamiri merged commit 8013e50 into develop Oct 28, 2026
24 checks passed
@bpamiri
bpamiri deleted the fix/4638-xml-null-rendering branch October 28, 2026 17:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(controller): XML rendering and regression coverage follow-ups from #4633

1 participant