Spring+GWT+jackson+JSON response text does not app

2019-08-09 18:57发布

Hi it's in relation to below post -

smartgwt listgrid RestDataSource not populating

I am facing an issue while trying to build an app with smartGWT and Spring3. Using jackson to convert return object to json.

Error (complete stack trace at end of the post) for json response returned from spring controller to client side:

16:52:27.094 [ERROR] [utilapp] 16:52:27.092:TMR1:WARN:RestDataSource:isc_ItemListGrid_1_0:RestDataSouce transformResponse(): JSON response text does not appear to be in standard response format. com.smartgwt.client.core.JsObject$SGWT_WARN: 16:52:27.092:TMR1:WARN:RestDataSource:isc_ItemListGrid_1_0:RestDataSouce transformResponse(): JSON response text does not appear to be in standard response format.

Just wondering if anyone else has encountered such error before or any hints on what may be the reason behind this will be very useful.

Json response payload on hitting corresponding GET method url directly from browser - {"status":0,"data":null,"errors":{},"endRow":0,"startRow":0,"totalRows":-1}

All fields have default values, although setting these within controller.

Have defined DSResponse POJO to bring json response in sync with what described on link - http://www.smartclient.com/smartgwt/javadoc/com/smartgwt/client/data/RestDataSource.html

Web.xml: dispatcher servlet entry

<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>         
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>

spring-servlet.xml – (annotation based so no controller beans just mapping to JacksonJsonView)

<context:component-scan base-package="com.khush.util.server.rest" />
<context:component-scan base-package="com.khush.util.server.spring" />
<context:annotation-config/>
<mvc:annotation-driven/>

<bean class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="html" value="text/html"/>
<entry key="json" value="application/json"/>
</map>
</property>
<property name="viewResolvers">
<list>
<bean class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="prefixJson" value="true"/>
</bean>
</list>
</property>
</bean>

Spring controller on server side–

@Controller
@RequestMapping("/service*")
public class RPCListService {

       @RequestMapping(value="/fetch", method=RequestMethod.POST)
       public @ResponseBody DSResponse fetch(@RequestBody String json){
              DSResponse dsResponse = new DSResponse();
              List<Account> accounts = new ArrayList<Account>();
              Account account;

              for(int i = 0 ; i < 500 ; i++){
                     account = new Account();
                     account.setAccountId(i * 100L);
                     account.setAccountName("i " + "accountName");
                     account.setAccountNumber("i " + "accountNumber");
                  accounts.add(account);
              }
              dsResponse.setDate(accounts.toArray());

              return response;
       }

       @RequestMapping(value="/get", method=RequestMethod.GET)
       @ResponseBody public Object get(@RequestBody String json){
              DSResponse dsResponse = new DSResponse();
              List<Account> accounts = new ArrayList<Account>();
              Account account;

              for(int i = 0 ; i < 500 ; i++){
                     account = new Account();
                     account.setAccountId(i * 100L);
                     account.setAccountName("i " + "accountName");
                     account.setAccountNumber("i " + "accountNumber");
                  accounts.add(account);
              }
              dsResponse.setDate(accounts.toArray());
              return dsResponse;
       }
}

RestDataSource def on client side –

public class AccountDataSource extends SpringJSONDataSource {

       public AccountDataSource(List<DataSourceField> fields) {
              super(fields);
              setPrettyPrintJSON(true);
       }

       @Override
       protected OperationBinding getFetch() {
              OperationBinding fetch = new OperationBinding();
           fetch.setOperationType(DSOperationType.FETCH);
           fetch.setDataProtocol(DSProtocol.POSTMESSAGE);
           DSRequest fetchProps = new DSRequest();
           fetchProps.setHttpMethod(httpMethod);
           fetch.setRequestProperties(fetchProps);

           return fetch;
       }

       @Override
       protected OperationBinding getRemove() {
              // TODO Auto-generated method stub
              return null;
       }

