Struts2 JSON Plugin: Adding ActionMessages, ActionErrors, and FieldErrors to response

icats picture icats · Mar 25, 2011 · Viewed 10.6k times · Source

I am making JQuery Ajax posts and would like any actionmessages, actionerrors, and fielderrors added to in the action back in the response (in JSON format).

I added this result:

<result name="input" type="json">    
    <param name="ignoreHierarchy">false</param>  
    <param name="includeProperties">fieldErrors,actionErrors</param>  
</result>

to my action configuration in the struts.xml.

I am getting: {"actionErrors":[],"fieldErrors":{}} back as a response, despite there being field errors on the value stack.

If I change my result configuration to:

<result name="input" type="json">    
    <param name="ignoreHierarchy">false</param>  
    <param name="root">fieldErrors</param>  
</result>

the JSON response is I expected::
{"thePropertyWithValidationError":["You must supply correct information."]}

I would really like both action errors and field errors included in the response, if possible.

Any ideas? Thank you so much in advance!!

Edit:
I think I may need to utilize some sort of regular expression...I tried:

<result name="input" type="json">    
    <param name="ignoreHierarchy">false</param>  
    <param name="includeProperties">fieldErrors\[\d+\],actionErrors\[\d+\]</param>  
</result>

with the same result:

{"actionErrors":[],"fieldErrors":{}}

I also found this bug report, which may be contributing to my issues as I am using Struts v2.2.1. (v2.2.2 is not yet out)

Edit #2:

Perhaps the JSONValidationInterceptor is what I need...I can't seem to figure out how to use it with my custom JQuery Ajax posts...

I am using the json interceptor to populate my properties-below is my action configuration:

<action name="MyAction" method="add" class="com.test.actions.MyAction">
    <interceptor-ref name="json" />
    <interceptor-ref name="jsonValidationWorkflowStack"/>
    <interceptor-ref name="MyCustomInterceptor" />  
    <result name="success" type="json" />
</action>  

I am posting: {"struts.enableJSONValidation":"true", "testProperty":"true"}

The response is just forwarding to my global results mapping, error.jsp (with the field errors displayed as I have them set to display in the error.jsp):

<global-results>   
    <result name="error">/WEB-INF/jsp/error.jsp</result>  
    <result name="Exception">/WEB-INF/jsp/error.jsp</result>  
</global-results>  
<global-exception-mappings>  
    <exception-mapping exception="java.lang.Throwable" result="Exception" />  
</global-exception-mappings>  

I guess I was expecting that if there were fielderrors/actionerrors on the stack, they would be returned as JSON?

Answer

icats picture icats · Apr 19, 2011

I figured out how to return ActionErrors, ActionMessages, and FieldErrors in the JSON result!

Below is a sample package- I set a up a global error handler that spits out the action errors, field errors, and action messages as JSON:

<!--myBase has interceptor stack defined-->
<package name="JsonResults" namespace="/json" extends="myBase">

<global-results>
    <result name="input" type="json">
        <param name="ignoreHierarchy">false</param>
        <param name="includeProperties">actionErrors\[\d+\], fieldErrors\..+$, actionMessages\[\d+\]</param>
    </result>
    <result name="error" type="json">
        <param name="ignoreHierarchy">false</param>
        <param name="includeProperties">actionErrors\[\d+\], fieldErrors\..+$, actionMessages\[\d+\]</param>
    </result>
    <result name="Exception" type="json">
        <param name="ignoreHierarchy">false</param>
        <param name="includeProperties">actionErrors\[\d+\], fieldErrors\..+$, actionMessages\[\d+\]</param>
    </result>
</global-results>
<global-exception-mappings>
    <exception-mapping exception="java.lang.Throwable" result="Exception" />
</global-exception-mappings>

<!-- sample action -->  
<action name="SampleAction" method="loadSamples" class="com.sample">
    <result name="success" type="json">
        <param name="ignoreHierarchy">false</param>
        <param name="includeProperties">sampleComplexBean\[\d+\]\..+$, actionMessages\[\d+\]</param>
    </result>   
</action>
</package>

I can check in my JQuery Javascript if action errors or field errors exist:

/**
 * Checks the passed in json and searches for the 
 * existence of an "actionErrors" or "fieldErrors" objects
 * 
 * @param json          The JSON to check for errors
 * @returns {Boolean}   true if errors exist; false otherwise
 */
function areActionOrFieldErrorInJson(json) {

    var errorsExist = false;

    if ( json != null && ( json.actionErrors != null || json.fieldErrors != null ) ) {
        errorsExist = true;
    }

    return errorsExist;
}  

or loop through them as follows:

if ( json.actionErrors != null && json.actionErrors.length !== 0 ) {  
    $.each(json.actionErrors, function(e) {  
        doStuff(this);  
    });  
}