Skip to content

fix(content): keep explicitly cleared fields from taking the Content Type default (#35416) - #37446

Open
danielsilva-dotcms wants to merge 3 commits into
mainfrom
issue-35416-show-on-menu-unchecked
Open

fix(content): keep explicitly cleared fields from taking the Content Type default (#35416)#37446
danielsilva-dotcms wants to merge 3 commits into
mainfrom
issue-35416-show-on-menu-unchecked

Conversation

@danielsilva-dotcms

@danielsilva-dotcms danielsilva-dotcms commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

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.map is a ContentletHashMap extends ConcurrentHashMap, and its put override removes the key outright when the value is null — it has to, since ConcurrentHashMap forbids null values:

if (newValue == null) {
    return super.remove(key);
}

Clearing a checkbox posts an empty string, which setContentletProperty routes to clearOrNullifyPropertysetProperty(var, null) → key gone. From that point a field the user deliberately cleared is indistinguishable from one that was never submitted.

checkin then calls setDefaultValues, which is gated on isNewContent (hence create-only), sees the key missing, and reapplies the Content Type's defaultValue. The stock htmlpageasset type defaults showOnMenu to "true", so the box the user just unchecked is silently re-checked.

The contentlet already records the distinction in its nullProperties set. validateContentlet in this same class honours it; setDefaultValues did not.

Fix

Consult nullProperties before substituting a default — but only for fields where an empty value is a genuine user choice:

private boolean isClearedSelectionField(final Field field, final Set<String> nullProperties) {
    return (field instanceof CheckboxField || field instanceof MultiSelectField)
            && nullProperties.contains(field.variable());
}

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 nullProperties for all field types and broke an intentional contract — ContentletJsonAPITest#Initialize_Fields_With_Default_Value_Test deliberately 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, showOnMenu default "true"), reading the persisted value straight from the database:

Check Result
New page, unchecked, before fix showOnMenu = "true" (bug)
New page, unchecked, after fix showOnMenu absent / false
New regression test, with fix passes
Same test, with the guard removed fails on its assertion

The 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:

Class Broad revision This revision
ContentletJsonAPITest 1 error 9/9 pass
StoryBlockMapTest 11 errors 12/12 pass
ShortyServletAndTitleImageTest 1 failure 11/11 pass
ContentletCheckInTest (new test) pass 1/1 pass

Test

ContentletCheckInTest#checkin_new_content_with_cleared_checkbox_does_not_apply_default_value — already registered via MainSuite2a, so it runs in CI.

./mvnw verify -pl :dotcms-integration -Dcoreit.test.skip=false \
  -Dit.test='ContentletCheckInTest#checkin_new_content_with_cleared_checkbox_does_not_apply_default_value'

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=false remains the escape hatch.

Out of scope

edit_field.jsp:1318 does defaultValue.split("|")split takes 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

…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
gortiz-dotcms previously approved these changes Sep 8, 2026
danielsilva-dotcms and others added 2 commits September 8, 2026 13:39
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area : Backend PR changes Java/Maven backend code

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

"Show on Menu" checkbox not persisted when unchecked during new page creation

3 participants