       @Override
       protected OperationBinding getAdd() {
              // TODO Auto-generated method stub
              return null;
       }

       @Override
       protected OperationBinding getUpdate() {
              // TODO Auto-generated method stub
              return null;
       }

       @Override
       public String getUpdateDataURL() {
              // TODO Auto-generated method stub
              return null;
       }

       @Override
       public String getRemoveDataURL() {
              // TODO Auto-generated method stub
              return null;
       }

       @Override
       public String getAddDataURL() {
              // TODO Auto-generated method stub
              return null;
       }

       @Override
       public String getFetchDataURL() {
              return "/rest/service/fetch";
       }
}


public abstract class SpringJSONDataSource extends RestDataSource {

       protected final String httpMethod;

       public SpringJSONDataSource(List<DataSourceField> fields){
              this(fields, "POST");
       }

       public SpringJSONDataSource(List<DataSourceField> fields, String httpMethod) {
           this.httpMethod = httpMethod;
           setDataFormat(DSDataFormat.JSON);
           addDataSourceFields(fields);
           setOperationBindings(getFetch());
           addURLs();
       }

       private void addURLs() {
           if(getUpdateDataURL() != null)
               setUpdateDataURL(getUpdateDataURL());

           if(getRemoveDataURL() != null)
               setRemoveDataURL(getRemoveDataURL());

           if(getAddDataURL() != null)
               setAddDataURL(getAddDataURL());

           if(getFetchDataURL() != null)
               setFetchDataURL(getFetchDataURL());

       }

       private void addDataSourceFields(List<DataSourceField> fields) {
           for (DataSourceField dataSourceField : fields) {
               addField(dataSourceField);
           }
       }

       protected abstract OperationBinding getFetch();
       protected abstract OperationBinding getRemove();
       protected abstract OperationBinding getAdd();
       protected abstract OperationBinding getUpdate();

       public abstract String getUpdateDataURL();
       public abstract String getRemoveDataURL();
       public abstract String getAddDataURL();
       public abstract String getFetchDataURL();
}

Account and DSResponse objects –

public class Account implements Serializable {

       private static final long serialVersionUID = 1L;       

       private Long accountId;

       private String accountName;

       private String accountNumber;


       public Account(){
       }

       public Account(Long accountId){
              setAccountId(accountId);
       }

       public Long getAccountId() {
              return accountId;
       }

       public void setAccountId(Long accountId) {
              this.accountId = accountId;
       }

       public String getAccountName() {
              return accountName;
       }

       public void setAccountName(String accountName) {
              this.accountName = accountName;
       }

       public String getAccountNumber() {
              return accountNumber;
       }

       public void setAccountNumber(String accountNumber) {
              this.accountNumber = accountNumber;
       }

       @Override
       public String toString(){
              StringBuilder sb = new StringBuilder();
              sb.append("Account Id: ").append(getAccountId()).append(", ");
              sb.append("Account Name: ").append(getAccountName()).append(", ");
              sb.append("Account Number: ").append(getAccountNumber()).append(", ");

              return sb.toString();
       }

       @Override
       public int hashCode(){
              final int prime = 31;
              int result = 1;
              result = prime * result + ((accountName == null) ? 0 : accountName.hashCode());
              return result;
       }

       @Override
       public boolean equals(Object obj){
              if(this == obj)
                     return true;
              if(obj == null)
                     return false;
              if(!(obj instanceof Account))
                     return false;
              Account other = (Account)obj;
              if(accountId == null){
                     if(other.accountId != null)
                           return false;
              } else if(! accountId.equals(other.accountId))
                     return false;
              if(accountName == null){
                     if(other.getAccountName() != null)
                           return false;
              }else if(! accountName.equals(other.accountName))
                     return false;
              if(accountNumber == null){
                     if(other.accountNumber != null)
                           return false;
              }else if(! accountNumber.equals(other.accountNumber))
                     return false;
              return true;
       }
}

public class DSResponse implements Serializable{

       private static final long serialVersionUID = -4937262101507779477L;

