2

I am using Struts2 and request.getInputStream() can't be used, since it gives error on 2nd use, first might have already being used by any of the interceptors.

So, I believe there must be some way to get the request-body. But I didn't found anything on internet, please help.

coding_idiot
  • 13,526
  • 10
  • 65
  • 116

1 Answers1

1

As you say, the interceptor (I guess JSONInterceptor) has already done the job before for you. Probably you have a similar struts.xml structure:

struts.xml

<constant name="struts.action.extension" value="xhtml,,xml,json,action"/> 
<constant name="struts.mapper.class" value="org.apache.struts2.dispatcher.mapper.PrefixBasedActionMapper" />
<constant name="struts.mapper.prefixMapping" value="/rest:rest,:struts"/>    
<constant name="struts.convention.action.suffix" value="Controller"/>
<constant name="struts.convention.action.mapAllMatches" value="true"/>
<constant name="struts.convention.default.parent.package" value="rest-default"/>    
<constant name="struts.convention.package.locators" value="rest"/>  
<constant name="struts.rest.namespace" value="/rest" />

<constant name="struts.rest.negotiation.handlerOverride.application/json" value="json" />


<package name="rest" namespace="/rest" extends="rest-default">          
        <interceptors>
            <interceptor name="json" class="org.apache.struts2.json.JSONInterceptor"/>
        </interceptors>         

        <action name="yourAction" class="com.struts.rest.MyController">                     
            <interceptor-ref name="json" />     
            <interceptor-ref name="defaultStack"/>
        </action>
</package>

Then, If you are trying to parse a JSON request like this:

{ "token":"mh5h6jrjkvnrk56" }

You should have a Controller (or Action) like this:

package com.struts.rest;
import ...

public class MyController implements ModelDriven<Result>{

    private static final long serialVersionUID = 1L;
    private static final Logger logger = Logger.getLogger(MyController.class.getName());
    private String token;           

    // Handles GET requests 
    public String index() {                         
        logger.info("token: " + token);         
        return "index";            
    }

    // Handles /POST requests
    public String create(){    
        // ....
        return "create"     
    }

    // Handles /PUT requests
    public HttpHeaders update() {   
        // ....
        return "update"
    }           

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }
}

In a RequestAware/ServletRequestAware Action you should access the request with request.getInputStream(), but when the JSONInterceptor acts, just let him do the work. Create as many fields as JSON elements want to be parsed in the Action/Controller. In this example I'm creating a String token field (with it's setter and getter) to hold the content of the JSON element "token".

When a /GET (with {"token":"mh5h6jrjkvnrk56"}) is done, index() is called and the field token has the value "mh5h6jrjkvnrk56" (as in the example).

exoddus
  • 2,230
  • 17
  • 27
  • Thank you @exoddus for your answer, it works. But when I try to make a request of type `GET` /movies/{id} or `PUT` /movies/{id}, I am getting the following error `HTTP ERROR: 500 Unable to show problem report: freemarker.core.InvalidReferenceException: The following has evaluated to null or missing: ==> rootloc.URI [in template "org/apache/struts2/dispatcher/error.ftl" at line 84, column 15]` `Java stack trace (for programmers): ---- freemarker.core.InvalidReferenceException: [... Exception message was already printed; see it above ...]`. Can anyone please let me know, what it's about? – Kavin Raju S Feb 08 '22 at 05:05