【问题标题】:Spring List of interface type data binding - how?接口类型数据绑定的Spring List - 如何?
【发布时间】:2012-02-16 09:13:58
【问题描述】:

试图在网上找到答案,但失败了。对于专业的 Spring 开发人员来说应该很简单......所以它来了:

简而言之,我想将接口类型列表绑定:列表到表单并取回数据(可能由用户通过表单修改。问题是它不起作用:(

我的代码(短版) - 传递给表单的命令/模型类:

public class RoomsFormSearchResultCommand extends RoomsFormSearchCommand {
    @SuppressWarnings("unchecked")
    private List<IRoom> roomsList = LazyList.decorate(new ArrayList<Room>(),
            FactoryUtils.instantiateFactory(Room.class));

    public List<IRoom> getRoomsList() {
        return roomsList;
    }

    public void setRoomsList(final List<IRoom> roomsList) {
        this.roomsList = roomsList;
    }

(...)

然后以我使用它的形式(短版):

    <form:form method="post" action="reserve" commandName="roomsResultsCmd">
(...)
    <c:forEach var="room" items="${roomsResultsCmd.roomsList}"
                varStatus="status">
                <tr>
                    <td><form:input path="roomsList[${status.index}].roomNumber" readonly="true"/>
(...)

表单显示正常,但提交后我得到:

2012-01-22 21:31:55 org.apache.catalina.core.StandardWrapperValve invoke
SEVERE: Servlet.service() for servlet [wyspa] in context with path [/wyspa] threw exception [Request processing failed; nested exception is org.springframework.beans.InvalidPropertyException: Invalid property 'roomsList[0]' of bean class [com.wyspa.controller.command.RoomsFormSearchResultCommand]: Illegal attempt to get property 'roomsList' threw exception; nested exception is org.springframework.beans.NullValueInNestedPathException: Invalid property 'roomsList' of bean class [com.wyspa.controller.command.RoomsFormSearchResultCommand]: Could not instantiate property type [com.wyspa.entity.IRoom] to auto-grow nested property path: java.lang.InstantiationException: com.wyspa.entity.IRoom] with root cause
org.springframework.beans.NullValueInNestedPathException: Invalid property 'roomsList' of bean class [com.wyspa.controller.command.RoomsFormSearchResultCommand]: Could not instantiate property type [com.wyspa.entity.IRoom] to auto-grow nested property path: java.lang.InstantiationException: com.wyspa.entity.IRoom
    at org.springframework.beans.BeanWrapperImpl.newValue(BeanWrapperImpl.java:633)
    at org.springframework.beans.BeanWrapperImpl.growCollectionIfNecessary(BeanWrapperImpl.java:863)
    at org.springframework.beans.BeanWrapperImpl.getPropertyValue(BeanWrapperImpl.java:770)
    at org.springframework.beans.BeanWrapperImpl.getNestedBeanWrapper(BeanWrapperImpl.java:555)

(...)

然后,当我将列表更改为“实例”列表时,一切正常!

public class RoomsFormSearchResultCommand extends RoomsFormSearchCommand {
    @SuppressWarnings("unchecked")
//notice that the List is now List<Room>
    private List<Room> roomsList = LazyList.decorate(new ArrayList<Room>(),
            FactoryUtils.instantiateFactory(Room.class));

在这种情况下,数据以正确的方式传递给控制器​​。

由于我习惯于在接口上进行开发并且对此非常着迷,我真的不希望将List&lt;IRoom&gt;(从服务返回)翻译成似乎适合 Spring 的List&lt;Room&gt;。在这种情况下是否可以使用 List&lt;IRoom&gt; 或者 Spring 不支持它?

//Room当然实现了IRoom——但我猜你已经明白了……

如果有任何帮助/建议,我将非常高兴!

最好的问候, 尼尔万

【问题讨论】:

    标签: forms spring data-binding binding spring-mvc


    【解决方案1】:

    试试下面几行

    @SuppressWarnings("unchecked")
    private List<IRoom> roomsList = LazyList.decorate(new ArrayList<IRoom>(),
        FactoryUtils.instantiateFactory(Room.class));
    

    我自己没有时间尝试,但它会很有意义。

    【讨论】:

      【解决方案2】:

      我有完全相同的问题。更改为关注不会解决问题。看起来 spring 绑定忽略了工厂工具并尝试实例化 null 对象本身:

      @SuppressWarnings("unchecked")
      private List<IRoom> roomsList = LazyList.decorate(new ArrayList<IRoom>(),
          FactoryUtils.instantiateFactory(Room.class));
      

      解决方法是在控制器中关闭自动增长嵌套路径:

      @InitBinder protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) {
          binder.setAutoGrowNestedPaths(false);
          super.initBinder(request, binder);
       }
      

      问题是您会丢失方便的嵌套路径,例如 user.account.address.street。您必须确保用户、帐户、地址都不为空。它确实会引起很多问题。这就是我来这里的原因,看看我是否能找到更好的解决方案。

      【讨论】:

        【解决方案3】:

        如果您实际上不需要列表自动增长,则可以将表单对象存储在会话中,以避免禁用自动增长嵌套路径的不良副作用。

        @Controller
        @SessionAttributes(types = RoomsFormSearchResultCommand.class)
        public final class SearchController {
        
            @InitBinder
            protected void initBinder(final WebDataBinder binder) {
                    binder.setAutoGrowNestedPaths(false);
            }
        
            @RequestMapping(method = RequestMethod.GET)
            public String showForm(final Model model) {
                    RoomsFormSearchResultCommand form = ... // create or load form
                    model.addAttribute(form); 
            }
        
            @RequestMapping(method = RequestMethod.POST)
            public String onSubmitUpdateCart(
                            @ModelAttribute final RoomsFormSearchResultCommand form,
                            final BindingResult result,
                            final SessionStatus status) {
                    // if result has no errors, just set status to complete
                    status.setComplete();
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2013-02-08
          • 1970-01-01
          • 2023-03-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-09
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多