Mryqu's Notes


  • 首页

  • 搜索
close

Spring REST can't solve nested object array generated by JavaScript

时间: 2015-01-15   |   分类: Service+JavaEE   Spring     |   阅读: 506 字 ~3分钟

最近遭遇SpringREST无法解析嵌套对象数组这么一个问题。为了排除客户端Javascript代码嫌疑,我通过GET操作从Spring RestfulWeb服务获取一个复杂对象,然后通过POST操作将其原封不动返给Spring Restful Web服务,问题依旧重现。

所操作的复杂对象

Spring REST can’t solve nested object array generated by JavaScript

客户端POST响应

Spring REST can’t solve nested object array generated by JavaScriptSpring REST can’t solve nested object array generated by JavaScript

中间层代码

package com.yqu.rest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import java.util.ArrayList;
import java.util.List;

@RestController
public class ConfigurationController {
  @RequestMapping(value = "/", method = RequestMethod.GET)
  public ModelAndView home(Model m){
    System.out.println("home");
    return new ModelAndView("index");
  }

  @RequestMapping(value = "/configure", method = RequestMethod.GET)
  public @ResponseBody
  SheetVO getConfiguration() {
    List columns = new ArrayList();
    columns.add(new ColumnVO("id","The Id",1));
    columns.add(new ColumnVO("name","The Name",2));
    columns.add(new ColumnVO("age","The Age",3));

    SheetVO metadata = new SheetVO(SheetVO.TITLE_MATCHING, 1,0, columns);
    System.out.println("getConfiguration:"+metadata);
    return metadata;
  }

  @RequestMapping(value = "/configure", method = RequestMethod.POST)
  public @ResponseBody
  SheetVO setConfiguration(@ModelAttribute("metadata") SheetVO metadata) {
    System.out.println(metadata);
    return metadata;
  }
}

中间层异常

org.springframework.beans.InvalidPropertyException: Invalid property 'columns[0][varIndex]' of bean class [com.yqu.rest.SheetVO]: Property referenced in indexed property path 'columns[0][varIndex]' is neither an array nor a List nor a Map; returned value was [1]
  at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:1058)
  at org.springframework.beans.BeanWrapperImpl.setPropertyValue(BeanWrapperImpl.java:927)
  at org.springframework.beans.AbstractPropertyAccessor.setPropertyValues(AbstractPropertyAccessor.java:95)
  at org.springframework.validation.DataBinder.applyPropertyValues(DataBinder.java:749)
  at org.springframework.validation.DataBinder.doBind(DataBinder.java:645)
  at org.springframework.web.bind.WebDataBinder.doBind(WebDataBinder.java:189)
  at org.springframework.web.bind.ServletRequestDataBinder.bind(ServletRequestDataBinder.java:106)
  at org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor.bindRequestParameters(ServletModelAttributeMethodProcessor.java:150)
  at org.springframework.web.method.annotation.ModelAttributeMethodProcessor.resolveArgument(ModelAttributeMethodProcessor.java:110)
  at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:77)
  at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:162)
  at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:129)
  at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
  at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
  at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
  at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
  at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
  at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
  at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
  at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:644)
  at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
  at javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:291)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  at org.springframework.boot.actuate.autoconfigure.EndpointWebMvcAutoConfiguration$ApplicationContextHeaderFilter.doFilterInternal(EndpointWebMvcAutoConfiguration.java:291)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  at org.springframework.boot.actuate.trace.WebRequestTraceFilter.doFilterInternal(WebRequestTraceFilter.java:102)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:85)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  at org.springframework.boot.actuate.autoconfigure.MetricFilterAutoConfiguration$MetricsFilter.doFilterInternal(MetricFilterAutoConfiguration.java:90)
  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:239)
  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:219)
  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:501)
  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:142)
  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:516)
  at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1086)
  at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:659)
  at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1558)
  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1515)
  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
  at java.lang.Thread.run(Thread.java:745)

问题原因

通过阅读两篇参考帖子,可知对于下列对象:

