Software Engineer

Things discovered in Struts 2

In this post I write about some things I discovered during the development of a project where Struts 2 is used. I note them since I couldn’t find them in the documentation and they were discovered through digging through pieces of documentation, the code and the web.

In general, sometimes more detailed information can be found in the Javadoc of the frameworks classes, e.g. interceptors.

Skipping validation for a specific method in an action class

If you use the validation interceptor some methods are already exluded by default (e.g. back or input) and you could add some more method names (even with a wildcard) to that list. This will be applied to the interceptor. But if you want to specify it in the action class on the method itself then you can use an annotation for that. Simply add @SkipValidation to the method and it will be skipped by the validation interceptor.

Using the parameters prepare trick with model driven actions

In the documentation of the interceptors there’s a trick (paramsPrepareParams trick) explained to call the parameters interceptor twice in order to be able to load something from the database in the prepare method (e.g. using a given ID)  and then getting the new parameters set to the loaded object.

This approach does not work when using model driven actions. When the parameters interceptor is called the first time, the model object doesn’t exist on the stack yet. Moving the model driven interceptor before the added parameters interceptor doesn’t work either because then the object on the stack doesn’t get updated (somehow). That means the model driven interceptor gets added a second time before the first parameters interceptor. That way the model object can be loaded from the database in prepare with the given parameters and then gets updated when the parameters interceptor gets executed the second time.

Receiving JSON requests (and using the model driven approach)

The JSON plugin for Struts can also receive requests containing JSON. All you have to do is simply add the JSON interceptor to your interceptor stack. Depending on the other interceptors you use it should be located after the model driven interceptor and before the validation interceptor for example. If you are using model driven actions though, you have to make a small adjustment because the interceptor tries to set the values to the action and not on to the model.

The interceptor has a property called root. All values will be added to this object. By default it is the action class. You can either set a param when you add the interceptor to your stack.

<interceptor-ref name="json">
    <param name="root">model</param>
</interceptor-ref>

Or set the param on your stack reference.

<interceptor-ref name="myStack">
    <param name="json.root">model</param>
</interceptor-ref>

But this means this will be applied to every action class. Even those that are not model driven. This will lead to a RuntimeException as the root object can’t be determined. Therefore I wrote my own small JSON intercepter (I already needed one so it wasn’t a big deal) that extends the original one and simply set model as the root object when the current action class is model driven. But the root object has to be resetted in any other case because the interceptor will be instantiated once.

@Override
public String intercept(ActionInvocation invocation) throws Exception {
    if (invocation.getAction() instanceof ModelDriven) {
        setRoot("model");
    }
    else {
        setRoot(null);
    }

    return super.intercept(invocation);
}

Update: This issue is resolved in Struts 2.2.3 (not released as of now). See this bug report.

Update #2: Since Struts 2.2.3 the root object is always considered to be the model if the action is model driven. This means that when creating the JSON request only the model will get serialized. In some cases one might use model driven for receiving requests and send something else in the response. Then the root object has to be changed. This can be done by setting the root parameter as shown above in the interceptor or for example in the result type.

<result-type name="json" class="org.apache.struts2.json.JSONResult">
    <param name="root">action</param>
</result-type>

3 Comments

  1. Sid

    Awesome! I used

    action

    And it solved my problem. Thanks. Doing good work!

  2. Mario D.

    Worked for me too! Ty đŸ™‚

  3. koushlendra singh parihar

    Hi Matthias,

    I am facing a problem related to JSON response when using ModelDriven, I have implemented ModelDriven and I need to expect the ActionError/ActionMessage in json response but I wasn’t able to do it.
    I used the below configuration when I’m not using ModelDriven and it works fine.

    false
    actionErrors\[\d+\], actionMessages\[\d+\]

    User is a POJO class
    Now I would like to do the same for ModelDriven, Kindly help me on this, If possible.

Leave a Reply

Your email address will not be published. Required fields are marked *

© 2024 Matthias Schoettle

Theme by Anders NorenUp ↑