4

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.)

Roman C
  • 49,761
  • 33
  • 66
  • 176
  • 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 Oct 06 '17 at 12:07
  • @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 Oct 06 '17 at 16:18
  • I have already provided the code called by post request and I have also given the result after post request which is above the code – Muhammad Danish Khan Oct 06 '17 at 16:19
  • *No result defined for action* means Struts cannot find the result for action. Try fixing this before digging any further. – Aleksandr M Oct 06 '17 at 18:46
  • @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 Oct 06 '17 at 19:49
  • What do you mean? You can return string also. – Aleksandr M Oct 06 '17 at 19:53
  • @MuhammadDanishKhan This is the question I saw after that `Is there any way I can load my own ContentTypeHandlerManager or return custom response`. My question is how it's related to what you `specifically saying I want a custom response to send to client`. – Roman C Oct 06 '17 at 21:37
  • @AleksandrM If you see the above code which is create method this is the convention of struts2 rest plugin, when i change it, It doesn't even called. This is not a normal request, it is rest request so basically I would return either xml or json. If you know how return response in xml and json in rest post request please share it with me. – Muhammad Danish Khan Oct 07 '17 at 06:15
  • @RomanC, For time being I'm return HttpHeaders which accepts the method name and success code. During post request when i return HttpHeaders I get no result defined, When i debugged the ContentTypeHandlerManager, It takes the rest post response as normal response and it pickups xhtml as default template instead of xml or json. This is why wrote my own ContentTypeHandlerManager where it searches for specific namespace and if it is rest post request then it return response as xml or json. – Muhammad Danish Khan Oct 07 '17 at 06:18
  • @AleksandrM by change I mean return String instead of HttpHeaders. – Muhammad Danish Khan Oct 07 '17 at 06:22
  • @AleksandrM I have updated the question. Please go through it. – Muhammad Danish Khan Oct 07 '17 at 06:34
  • @MuhammadDanishKhan For time being you are in deep confuse what is returned by `HttpHeaders`. Asking for debugging at the first place is off-topic since you didn't provide [MCVE](http://stackoverflow.com/help/mcve). If your question is about overriding `ContentTypeHandlerManager` you should at least provide a source code and create a **clear problem statement**. From my point of view you are on the wrong way, however it's most interesting part of your question but it doesn't qualify for the topic on SO and we can't improve it for you without reading your attempts to destroy Struts2 :-) – Roman C Oct 07 '17 at 17:01
  • @RomanC Just ignore this ContentTypeHandlerManager. What should i do for returning custom response for post request. I have updated the question please see it. Removed the ContentTypeHandlerManager. – Muhammad Danish Khan Oct 07 '17 at 17:41
  • Ok, see the answer below @MuhammadDanishKhan – Roman C Oct 07 '17 at 21:12
  • Again. You need to fix the error about result not found. – Aleksandr M Oct 08 '17 at 19:40

2 Answers2

2

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"}
Roman C
  • 49,761
  • 33
  • 66
  • 176
  • I did what is said by the documents. When I send request like http://my.company.com/myapp/movies/superman.xml or .json it returns data accordingly, The only thing i can't find is that I want to return my custom response instead of redirecting it like it is done in struts2-rest-showcase. I have updated the questions – Muhammad Danish Khan Oct 08 '17 at 03:19
  • It returns response for post by redirecting and providing location id in httpheaders, I don't want to do this, Simple I want directly to return some custom message instead of redirection. – Muhammad Danish Khan Oct 08 '17 at 03:38
  • It returns a `Location` header in response, but it doesn't redirect, see the status code returned. – Roman C Oct 08 '17 at 14:45
  • Ok got it, but somehow in location you gave the URI. I don't want to do this. I want to return simply a message – Muhammad Danish Khan Oct 08 '17 at 16:08
  • The message you can return by adding a property to the action. – Roman C Oct 09 '17 at 02:29
  • can you please give me example. – Muhammad Danish Khan Oct 09 '17 at 06:41
  • I have already added a property by name response with type String. Still I'm getting same error. – Muhammad Danish Khan Oct 09 '17 at 07:20
  • The action returns a String that is a result code. You can check that its handled by rest action invocation and the result is returned. If its a redirect result or redirectAction result then it's not a error but a response returned to the client after executing the result configured to the action by the code. – Roman C Oct 09 '17 at 15:49
  • Though It was helpful but it was not what I wanted as I already know that. What I did was in Model I set the object which I need to return. So I created a response object and then set response object in Model and handled the object in Content-Type Handler – Muhammad Danish Khan Feb 28 '18 at 12:05
  • I have answered the question and marked as correct. – Muhammad Danish Khan Feb 28 '18 at 12:14
  • @Muhammad you might being wrong marked your answer. It's not correct and you should think before you makes someone answer as accepted answer. The accepted answer is not necessary correct one if you need learn More about how stack overflow works. – Roman C Mar 05 '18 at 23:22
  • Adding `` makes the response to be of JSON type when request if of type POST, PUT, DELETE. – Kavin Raju S Feb 08 '22 at 16:33
0

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));
}