       public static int STATUS_FAILURE = -1;
       public static int STATUS_LOGIN_INCORRECT = -5;
       public static int STATUS_LOGIN_REQUIRED = -7;
       public static int STATUS_LOGIN_SUCCESS = -8;
       public static int STATUS_MAX_LOGIN_ATTEMPTS_EXCEEDED = -6;
       public static int STATUS_SERVER_TIMEOUT = -100;
       public static int STATUS_SUCCESS = 0;
       public static int STATUS_TRANSPORT_ERROR = -90;
       public static int STATUS_VALIDATION_ERROR = -4;

       private int status;
       private Integer startRow;
       private Integer endRow;
       private Integer totalRows;
       private Object[] data;
       private Map errors;

       public int getStatus()
       {
              return status;
       }

       public void setStatus(int status)
       {
              this.status = status;
       }

       public Integer getStartRow()
       {
              return startRow;
       }

       public void setStartRow(Integer startRow)
       {
              this.startRow = startRow;
       }

       public Integer getEndRow()
       {
              return endRow;
       }

       public void setEndRow(Integer endRow)
       {
              this.endRow = endRow;
       }

       public Integer getTotalRows()
       {
              return totalRows;
       }

       public void setTotalRows(Integer totalRows)
       {
              this.totalRows = totalRows;
       }

       public Object[] getData()
       {
              return data;
       }

       public void setData(Object[] data)
       {
              this.data = data;
       }

       public Map getErrors()
       {
              return errors;
       }

       public void setErrors(Map errors)
       {
              this.errors = errors;
       }

       public DSResponse()
       {
              status = STATUS_SUCCESS;

              errors = new HashMap();
              startRow = 0;
        endRow = 0;
        totalRows = -2;
       }

       public DSResponse(int status)
       {
              this.status = status;

              errors = new HashMap();
        startRow = 0;
        endRow = 0;
        totalRows = -1;
       }

}

Complete stack trace :

09:24:58.896 [ERROR] [utilapp] 09:24:58.894:TMR0:WARN:RestDataSource:isc_AccountDataSource_0:RestDataSouce transformResponse(): JSON response text does not appear to be in standard response format. com.smartgwt.client.core.JsObject$SGWT_WARN: 09:24:58.894:TMR0:WARN:RestDataSource:isc_AccountDataSource_0:RestDataSouce transformResponse(): JSON response text does not appear to be in standard response format. at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) at java.lang.reflect.Constructor.newInstance(Constructor.java:513) at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:105) at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71) at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172) at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:338) at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:219) at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136) at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:571) at com.google.gwt.dev.shell.ModuleSpace.invokeNativeVoid(ModuleSpace.java:299) at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeVoid(JavaScriptHost.java:107) at com.smartgwt.client.data.DataSource.transformResponse(DataSource.java) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103) at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71) at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172) at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:338) at com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:219) at com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136) at com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:571) at com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:279) at com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91) at com.google.gwt.core.client.impl.Impl.apply(Impl.java) at com.google.gwt.core.client.impl.Impl.entry0(Impl.java:242) at sun.reflect.GeneratedMethodAccessor50.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103) at com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71) at com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172) at com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:293) at com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:547) at com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:364) at java.lang.Thread.run(Thread.java:619)

thanks!

2条回答
Melony?
2楼-- · 2019-08-09 19:38

sorted it out by defining a simple java object (used as return type of Spring controller) implementing Serializable interface with a variable named 'response' of type Map and added contents of the json response to that map as key-value paired and it worked.

thanks

查看更多
Bombasti
3楼-- · 2019-08-09 19:53

Well you have no data in your response according to your comment. Does your response match exactly the format specified here?

I suggest it may not match, given your error message is

JSON response text does not appear to be in standard response format

What to do next? Maybe try converting some really simple object to JSON to see if the problem lies with your Account object? Try it with just one Account object in the response? Or post your Account object code?

查看更多
登录 后发表回答