Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

POST request to Struts2 with REST plugin not receiving response

I have a struts2 application which uses the struts2-rest-plugin v.2.2.3.

Everything is working great when it comes to the routing of the requests to the actions and its methods and I'm also using ModelDriven to specify the object to serialise when using extensions like JSON and XML.

The problem I'm having is that when I send a POST or PUT request to the struts layer I just get an empty response.

I am sending a POST request to the action like so: http://localhost:8080/alert-settings!update.json. I have a breakpoint in that method and it gets called and the code runs and completes. I have a feeling the issue might be that I am trying to use the ModelDriven interface to send me back the response and for some reason the rest-plugin doesn't like this but I don't know why it would behave like that.

Is there a known issue with receiving responses from POST requests while using the rest plugin? I have looked everywhere and can't find anything about it really.

Any help appreciated and I can provide any more details on request.

like image 837
noShowP Avatar asked Oct 07 '11 09:10

noShowP


2 Answers

I encountered the same issue. Have you tried to set in the struts.xml file:

struts.rest.content.restrictToGET = false

See the last setting on the rest plugin docs

like image 117
ontk Avatar answered Sep 28 '22 22:09

ontk


I actually figured out that it was a line in the rest plugin causing this:

// don't return any content for PUT, DELETE, and POST where there are no errors
if (!hasErrors && !"get".equalsIgnoreCase(ServletActionContext.getRequest().getMethod())) {
  target = null;
}

This is in org.apache.struts2.rest.RestActionInvocation in the selectTarget() method. I find this to be quite annoying as it doesn't really follow the REST architecture, id like the option to be able to return response objects for POST, DELETE and PUT requests in some cases.

I worked around this by extending RestActionProxyFactory and RestActionInvocation and specifying the use of this in my struts xml like so:

<bean type="com.opensymphony.xwork2.ActionProxyFactory" name="restOverride" class="uk.co.ratedpeople.tp.rest.RPRestActionProxyFactory" />
<constant name="struts.actionProxyFactory" value="restOverride" />

This allows me to use the struts plugin throughout while returning object on POST requests.

RestActionProxyFactory

public class RPRestActionProxyFactory extends RestActionProxyFactory {

    @Override
    public ActionProxy createActionProxy(String namespace, String actionName, String methodName, Map extraContext, boolean executeResult, boolean cleanupContext) {
        if (namespace.startsWith(this.namespace)) {
            ActionInvocation inv = new RPRestActionInvocation(extraContext, true);
            container.inject(inv);
            return createActionProxy(inv, namespace, actionName, methodName, executeResult, cleanupContext);
        } else {
            return super.createActionProxy(namespace, actionName, methodName, extraContext, executeResult, cleanupContext);
        }
    }

}

RestActionInvocation

public class RPRestActionInvocation extends RestActionInvocation {

    public RPRestActionInvocation(Map extraContext, boolean pushAction) {
        super(extraContext, pushAction);
    }

    @SuppressWarnings("unchecked")
    @Override
    protected void selectTarget() {

        // Select target (content to return)
        Throwable e = (Throwable)stack.findValue("exception");
        if (e != null) {

            // Exception
            target = e;
            hasErrors = true;

        } else if (action instanceof ValidationAware && ((ValidationAware)action).hasErrors()) {

            // Error messages
            ValidationAware validationAwareAction = ((ValidationAware)action);

            Map errors = new HashMap();
            if (validationAwareAction.getActionErrors().size() > 0) {
                errors.put("actionErrors", validationAwareAction.getActionErrors());
            }
            if (validationAwareAction.getFieldErrors().size() > 0) {
                errors.put("fieldErrors", validationAwareAction.getFieldErrors());
            }
            target = errors;
            hasErrors = true;

        } else if (action instanceof ModelDriven) {

            // Model
            target = ((ModelDriven)action).getModel();

        } else {
            target = action;
        }

        // don't return any content for PUT, DELETE, and POST where there are no errors
//      if (!hasErrors && !"get".equalsIgnoreCase(ServletActionContext.getRequest().getMethod())) {
//          target = null;
//      }
    }

}
like image 22
noShowP Avatar answered Sep 28 '22 21:09

noShowP