3
votes

I have implemented Struts2 REST API from getting info from here

Struts2 Rest Plugin

Is there any way to return custom response in in restful plugin in Struts2. I did all the required changes like

struts.rest.content.restrictToGET = false

Got from This Question. Still I'm getting this error

No result defined for action `com.web.Controller.RestDemoController` and result create, 

If I don't add the above line I still get the same response.

This is the action i have provided in struts.xml:

<action name="restdemo" class="com.web.Controller.RestDemoController">
    <interceptor-ref name="customRestStack"></interceptor-ref>
</action>

This serves all the request GET,POST,PUT,UPDATE.

After Changing return type of post method from HttpHeader to String I'm still getting the same error

Error 404: No result defined for action com.web.Controller.RestDemoController and result <?xml version="1.0" encoding="UTF-8"?> <Status><code>200</code><message>Success</message></Status>

This is the code i have written for POST:

public HttpHeaders create(){
    System.out.println(envision2Data.toString());
    return new DefaultHttpHeaders("create").withStatus(200);
}

this is the POST request method with return type String:

public String create(){
    System.out.println(envision2Data.toString());
    return "<?xml version=\"1.0\" encoding=\"UTF-8\"?> <Status><code>200</code><message>Success</message></Status>";
}

I'm getting perfect response for get either if i send request for xml or json, I do get xml and json based on extension. like http://localhost:8080/restdemoapplication/restdemo.xml, http://localhost:8080/restdemoapplication/restdemo.json

for POST request i do post request like enter image description here

and you can see the response i get. The method i have written for post is written above with name create. I do have data in body and I do get the data in create method perfectly.

Now in post as i have seen in multiple example like

struts-rest, stuts2-rest-sample, struts2-rest-shopping-list

I don't want to return response for post request like these applications do. I want to return my own response, It will be a status code and a message like this

<?xml version="1.0" encoding="UTF-8"?> <Status><code>200</code><message>Success</message></Status>

After some debugging I found that DefaultContentTypeHandlerManager in struts2-rest-plugin consider xhtml as default template. While it should be either XML or JSON.

I want to return

 code : 1xx,2xx,4xx
 message: Success, Fail

in either XML or JSON when a POST request is entertained.

(This is application entertains both non-restful request and restful requests. I can make xml or json as default template but I don't want as it will effect non-restful requests.)

2
This is unclear why do you need to override ContentTypeHandlerManager, it won't help you . And the link is absolutely has nothing with your problem. I will mark this off-topic, nobody interestin to dig into Struts2 internals if any, without clear problem statement, without code, asking for XY problem.Roman C
@Roman C if you see at the top I'm specifically saying I want a custom response to send to client. it may be xml or json. And After that you will see that what kind of response do i get when i do a post request. Can you please mention what kind of more information do you need to make this question more suitable.Muhammad Danish Khan
I have already provided the code called by post request and I have also given the result after post request which is above the codeMuhammad Danish Khan
No result defined for action means Struts cannot find the result for action. Try fixing this before digging any further.Aleksandr M
@AleksandrM do we really need result for rest api in struts2? Is it not supposed to return a success or failure response?Muhammad Danish Khan

2 Answers

1
votes

You misunderstood the concept of content types used with struts2-rest-plugin.

Content Types

In addition to providing mapping of RESTful URL's to Controller ( Action ) invocations, the REST plugin also provides the ability to produce multiple representations of the resource data. By default, the plugin can return the resource in the following content types:

  • HTML
  • XML
  • JSON

There is nothing configure here, just add the content type extension to your RESTful URL. The framework will take care of the rest. So, for instance, assuming a Controller called Movies and a movie with the id of superman, the following URL's will all hit the

http://my.company.com/myapp/movies/superman
http://my.company.com/myapp/movies/superman.xml
http://my.company.com/myapp/movies/superman.xhtml
http://my.company.com/myapp/movies/superman.json

Note, these content types are supported as incoming data types as well. And, if you need, you can extend the functionality by writing your own implementations of org.apache.struts2.rest.handler.ContentTypeHandler and registering them with the system.

The plugin servers request by content type, either provided as action extension or by providing a data type. Incoming data type is defined by "Content-Type" header, and outgoing data type defined by "Accept" header.

To make POST request returning data you need to add a constant to Struts configuration file struts.xml:

<constant name="struts.rest.content.restrictToGET" value="false"/>

Demo application is provided with the Struts distro named struts2-rest-showcase. After adding a constant above you can test the application with some http client.

POST http://localhost:8080/orders
Accept: application/json
Content-Type: application/json
{
  "id":"23423423",
  "clientName":"Roman C",
  "amount": 1000
}
 -- response --
201 
Content-Language:  en-US
Content-Length:  54
Content-Type:  application/json;charset=UTF-8
Date:  Sat, 07 Oct 2017 20:44:39 GMT
ETag:  -735433458
Location:  http://localhost:8080/orders/23423423

{"amount":1000,"clientName":"Roman C","id":"23423423"}
0
votes

So here is the solution which I needed. What I did is

@Override
public Object getModel() {
        <!-- Changed name of the object overhere to mainObject-->
    if (mainObject == null) {
        if (responseObject != null) {
            return responseObject;
        } else if (mainObject != null) {
            return mainObject;
        }
        mainObject = new mainObject();
    }
    return mainObject;
}

and then in content type handler. Content-Type handler is custom as I have used Jackson for conversion from JSON to object and vice versa.

if (paramObject instanceof MainObject) {
        MainObject mainObject = (MainObject) paramObject;
        writer.write(mapper.writeValueAsString(mainObject));
} else if (paramObject instanceof ResponseObject) {
        ResponseObject responeObject = (ResponseObject) paramObject;
        writer.write(mapper.writeValueAsString(responeObject));
}