fix(forms): an optional field with a format constraint must accept empty - #6690
Open
delchev wants to merge 1 commit into
Open
fix(forms): an optional field with a format constraint must accept empty#6690delchev wants to merge 1 commit into
delchev wants to merge 1 commit into
Conversation
A blank optional field could not be saved. Creating a Customer with only the required Name failed with "Could not save - Fields that need attention: Email" / "Enter a valid email address.", even though Email is not required. The only way through was to invent an address, which then pollutes the data - the dunning and notify paths mail whatever is stored there. Both layers applied the format rule to the empty value: - the shared client validator ran every rule regardless of presence, so the `email` rule on an OPTIONAL field rejected '' (a field gets EITHER the `required` rule OR the format rule, never both, so no required field loses its check); - the generated controller guarded the pattern on `!= null` only, so a direct REST caller sending "" got a 400 (the Harmonia form already posts '' as null, so this path is REST-only). A format constraint describes what a value must look like WHEN THERE IS ONE. Presence is `required`'s decision alone; applying a format rule to an empty value makes every optional field carrying one required by the back door. Client: skip any non-`required` rule when the value is blank - this covers email/pattern/minLength/min/max alike. The file is the SHARED runtime (application-core), so every generated app picks it up without a regen. Server: emit the blank skip only for OPTIONAL properties. A required property keeps the strict check, where blank is not a legal value - so nothing that is rejected today starts passing. Verified: the client validator against 11 cases (blank/null/whitespace accepted on an optional email, "abc" still refused, required still fails on '' and null, optional minLength/min skip empty but still fail a present bad value); the controller template rendered through Velocity with an optional-and-a required-patterned property, confirming the emitted Java gains `&& !isBlank()` on the optional one only and is unchanged for the required one. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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
A blank optional field cannot be saved.
Creating a Customer with only the required
Namefails with "Could not save — Fields that need attention: Email" / "Enter a valid email address.", even thoughEmailis not required. The only way through is to invent an address — which then pollutes the data, since the dunning and notify paths mail whatever is stored there.Cause
Both layers applied the format rule to the empty value:
application-coreformValidation.js) ran every rule regardless of presence, so theemailrule on an optional field rejected''.EntityController.java.template) guarded the pattern on!= nullonly, so a direct REST caller sending""got a 400. The Harmonia form already posts''asnull, so this path is REST-only.A format constraint describes what a value must look like when there is one. Presence is
required's decision alone; applying a format rule to an empty value makes every optional field carrying one required by the back door.Fix
Client — skip any non-
requiredrule when the value is blank. This coversemail/pattern/minLength/min/maxalike. No required field loses its check: the generator emits either therequiredrule or the format rule for a given field, never both.This file is the shared runtime, so every generated app picks the fix up without a regen.
Server — emit the blank skip only for optional properties:
A required property keeps the strict check, where blank is not a legal value — so nothing that is rejected today starts passing. Modules pick this up on their next regen.
Verification
"abc"still refused;requiredstill fails on''andnull; optionalminLength/minskip empty but still fail a present bad value.&& !isBlank()on the optional one only, and is byte-identical for the required one.🤖 Generated with Claude Code