fix(content): keep explicitly cleared fields from taking the Content Type default (#35416) - #37446
Open
danielsilva-dotcms wants to merge 3 commits into
Open
fix(content): keep explicitly cleared fields from taking the Content Type default (#35416)#37446danielsilva-dotcms wants to merge 3 commits into
danielsilva-dotcms wants to merge 3 commits into
Conversation
…Type default (#35416) ContentletHashMap#put removes a key outright when its value is null -- it extends ConcurrentHashMap, which forbids null values -- so a field the user deliberately cleared became indistinguishable from one that was never submitted. On new content only, checkin's setDefaultValues then reapplied the Content Type's default value, silently re-checking "Show on Menu" for pages whose type defaults it to true. Honour the contentlet's existing nullProperties set, the way validateContentlet already does, so an explicit clear survives checkin. Refs: #35416 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gortiz-dotcms
previously approved these changes
Sep 8, 2026
The previous commit honoured nullProperties for every field type, which broke an intentional contract: for text and numeric fields a null means "not provided" and the Content Type default should still be applied. ContentletJsonAPITest's Initialize_Fields_With_Default_Value_Test asserts exactly that, and it failed in CI along with StoryBlockMapTest and ShortyServletAndTitleImageTest, both of which depend on defaults backfilling nulled fields. Restrict the guard to Checkbox and MultiSelect fields, where the value is a set of selected options and the empty set is itself a valid choice. Everything else keeps its previous behaviour. Refs: #35416 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gortiz-dotcms
approved these changes
Sep 8, 2026
danielsolis-dotcms
approved these changes
Sep 8, 2026
danielsolis-dotcms
approved these changes
Sep 8, 2026
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.
Fixes #35416
Problem
Creating a new page, unchecking Show on Menu, and publishing did not stick — the page came back with the box checked. Unchecking on an existing page worked fine, which is the clue: the defect is create-only.
Root cause
Contentlet.mapis aContentletHashMap extends ConcurrentHashMap, and itsputoverride removes the key outright when the value is null — it has to, sinceConcurrentHashMapforbids null values:Clearing a checkbox posts an empty string, which
setContentletPropertyroutes toclearOrNullifyProperty→setProperty(var, null)→ key gone. From that point a field the user deliberately cleared is indistinguishable from one that was never submitted.checkinthen callssetDefaultValues, which is gated onisNewContent(hence create-only), sees the key missing, and reapplies the Content Type'sdefaultValue. The stockhtmlpageassettype defaultsshowOnMenuto"true", so the box the user just unchecked is silently re-checked.The contentlet already records the distinction in its
nullPropertiesset.validateContentletin this same class honours it;setDefaultValuesdid not.Fix
Consult
nullPropertiesbefore substituting a default — but only for fields where an empty value is a genuine user choice:For a Checkbox or MultiSelect the value is a set of selected options, and the empty set is itself a valid choice. For text, numeric and every other field type, a null still means "not provided" and the default is applied exactly as before.
That narrowing matters: an earlier revision of this PR honoured
nullPropertiesfor all field types and broke an intentional contract —ContentletJsonAPITest#Initialize_Fields_With_Default_Value_Testdeliberately nulls text/numeric fields and asserts the defaults come back. CI caught it (see history below). The Javadoc on the helper names that test so the constraint isn't lost.Verification
Reproduced and confirmed against a running instance (legacy content editor,
CONTENT_EDITOR2_ENABLED: false,showOnMenudefault"true"), reading the persisted value straight from the database:showOnMenu = "true"(bug)showOnMenuabsent /falseThe red/green pair matters here: the test asserts an absence, so it was worth proving it actually fails without the fix rather than passing for incidental reasons.
The three classes that failed on the over-broad revision all pass locally against this one:
ContentletJsonAPITestStoryBlockMapTestShortyServletAndTitleImageTestContentletCheckInTest(new test)Test
ContentletCheckInTest#checkin_new_content_with_cleared_checkbox_does_not_apply_default_value— already registered viaMainSuite2a, so it runs in CI.Reviewer note
The behavior change is now confined to Checkbox and MultiSelect fields on new content: an option set the user deliberately emptied is no longer refilled from the field's default. Every other field type is untouched.
CONTENT_API_SET_DEFAULT_VALUES=falseremains the escape hatch.Out of scope
edit_field.jsp:1318doesdefaultValue.split("|")—splittakes a regex and|is the alternation operator, so"true".split("|")yields["t","r","u","e"]and the default-checked branch never matches. A real bug, unrelated to this one, deliberately left for its own issue.🤖 Generated with Claude Code