Domanda

I'm writing a RESTful service with Struts2 and the Struts2 REST plugin. Currently, my service is able to handle GET requests without issues, but I'm stuck trying to get it the "update" (PUT) request to work.

I have two possible models, a List for show() and a ClientFeature object for update(), where ClientFeature is a pojo class.

REST Controller:

public class ClientfeatureController extends ControllerParent implements ModelDriven<Object> {

    private ClientFeature clientFeature = new ClientFeature();
    private List<ClientFeature> clientFeatureList;

    //Client ID
    private String id;

    public ClientfeatureController() {
        super(ClientfeatureController.class);
    }

    @Override
    public Object getModel() {
        return (clientFeatureList != null ? clientFeatureList : clientFeature);
    }

    /**
     * @return clientFeatureList through Struts2 model-driven design
     */
    public HttpHeaders show() {
        -logic for GET request here..-
        //todo: add ETag and lastModified information for client caching purposes
        return new DefaultHttpHeaders("show").disableCaching();
    }

    // PUT request: /clientfeature/update/<id> + JSON data
    public String update() {
        logger.info("client id: " + id);
        logger.info("updated model test:" + clientFeature.getClientId());
        return "update";
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public List<ClientFeature> getClientFeatureList() {
        return clientFeatureList;
    }

    public void setClientFeatureList(List<ClientFeature> clientFeatureList) {
        this.clientFeatureList = clientFeatureList;
    }
}

ClientFeature:

    public class ClientFeature {
    private Long clientId;
    private Feature feature;
    private ArrayList<String> countries;

    public ClientFeature() {
        this.countries = new ArrayList<String>();
    }

    public Long getClientId() {
        return clientId;
    }

    public void setClientId(Long clientId) {
        this.clientId = clientId;
    }

    public Feature getFeature() {
        return feature;
    }

    public void setFeature(Feature feature) {
        this.feature = feature;
    }

    public ArrayList<String> getCountries() {
        return countries;
    }

    public void setCountries(ArrayList<String> countries) {
        this.countries = countries;
    }
}

And am testing the service using the Postman extension for chrome and sending over JSON data that's something like:

{
 "clientFeature": {
   "feature" : {"featureId" : 999, "featureName" : "testFeature"}
   "countries": ["CA","US"]
   "clientId" : 001
 }
}

And the error:

356572 [http-bio-8080-exec-6] WARN  net.sf.json.JSONObject  - Tried to assign property clientFeature:java.lang.Object to bean of class com.foo.bar.ClientFeature

I'm pretty much new to everything related, so any help will be very much appreciated.

EDIT:

Tried sending the following JSON:

{ "com.foo.entity.clientFeature" : {"clientId":10} }

And got the following full error:

1016894 [http-bio-8080-exec-3] ERROR freemarker.runtime  - Method public java.lang.String org.apache.commons.lang.exception.NestableRuntimeException.getMessage(int) threw an exception when invoked on net.sf.json.JSONException: Error while setting property=com.foo.entity.clientFeature type class java.lang.Object

Method public java.lang.String org.apache.commons.lang.exception.NestableRuntimeException.getMessage(int) threw an exception when invoked on net.sf.json.JSONException: Error while setting property=com.foo.entity.clientFeature type class java.lang.Object
The problematic instruction:
----------
==> ${msg[0]} [on line 68, column 29 in org/apache/struts2/dispatcher/error.ftl]
----------

Java backtrace for programmers:
----------
freemarker.template.TemplateModelException: Method public java.lang.String org.apache.commons.lang.exception.NestableRuntimeException.getMessage(int) threw an exception when invoked on net.sf.json.JSONException: Error while setting property=com.foo.entity.clientFeature type class java.lang.Object
    at freemarker.ext.beans.SimpleMethodModel.exec(SimpleMethodModel.java:130)
    at freemarker.ext.beans.SimpleMethodModel.get(SimpleMethodModel.java:138)
    at freemarker.core.DynamicKeyName.dealWithNumericalKey(DynamicKeyName.java:111)
    at freemarker.core.DynamicKeyName._getAsTemplateModel(DynamicKeyName.java:90)
    at freemarker.core.Expression.getAsTemplateModel(Expression.java:89)
    at freemarker.core.Expression.getStringValue(Expression.java:93)
    at freemarker.core.DollarVariable.accept(DollarVariable.java:76)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.MixedContent.accept(MixedContent.java:92)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.IfBlock.accept(IfBlock.java:82)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.IteratorBlock$Context.runLoop(IteratorBlock.java:179)
    at freemarker.core.Environment.visit(Environment.java:417)
    at freemarker.core.IteratorBlock.accept(IteratorBlock.java:102)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.MixedContent.accept(MixedContent.java:92)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.IfBlock.accept(IfBlock.java:82)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.MixedContent.accept(MixedContent.java:92)
    at freemarker.core.Environment.visit(Environment.java:210)
    at freemarker.core.Environment.process(Environment.java:190)
    at freemarker.template.Template.process(Template.java:237)
    at org.apache.struts2.dispatcher.Dispatcher.sendError(Dispatcher.java:797)
    at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:519)
    at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
    at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:91)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:462)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:164)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:851)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:278)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:300)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:680)
