Repository navigation
WW-5816 Add a range validator for java.time.LocalDate - #2060
Merged
Merged
Conversation
DateRangeFieldValidator compares against java.util.Date bounds, so on a LocalDate property it throws ClassCastException. LocalDateRangeFieldValidator is a RangeValidatorSupport<LocalDate>, registered as "localdate", with ISO min/max bounds (or minExpression/maxExpression), both inclusive. An XML min such as "2026-01-01" reaches the generic setMin(T) as a LocalDate through the usual parameter conversion, which a test pins. @LocalDateRangeFieldValidator mirrors @DateRangeFieldValidator without dateFormat, since the bounds are ISO only. It is processed on a method and inside @validations via the new localDateRangeFields() member. The builder parses the bounds with LocalDate.parse, so a malformed bound fails when the validators are built instead of passing through as a string. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
🟡 Changes recommended
XML bounds can be interpreted using the action's global date format rather than ISO, producing incorrect validation limits.
1 open issue
What changed in this PR
Adds localdate range validation to Struts core for java.time.LocalDate properties, reusing the existing range-validation infrastructure without changing the legacy date validator.
Changes:
- Registers a LocalDate validator supporting inclusive bounds and bound expressions.
- Adds method-level annotation support and integration with
@Validations. - Adds tests for range behavior, registration, configuration conversion, and annotation parsing.
| File | Description |
|---|---|
core/src/test/java/org/apache/struts2/validator/validators/LocalDateRangeFieldValidatorTest.java |
Tests range behavior, expressions, registration, and bound conversion. |
core/src/test/java/org/apache/struts2/validator/AnnotationValidationConfigurationBuilderTest.java |
Tests annotation processing and malformed-bound rejection. |
core/src/test/java/org/apache/struts2/validator/AnnotationMalformedLocalDateRangeAction.java |
Provides an invalid-bound annotation fixture. |
core/src/test/java/org/apache/struts2/validator/AnnotationLocalDateRangeAction.java |
Provides standalone and grouped annotation fixtures. |
core/src/main/resources/org/apache/struts2/validator/validators/default.xml |
Registers the localdate validator. |
core/src/main/java/org/apache/struts2/validator/validators/LocalDateRangeFieldValidator.java |
Implements and documents the LocalDate range validator. |
core/src/main/java/org/apache/struts2/validator/AnnotationValidationConfigurationBuilder.java |
Builds LocalDate validator configurations from annotations. |
core/src/main/java/org/apache/struts2/validator/annotations/Validations.java |
Adds the LocalDate annotation collection. |
core/src/main/java/org/apache/struts2/validator/annotations/LocalDateRangeFieldValidator.java |
Defines the new validation annotation. |
Review effort: Balanced
…ates XML min/max params reached setMin/setMax through DateConverter, which tries the application's struts.date.format before ISO: with yyyy-dd-MM, a min of 2026-01-02 became February 1. The annotation bounds were already ISO-only. LocalDateRangeFieldValidator-conversion.properties maps min and max to LocalDateRangeBoundConverter, which parses them with LocalDate.parse, so XML bounds no longer depend on the display format. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The converter's error branch is unreachable through buildValidator, which swallows conversion errors on validator params (WW-5818/WW-5819), so it was uncovered. Test the converter on its own: an ISO bound is parsed (trimmed), a non-ISO bound throws TypeConversionException naming the param with the DateTimeParseException as cause, and an already converted LocalDate passes through. Co-Authored-By: Claude Opus 5.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.



Fixes WW-5816
Problem
DateRangeFieldValidator(date) is aRangeValidatorSupport<Date>. On ajava.time.LocalDateproperty it compares the value againstjava.util.Datebounds and throwsClassCastException, so aLocalDatefield has no working range validation. Conversion and the date tags have supportedLocalDatefor a while; the validators had not.Change
LocalDateRangeFieldValidator extends RangeValidatorSupport<LocalDate>, registered aslocaldatein the default validators.min/maxas ISO dates, orminExpression/maxExpression.requiredvalidator), all inherited fromRangeValidatorSupport.<param name="min">2026-01-01</param>reaches the genericsetMin(T)as aLocalDatethrough the usual parameter conversion. That was the open question in the ticket, and a test pins it.@LocalDateRangeFieldValidatormirrors@DateRangeFieldValidatorwithoutdateFormat, sinceLocalDatebounds are ISO only. It is processed on a method and inside@Validationsvia the newlocalDateRangeFields()member, whose empty default keeps existing code compiling.LocalDate.parse, so a malformed bound fails when the validators are built instead of passing through as a string.DateRangeFieldValidator.LocalDateTime/LocalTimecan follow on demand.Tests
LocalDateRangeFieldValidatorTest:localdateregistrationLocalDatewhen the validator is built from configurationAnnotationValidationConfigurationBuilderTest:@Validationsannotations producelocaldatevalidators withLocalDateboundsDateTimeParseExceptionFollow-ups
localdate.min/maxondatecontrols.🤖 Generated with Claude Code