Hi Prasanth,

Thanks, that settles the stack question: it is not the stack. Your
secureStack is the unmodified defaultStack (only csp.disabled changed) plus
your own cspHeader interceptor, so it still runs

checkbox -> params -> conversionError -> validation -> workflow

and the scope interceptor in front of it does not touch validation errors.

I ran your binding through that chain again. With an ActionSupport-based
action the unchecked box ends up as

fieldErrors = {capDeferral[200]=[Invalid field value for field
"capDeferral[200]".]}

and workflow returns INPUT whenever hasErrors() is true. So if your form
goes
through, the error is being lost inside the action itself. In order of
likelihood, I would check:

1. validate(), or anything it calls, invoking clearErrors() or
clearFieldErrors(). That would match what you describe - the submission
succeeds exactly when validate() adds no errors of its own.
2. The action not being ValidationAware (e.g. not extending ActionSupport).
The conversionError interceptor then has nowhere to put the error and
drops it silently.
3. The action method being named input, back, cancel or browse (workflow
skips those), an overridden hasErrors(), or ValidationWorkflowAware /
@InputConfig / ValidationErrorAware changing the result name.

About 7.4.0
-----------

The fix (WW-5700 and WW-5701) is in the 7.4.0 test build announced on this
list on 17 September, so you can try it against your application now rather
than waiting for the final release - feedback on the test build is very
welcome.

What it will do for you: the ClassCastException goes away and you can drop
the instanceof guard. What it will not do: change whether you land on the
input page - that depends on the points above, and behaves the same before
and after.

Longer term, binding the checkbox to Boolean is still the cleanest option,
since uncheckedValue can only be set on the interceptor, not per tag.

Cheers
Łukasz

On Thu, Sep 03, 2026 04:42 PM, Prasanth Pasala <[email protected]>
wrote:

> Hi Lukasz,
>
> We are using a scope interceptor to set values between actions followed by
> custom stack.
>
> Custom Stack is as below.
> <interceptor-stack name="secureStack">
>      <interceptor-ref name="defaultStack">
>            <param name="csp.disabled">true</param>
>       </interceptor-ref>
> <interceptor-ref name="cspHeader"/>
>
>
> Thanks,
> Prasanth
>
> On 9/3/26 7:49 AM, Lukasz Lenart wrote:
> > Hi Prasanth,
> >
> > Short answer: no. 7.4.0 will not start sending you to the input page.
> >
> > The conversion error was already being registered before the fix. WW-5700
> > only
> > changed what the map accessor does with the *return value* of
> > XWorkConverter.convertValue(); it did not touch the error reporting
> inside
> > convertValue() itself. I ran the same binding against the pre-fix and
> > post-fix
> > code to be sure:
> >
> > before: map = {100=1, 200=ognl.NoConversionPossible}
> > conversionErrors = {capDeferral[200]=ConversionData}
> >
> > after: map = {100=1}
> > conversionErrors = {capDeferral[200]=ConversionData}
> >
> > Identical error, different map. So whatever your stack does with that
> error
> > today, it will do exactly the same in 7.4.0.
> >
> > One thing that does change for your code
> > ----------------------------------------
> >
> > The entry is now absent rather than holding the marker. That means
> >
> > getCapDeferral().get(compID)
> >
> > returns null where it used to return "ognl.NoConversionPossible". Your
> > temporary
> > guard is therefore not merely redundant after the upgrade - its else
> branch
> > stops
> > running, because the outer != null test is now false and the 0 is never
> put:
> >
> > if (get(compID) != null) {
> > if (get(compID) instanceof Integer) { ... }
> > else { put(compID, Integer.valueOf(0)); } // no longer reached
> > }
> >
> > Your validate() line itself is fine, since
> >
> > get(compID) != null && get(compID) == 1
> >
> > is already null-safe and simply evaluates to false. But if anything
> > downstream
> > relies on the key existing with a 0, key that off absence instead:
> >
> > Integer v = getCapDeferral().get(compID);
> > boolean selected = Integer.valueOf(1).equals(v);
> >
> > Why yours submits successfully at all
> > -------------------------------------
> >
> > This part is worth a look, independently of the fix. The default stack
> runs
> >
> > params -> conversionError -> validation -> workflow
> >
> > so validate() always runs even when a conversion error is pending -
> > workflow is
> > what returns INPUT, and it comes after validation. That ordering is why
> your
> > ClassCastException surfaced inside validate() rather than being
> > short-circuited
> > earlier.
> >
> > But with an unmodified defaultStack and a ValidationAware action, the
> > conversionError interceptor does turn that entry into a field error - I
> > checked,
> > it produces
> >
> > capDeferral[200] = [Invalid field value for field "capDeferral[200]".]
> >
> > and hasErrors() is then true, so workflow returns INPUT. If your form
> > submits
> > successfully instead, something in your setup is swallowing it: most
> likely
> > the
> > conversionError interceptor is not in your stack, or the action is not
> > ValidationAware, or workflow is excluded for that method. Worth
> confirming,
> > because that is your safety net for every conversion failure, not just
> this
> > one.
> >
> > Again, none of that changes in 7.4.0 - it behaves the same before and
> after.
> >
> > Cheers
> > Łukasz
> >
> > On Wed, Sep 02, 2026 03:42 PM, Prasanth<[email protected]>
> wrote:
> >
> >> Hi Lukasz,
> >>
> >> After adding the instanceof guard if validate method did not generate
> any
> >> field errors the form submission was successful. Would the new 7.4.0 go
> >> back to input page because the struts has added a
> >> conversion error?
> >>
> >> Thanks,
> >> Prasanth
> >>
> >> On 9/2/26 12:22 AM, Lukasz Lenart wrote:
> >>> Hi Prasanth,
> >>>
> >>> Just to close the loop: the fix is merged.
> >>>
> >>> WW-5700 — the map and list accessors no longer store the value when the
> >>> conversion fails, so the marker string never reaches your map. A
> >> follow-up,
> >>> WW-5701, fixes a related case where the marker was compared with
> equals()
> >>> instead of identity, which could drop a legitimate element whose text
> >>> happens
> >>> to match.
> >>>
> >>> Both are in 7.4.0 and 6.12.0, neither released yet. Once you upgrade
> you
> >> can
> >>> drop the instanceof Integer guard — an unconvertible value will simply
> >> leave
> >>> the entry is absent, and the conversion error is still recorded as
> >> before.
> >>> Thanks again for the report and for coming back with the tag; that is
> >> what
> >>> made it reproducible.
> >>>
> >>> Cheers
> >>> Łukasz
> >>>
> >>> On Thu, Aug 27, 2026 06:08 PM, Prasanth Pasala<
> [email protected]
> >>>
> >>> wrote:
> >>>
> >>>> Hi Lukasz,
> >>>>
> >>>> Thank you for looking into it and the detailed explanation.  During
> >>>> debugging I did see the NO CONVERSION POSSIBLE message in the map.
> >>>>
> >>>> As you suggested using Boolean is probably the best solution.
> Changing
> >>>> the default value of unchecked for the stack could cause problems
> >> somewhere
> >>>> else.
> >>>>
> >>>> The line of code where the error occurs is in the validate method.
> There
> >>>> are dependencies between fields so the validation code is checking if
> >> the
> >>>> check box is selected and if so has the user populated another text
> box
> >> or
> >>>> not.
> >>>>
> >>>> Below is the temporary solution I had put in to make the site work.
> >>>> --------------
> >>>> if(getEnrollmentForm().getCapDeferral().get(compID) != null ) {
> >>>>                   if(getEnrollmentForm().getCapDeferral().get(compID)
> >>>> instanceof Integer) {
> >>>>                       // got valid value
> >>>>                   }
> >>>>                   else {
> >>>>                       getEnrollmentForm().getCapDeferral().put(compID,
> >>>> Integer.valueOf(0));
> >>>>                   }
> >>>>               }
> >>>> --------------
> >>>> Thanks,
> >>>> Prasanth
> >>>>
> >>>> On 8/27/26 2:52 AM, Łukasz Lenart wrote:
> >>>>
> >>>> Thanks for the tag, that was the missing piece — I can reproduce it
> and
> >> it
> >>>> is
> >>>> a bug in Struts, not in your code.
> >>>>
> >>>> I have raised it as WW-5700:
> >>
> https://www.google.com/url?q=https://issues.apache.org/jira/browse/WW-5700&source=gmail&ust=1787903552853000&sa=E
> >>>> What happens
> >>>> ------------
> >>>>
> >>>> With submitUnchecked="true" the tag renders a companion hidden field,
> >> and
> >>>> when
> >>>> the box is not checked CheckboxInterceptor submits the parameter with
> >> its
> >>>> "uncheckedValue", which defaults to the string "false".
> >>>>
> >>>> So Struts is asked to bind "false" into a HashMap<Long, Integer>. That
> >>>> conversion fails, as it should. The problem is what happens next:
> >>>> XWorkConverter.convertValue() signals failure by returning the
> constant
> >>>> TypeConverter.NO_CONVERSION_POSSIBLE — and that constant is itself a
> >> plain
> >>>> String, "ognl.NoConversionPossible".
> >> XWorkMapPropertyAccessor.setProperty()
> >>>> puts that return value straight into your map without checking for it.
> >>>>
> >>>> Because generics are erased, the map is just a Map at that point, so
> >> the put
> >>>> succeeds silently. Nothing blows up until your own code reads the
> entry
> >> back
> >>>> and unboxes it, which is exactly why the stack trace points at your
> line
> >>>>
> >>>> ... getCapDeferral().get(compID) == 1 ...
> >>>>
> >>>> and not at anything in Struts. The same missing check exists for List
> >> and
> >>>> Collection properties, and for map keys as well as values.
> >>>>
> >>>> What you can do now
> >>>> -------------------
> >>>>
> >>>> The cleanest workaround is to bind the checkbox to a Boolean rather
> >> than an
> >>>> Integer. "false" is the unchecked default precisely because a checkbox
> >> is
> >>>> boolean by nature, so this converts cleanly:
> >>>>
> >>>> @Element(value = java.lang.Boolean.class)
> >>>> private HashMap<Long, Boolean> capDeferral = new HashMap<>();
> >>>>
> >>>> <s:checkbox name="capDeferral[%{#attr.compensation.enrollmentCompID}]"
> >>>> fieldValue="true" submitUnchecked="true"/>
> >>>>
> >>>> and then test Boolean.TRUE.equals(getCapDeferral().get(compID)).
> >>>>
> >>>> If you need to keep Integer, set the interceptor's uncheckedValue to
> >>>> something
> >>>> convertible instead:
> >>>>
> >>>> <interceptor-ref name="checkbox">
> >>>> <param name="uncheckedValue">0</param>
> >>>> </interceptor-ref>
> >>>>
> >>>> Be aware that is stack-wide, so it affects every checkbox in that
> >> stack, not
> >>>> just this one — any checkbox bound to a Boolean will then receive "0".
> >>>>
> >>>> One more thing worth checking on your side: the conversion failure
> *is*
> >>>> recorded as a conversion error, so with the default stack the
> >>>> conversionError
> >>>> and workflow interceptors should normally return INPUT before your
> >> action
> >>>> code
> >>>> runs. If your action is reaching that line anyway, it may not be
> >>>> ValidationAware, or it may be on a custom stack — that is worth a look
> >>>> independently of this bug, since it is your safety net for every other
> >>>> conversion failure too.
> >>>>
> >>>> Thanks for the report and for following up with the tag.
> >>>>
> >>>> Cheers
> >>>> Łukasz
> >>>>
> >>>> On Tue, Aug 18, 2026 12:12 AM, Prasanth Pasala<
> >> [email protected]> <[email protected]>
> >>>> wrote:
> >>>>
> >>>>
> >>>> <s:checkbox class="disableText"
> >> name="capDeferral[%{#attr.compensation.enrollmentCompID}]"
> >>>> fieldValue="1" submitUnchecked="true"/>
> >>>>
> >>>> Thanks,
> >>>> Prasanth
> >>>>
> >>>> On 8/14/26 11:24 PM, Lukasz Lenart wrote:
> >>>>
> >>>> pt., 14 sie 2026 o 22:36 Prasanth<[email protected]> <
> >> [email protected]>
> >>>> napisał(a):
> >>>>
> >>>> Getting the below exception after a form is submitted. The form has a
> >>>>
> >>>> check box, when this check box is not selected we get the exception.
> If
> >> the
> >>>> check box is selected it works normally. Is there
> >>>>
> >>>> anything I should be doing to force struts to put a Integer value in
> >>>>
> >>>> the hash map when the check box is not selected?
> >>>>
> >>>>      Exception: java.lang.ClassCastException: class java.lang.String
> >>>>
> >>>> cannot be cast to class java.lang.Integer (java.lang.String and
> >>>> java.lang.Integer are in module java.base of loader 'bootstrap')
> >>>>
> >>>> The code line where it happens is below
> >>>>
> >>>>                     else
> >> if(getEnrollmentForm().getCapDeferral().get(compID)
> >>>> != null && getEnrollmentForm().getCapDeferral().get(compID)==1) {
> >>>>
> >>>> Variable Declaration:
> >>>>         @Element(value=java.lang.Integer.class)
> >>>>         private HashMap<Long, Integer> capDeferral = new
> >>>>
> >>>> HashMap<Long,Integer>();
> >>>>
> >>>> Can you post the UI, how do you compose the form from tags?
> >>>>
> >>>>
> >>>> Cheers
> >>>> Łukasz
> >>>>
> >>>> ---------------------------------------------------------------------
> >>>> To unsubscribe,e-mail:[email protected]
> >>>> For additional commands,e-mail:[email protected]
> >>>>
> >>>>
> ---------------------------------------------------------------------
> >>>> To unsubscribe,e-mail:[email protected]
> >>>> For additional commands,e-mail:[email protected]
> >>>>
> >>>>
> >>>>
>

Reply via email to