Caused by: java.lang.NullPointerException
    at freemarker.ext.beans.SimpleMemberModel.unwrapArguments(SimpleMemberModel.java:85)
    at freemarker.ext.beans.SimpleMethodModel.exec(SimpleMethodModel.java:106)
    ... 43 more
È stato utile?

Soluzione

Solved the problem by using the correct JSON syntax..

In case anyone gets stuck on something similar, in my case the correct syntax is:

{clientFeature: {"feature":{"id":3,"enabled":true,"description":"description here","type":"FEATURE_TYPE_HERE"},"countries":["SG"],"clientId":10}}

Altri suggerimenti

i would like to explain what i've been found when develop API using Strtus2 rest plugin. you should understand how rest plugin manage our bean that expose to outside world (json, xml, etc)

i've stuck for a day to figure out how to my json bellow does't converting into my bean list properly.

so, this is my json string:

{ 
"messagesList": [{
    "id": "E57EC40F",
    "body": "Ok!",
    ... other_property
},{
    "id": "25B42CC8CCE57EC40F",
    "body": "Testing",
    ... other_property
}],
"ackList": [{
    "id": "5B42CC8CCE57EC40F",
    "queueNumber": 100,
    "chatId": "3434",
    "status": "delivered"
},{
    "id": "E6A25B42CC8CCE57EC40F",
    "queueNumber": 100,
    "chatId": "1747",
    "status": "viewed"
}]
}

with this json, i assume i could get and automatically translate that json to my list by add property

 List<OurModel> messageList;
 List<OurModel> ack;

in my controller. so my wrong controller looks like this:



@ParentPackage("api-pesan")
@Namespace("/api/pesan")
    public class RetrieveMessageApi implements ModelDriven<Object> {
    @Autowired
    WebHookService webHookService;

    Object retModal;
    List<OurModel> messagesList;
    List<OurModel> ack;
    public HttpHeaders create() throws IOException {

        System.out.println(messagesList.toString());

        System.out.println(ack.toString());

        return new DefaultHttpHeaders("create");
    }


    public Object getModel() {
        return model;
    }

//setter and getter

 }

if you assume you could print line the messagesList and ack property in create method, you are wrong. i am stuck a day to figure it out. this is my explanation about how to post json to our strtus2 rest plugin.

first of all, the rest plugin in struts2 only read the object (property name, also object as a type) when they retrieve and return object to the outside restful url.

by then, i create my class (pojo) to wrap my list. the class looks like this


public class WrapperModel implements Serializable {

    private List<YourObject> messages;
    private List<YourObject> ack;

//setter getter

}

you will notice, our json structure looks like the same with this class. so this is my complete and successful cotroller class that could get json and binding to our property properly.

@ParentPackage("api-pesan")
public class RetrieveMessageApi implements ModelDriven<Object> {

    @Autowired
    WebHookService webHookService;

    Object model = new WrapperModel();

    public HttpHeaders create() throws IOException {

        System.out.println(model.toString());


        return new DefaultHttpHeaders("create");
    }



    public Object getModel() {
        return model;
    }

}

then try to hit and send json via http://localhost:8080/app/api/api-pesan/retrieve-message.json and method post, also your json as body.

the result, you will see on log console the string of list in our property that source from our json.

Thank you, hope this help you guys....

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top