【问题标题】:Spring+GWT+jackson+JSON response text does not appear to be in standard response formatSpring+GWT+jackson+JSON 响应文本似乎不是标准响应格式
【发布时间】:2013-04-23 22:42:01
【问题描述】:

嗨,这与下面的帖子有关-

smartgwt listgrid RestDataSource not populating

我在尝试使用 smartGWT 和 Spring3 构建应用程序时遇到问题。使用jackson将返回对象转成json。

从 spring 控制器返回到客户端的 json 响应的错误(帖子末尾的完整堆栈跟踪):

16:52:27.094 [ERROR] [utilapp] 16:52:27.092:TMR1:WARN:RestDataSource:isc_ItemListGrid_1_0:RestDataSouce transformResponse():JSON 响应文本似乎不是标准响应格式。 com.smartgwt.client.core.JsObject$SGWT_WARN: 16:52:27.092:TMR1:WARN:RestDataSource:isc_ItemListGrid_1_0:RestDataSouce transformResponse(): JSON 响应文本似乎不是标准响应格式。

只是想知道是否有其他人以前遇到过这样的错误,或者任何关于这可能是什么原因的提示将非常有用。

直接从浏览器点击相应的 GET 方法 url 时的 Json 响应负载 - {"status":0,"data":null,"errors":{},"endRow":0,"startRow":0,"totalRows":-1}

所有字段都有默认值,尽管在控制器中设置了这些值。

已定义 DSResponse POJO 以使 json 响应与链接上描述的内容同步 - http://www.smartclient.com/smartgwt/javadoc/com/smartgwt/client/data/RestDataSource.html

Web.xml:调度程序 servlet 条目

<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 –(基于注释,因此没有控制器 bean 只是映射到 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
@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 –

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 和 DSResponse 对象 –

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

}

完整的堆栈跟踪:

09:24:58.896 [ERROR] [utilapp] 09:24:58.894:TMR0:WARN:RestDataSource:isc_AccountDataSource_0:RestDataSouce transformResponse():JSON 响应文本似乎不是标准响应格式。 com.smartgwt.client.core.JsObject$SGWT_WARN: 09:24:58.894:TMR0:WARN:RestDataSource:isc_AccountDataSource_0:RestDataSouce transformResponse():JSON 响应文本似乎不是标准响应格式。 在 sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 在 sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39) 在 sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27) 在 java.lang.reflect.Constructor.newInstance(Constructor.java:513) 在 com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:105) 在 com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71) 在 com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172) 在 com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:338) 在 com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:219) 在 com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136) 在 com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:571) 在 com.google.gwt.dev.shell.ModuleSpace.invokeNativeVoid(ModuleSpace.java:299) 在 com.google.gwt.dev.shell.JavaScriptHost.invokeNativeVoid(JavaScriptHost.java:107) 在 com.smartgwt.client.data.DataSource.transformResponse(DataSource.java) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 在 java.lang.reflect.Method.invoke(Method.java:597) 在 com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103) 在 com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71) 在 com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172) 在 com.google.gwt.dev.shell.BrowserChannelServer.reactToMessagesWhileWaitingForReturn(BrowserChannelServer.java:338) 在 com.google.gwt.dev.shell.BrowserChannelServer.invokeJavascript(BrowserChannelServer.java:219) 在 com.google.gwt.dev.shell.ModuleSpaceOOPHM.doInvoke(ModuleSpaceOOPHM.java:136) 在 com.google.gwt.dev.shell.ModuleSpace.invokeNative(ModuleSpace.java:571) 在 com.google.gwt.dev.shell.ModuleSpace.invokeNativeObject(ModuleSpace.java:279) 在 com.google.gwt.dev.shell.JavaScriptHost.invokeNativeObject(JavaScriptHost.java:91) 在 com.google.gwt.core.client.impl.Impl.apply(Impl.java) 在 com.google.gwt.core.client.impl.Impl.entry0(Impl.java:242) 在 sun.reflect.GeneratedMethodAccessor50.invoke(未知来源) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 在 java.lang.reflect.Method.invoke(Method.java:597) 在 com.google.gwt.dev.shell.MethodAdaptor.invoke(MethodAdaptor.java:103) 在 com.google.gwt.dev.shell.MethodDispatch.invoke(MethodDispatch.java:71) 在 com.google.gwt.dev.shell.OophmSessionHandler.invoke(OophmSessionHandler.java:172) 在 com.google.gwt.dev.shell.BrowserChannelServer.reactToMessages(BrowserChannelServer.java:293) 在 com.google.gwt.dev.shell.BrowserChannelServer.processConnection(BrowserChannelServer.java:547) 在 com.google.gwt.dev.shell.BrowserChannelServer.run(BrowserChannelServer.java:364) 在 java.lang.Thread.run(Thread.java:619)

谢谢!

【问题讨论】:

  • 你的控制器是什么样的?您确定要从控制器返回 JSON 吗?如果你用浏览器点击你的控制器,你的响应看起来像有效的 JSON 吗?
  • 嗨,马克,感谢您的回复。 {"status":0,"data":null,"errors":{},"endRow":0,"startRow":0,"totalRows":-1} 是在浏览器中点击控制器时的响应。还在帖子中添加控制器代码。
  • 还添加了控制器代码。 jackson 用于将对象转换为 JSON 格式
  • 看起来错误是在调用 :RestDataSouce transformResponse() 但不确定原因
  • 谢谢马克。尽管我正在从控制器代码中清除数据到响应中,但 JSON 响应有效负载中的数据仍然为空。也已经通过 RestDataSource 的链接,但如何转换为该格式是关于链接帖子的问题 - stackoverflow.com/q/13455342/2294988

标签: java spring gwt jackson smartgwt


【解决方案1】:

根据您的评论,您的回复中没有数据。您的回复是否完全符合here 指定的格式?

我建议它可能不匹配,因为您的错误消息是

JSON 响应文本似乎不是标准响应格式

接下来要做什么?也许尝试将一些非常简单的对象转换为 JSON 以查看问题是否出在您的 Account 对象上?尝试在响应中仅使用一个 Account 对象?或者发布您的帐户对象代码?

【讨论】:

    【解决方案2】:

    通过定义一个简单的 java 对象(用作 Spring 控制器的返回类型)实现 Serializable 接口,并使用 Map 类型的名为“response”的变量并将 json 响应的内容作为键值配对添加到该映射并添加成功了。

    谢谢

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-05-07
      • 2015-01-14
      • 1970-01-01
      • 1970-01-01
      • 2019-01-13
      • 2014-01-21
      • 1970-01-01
      相关资源
      最近更新 更多