Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Struts 2.3 form with multiple submit tags with action attribute

This is something quite simple which worked perfectly with Struts 2.1.x. But we recently upgraded to 2.3.15.2 and it broke. Basically we have a form (actually, many forms) with multiple submits:

<s:form>
 <s:submit action="save"  />
 <s:submit action="resetPassword"  />
</s:form>

If I stick the action in the tag all is well. But if instead it is in the tag, I get a 404 error. And it's the same action!

I've been debugging and discovered that when you use the "action" attribute in the tag, the generated html is:

<input type="submit" name="action:save">
<input type="submit" name="action:resetPassword">

Supposedly Struts should take this "action" prefix and say "A-ha! This is an action!" and execute it. And it more or less does this. Or at least tries to. What I've discovered is that at a very low level, the DefaultActionMapper.handleSpecialParameters() method goes through all the parameters and tries to create a ParameterAction for each one, and if it's not null, it is executed. Most of the parameters produce a "null" ParameterAction, but not "action:".

In the docs I found this about ParameterAction:

Defines a parameter action prefix.  This is executed when the configured prefix key is
matched in a parameter name, allowing the implementation to manipulate the action mapping 
accordingly.  For example, if the "action:foo" parameter name was found, and a 
ParameterAction implementation was registered to handle the "action" prefix, the execute 
method would be called, allowing the implementation to set the "method" value on the 
ActionMapping

So what it does is set the mapping's result to a new ServletDispatcherResult with the name of the Action:

mapping.setResult(new ServletDispatcherResult(actionName));

On the other hand, when the action is specified in the s:form tag, the mapping's result is null.

So that when finally we get to Dispatcher.serviceAction():

if (mapping.getResult() != null) {
 Result result = mapping.getResult();
 result.execute(proxy.getInvocation());
} else {
 proxy.execute();
}

So when the action is specified in the tag, proxy.execute() is called, which just calls the Action/method itself. Which is what should happen! But when the action is specified in the tag, since the mapping has a result, the proxy's invocation is passed to result.execute(), which calls ServletDispatcherResult ... and in the end, I get a 404.

This seems like a whole lot of work just to get multiple submit buttons with action attributes working. Is this a known issue for Struts 2.3? Do I need to implement a ParameterAction for the "action" prefix as stated in the docs?

EDIT

Ok, known bug, opened just a few days ago. In the meantime I can either downgrade to 2.3.15.1 or use the "method" attribute rather than the "action" attribute.

Hopefully it will be fixed soon ...

like image 669
Robert Bowen Avatar asked Oct 02 '13 12:10

Robert Bowen


1 Answers

this is b/c in struts2.3.16.

Disables support for action: prefix

by default struts.mapper.action.prefix.enabled = false

set

<constant name="struts.mapper.action.prefix.enabled" value="true"/> 

in struts.xml

Internal Changes of struts2-core 2.3.16

The action: and method: prefixes are be by default excluded and changed order to first check excludeParams and then acceptedParams in ParametersInterceptor

like image 172
MSR Avatar answered Nov 13 '22 07:11

MSR