[
https://issues.apache.org/jira/browse/WW-5819?focusedWorklogId=1050241&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-1050241
]
ASF GitHub Bot logged work on WW-5819:
--------------------------------------
Author: ASF GitHub Bot
Created on: 26/Oct/26 12:14
Start Date: 26/Oct/26 12:14
Worklog Time Spent: 10m
Work Description: Copilot commented on code in PR #2062:
URL: https://github.com/apache/struts/pull/2062#discussion_r4377067163
##########
core/src/test/java/org/apache/struts2/test/LogCapture.java:
##########
@@ -54,6 +58,13 @@ public List<String> messages() {
return messages;
}
+ public List<String> messages(Level level) {
+ return IntStream.range(0, messages.size())
+ .filter(i -> levels.get(i) == level)
Review Comment:
`org.apache.logging.log4j.Level` is not an enum, so comparing with `==`
relies on reference identity and can silently fail. Use `.equals(...)` (or
compare `intLevel()` values) to ensure level filtering works reliably.
##########
core/src/test/java/org/apache/struts2/test/LogCapture.java:
##########
@@ -54,6 +58,13 @@ public List<String> messages() {
return messages;
}
+ public List<String> messages(Level level) {
+ return IntStream.range(0, messages.size())
+ .filter(i -> levels.get(i) == level)
+ .mapToObj(messages::get)
+ .toList();
Review Comment:
Using `Stream#toList()` requires JDK 16+. If this project/module still
targets JDK 8/11 for tests, this will not compile. Using
`collect(Collectors.toList())` avoids coupling the test utility to newer JDKs.
##########
core/src/test/java/org/apache/struts2/test/LogCapture.java:
##########
@@ -36,13 +38,15 @@ public class LogCapture implements AutoCloseable {
private final Logger logger;
private final AbstractAppender appender;
private final List<String> messages = new CopyOnWriteArrayList<>();
+ private final List<Level> levels = new CopyOnWriteArrayList<>();
public LogCapture(Class<?> source) {
logger = (Logger) LogManager.getLogger(source);
appender = new AbstractAppender("LogCapture-" + System.nanoTime(),
null, null, false, Property.EMPTY_ARRAY) {
@Override
public void append(LogEvent event) {
String message = event.getMessage().getFormattedMessage();
+ levels.add(event.getLevel());
messages.add(event.getThrown() == null ? message : message + "
" + event.getThrown());
Review Comment:
`messages` and `levels` are maintained as two separate
`CopyOnWriteArrayList`s, but updates to them aren’t atomic as a pair. If
`messages(Level)` is called while another thread is appending,
`IntStream.range(0, messages.size())` can observe a larger `messages.size()`
than `levels.size()` and throw `IndexOutOfBoundsException`. Consider storing a
single combined record per event (e.g., a small DTO with `Level` + message) or
iterating up to `min(messages.size(), levels.size())`.
##########
core/src/main/java/org/apache/struts2/factory/DefaultValidatorFactory.java:
##########
@@ -43,10 +55,37 @@ public void setReflectionProvider(ReflectionProvider
reflectionProvider) {
this.reflectionProvider = reflectionProvider;
}
+ @Inject(value = StrutsConstants.STRUTS_DEVMODE, required = false)
+ public void setDevMode(String devMode) {
+ this.devMode = BooleanUtils.toBoolean(devMode);
+ }
+
public Validator buildValidator(String className, Map<String, Object>
params, Map<String, Object> extraContext) throws Exception {
Validator validator = (Validator) objectFactory.buildBean(className,
extraContext);
- reflectionProvider.setProperties(params, validator, extraContext);
+ if (params != null) {
+ params.forEach((name, value) -> setParam(className, validator,
name, value, extraContext));
+ }
return validator;
}
+
+ private void setParam(String className, Validator validator, String name,
Object value, Map<String, Object> extraContext) {
+ try {
+ reflectionProvider.setProperty(name, value, validator,
extraContext, true);
+ } catch (ReflectionException e) {
+ if (hasWritableProperty(validator, name)) {
+ LOG.log(devMode ? Level.ERROR : Level.WARN, "Validator [{}]
ignores param [{}]: value [{}] cannot be converted ({})",
+ className, name, value,
ExceptionUtils.getRootCauseMessage(e));
Review Comment:
The log reports `className` passed into `buildValidator`, which may not
match the runtime validator class (e.g., if `ObjectFactory` returns a
subclass/proxy). Logging `validator.getClass().getName()` would make the
message more accurate and easier to correlate with the actual instance.
##########
core/src/test/java/org/apache/struts2/test/LogCapture.java:
##########
@@ -54,6 +58,13 @@ public List<String> messages() {
return messages;
}
+ public List<String> messages(Level level) {
+ return IntStream.range(0, messages.size())
Review Comment:
`messages` and `levels` are maintained as two separate
`CopyOnWriteArrayList`s, but updates to them aren’t atomic as a pair. If
`messages(Level)` is called while another thread is appending,
`IntStream.range(0, messages.size())` can observe a larger `messages.size()`
than `levels.size()` and throw `IndexOutOfBoundsException`. Consider storing a
single combined record per event (e.g., a small DTO with `Level` + message) or
iterating up to `min(messages.size(), levels.size())`.
Issue Time Tracking
-------------------
Worklog Id: (was: 1050241)
Time Spent: 20m (was: 10m)
> Log a validator param that fails type conversion instead of ignoring it
> silently
> --------------------------------------------------------------------------------
>
> Key: WW-5819
> URL: https://issues.apache.org/jira/browse/WW-5819
> Project: Struts 2
> Issue Type: Improvement
> Components: XML Validators
> Reporter: Lukasz Lenart
> Priority: Major
> Fix For: 7.5.0
>
> Time Spent: 20m
> Remaining Estimate: 0h
>
> h2. Problem
> {{DefaultValidatorFactory}} builds each validator through
> {{ObjectFactory.buildValidator}}, which sets the configured params with type
> conversion errors swallowed. A param that cannot be converted is left unset,
> and nothing is logged. For a range bound, that turns the check off without
> any trace:
> {code:xml}<field-validator type="localdate">
> <param name="min">01/02/2026</param> <!-- not an ISO date: min stays
> null -->
> </field-validator>
> {code}
> h2. Proposal
> Keep the current behaviour (the validator is still built and the param is
> still left unset), but log the swallowed conversion error. The message names
> the validator type, the param, the value and the cause:
> * WARN by default
> * ERROR in devMode
> h2. Scope
> A logging-only change with no behaviour change, so it is safe for 7.5.0.
> Failing the configuration instead is WW-5818 (8.0.0).
> h2. Tests
> * an unconvertible param on an XML-configured validator produces the log
> entry at the expected level, and the validator is still built
> * a valid param produces no entry
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)