{ 
  "columnMatchMethod": 2,
  "ignoredHeaderCount": 1,
  "ignoredFooterCount": 0,
  "columns": [{
      "varName": "id",
      "varTitle": "The Id",
      "varIndex": 1
    }, {
      "varName": "name",
      "varTitle": "The Name",
      "varIndex": 2
    }, {
      "varName": "age",
      "varTitle": "The Age",
      "varIndex": 3
    }
  ]
}

JQuery是进行如下:

columnMatchMethod: 2,
ignoredHeaderCount: 1,
ignoredFooterCount: 0,
columns[0][varName]: "id",
columns[0][varTitle]: "The Id",
columns[0][varIndex]: 1
columns[1][varName]: "name",
columns[1][varTitle]: "The Name",
columns[1][varIndex]: 2
columns[2][varName]: "age",
columns[2][varTitle]: "The Age",
columns[2][varIndex]: 3

但是Spring MVC期望的是如下参数格式:

columnMatchMethod: 2,
ignoredHeaderCount: 1,
ignoredFooterCount: 0,
columns[0].varName: "id",
columns[0].varTitle: "The Id",
columns[0].varIndex: 1
columns[1].varName: "name",
columns[1].varTitle: "The Name",
columns[1].varIndex: 2
columns[2].varName: "age",
columns[2].varTitle: "The Age",
columns[2].varIndex: 3

解决方案

通过资料查找,采用参考帖子中的第二种方案解决问题。

  • 客户端代码:

    setConf = function (event) {
      $.ajax({
        url: "configure",
        type: "POST",
        data: JSON.stringify(metadata),
        dataType: "json",
        contentType: "application/json",
        success: function (res) {
          $('#cfgContent').text(JSON.stringify(res));
          $('#cfgError').text("");
        },
        error: function (res) {
          $('#cfgContent').text("");
          $('#cfgError').text(res.responseText);
        }
      });
    };
    
  • 中间层代码:

    package com.yqu.rest;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.http.HttpStatus;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.*;
    import org.springframework.web.servlet.ModelAndView;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @RestController
    public class ConfigurationController {
      @RequestMapping(value = "/", method = RequestMethod.GET)
      public ModelAndView home(Model m){
        System.out.println("home");
        return new ModelAndView("index");
      }
    
      @RequestMapping(value = "/configure", method = RequestMethod.GET)
      public @ResponseBody
      SheetVO getConfiguration() {
        List columns = new ArrayList();
        columns.add(new ColumnVO("id","The Id",1));
        columns.add(new ColumnVO("name","The Name",2));
        columns.add(new ColumnVO("age","The Age",3));
    
        SheetVO metadata = new SheetVO(SheetVO.TITLE_MATCHING, 1,0, columns);
        System.out.println("getConfiguration:"+metadata);
        return metadata;
      }
    
      @RequestMapping(value = "/configure", method = RequestMethod.POST)
      public @ResponseBody
      SheetVO setConfiguration(@RequestBody SheetVO metadata) {
        System.out.println(metadata);
        return metadata;
      }
    }
    

参考

Spring MVC 3: Property referenced in indexed property path is neither an array nor a List nor a Map
Post Nested Object to Spring MVC controller using JSON

标题:Spring REST can't solve nested object array generated by JavaScript
作者:mryqu
声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 3.0 CN 许可协议。转载请注明出处!

#spring# #rest# #javascript# #json# #解析#
Spring3 REST can't solve list of object generated by Javascript
[OpenUI5] 示例: open dialog which content is a form defined in another view
  • 文章目录
  • 站点概览

Programmer & Architect

662 日志
27 分类
1472 标签
GitHub Twitter FB Page
    • 所操作的复杂对象
    • 客户端POST响应
    • 中间层代码
    • 中间层异常
    • 问题原因
    • 解决方案
    • 参考
© 2009 - 2023 Mryqu's Notes
Powered by - Hugo v0.120.4
Theme by - NexT
0%