试图在网上找到答案但却失败了。对于专业的Spring Devs来说应该很简单......所以它来了:
简单地说,我想将接口类型List:List绑定到表单并获取数据(可能由用户通过表单修改。问题是它不起作用:(
我的代码(简短版本) - 传递给表单的命令/模型类:
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)
(...)
当我将List更改为“实例”列表时,一切正常!
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<IRoom>
(从服务返回)转换为List<Room>
,这似乎适合Spring。在这种情况下是否可以使用List<IRoom>
或Spring只是不支持它?
//当然Room实现了IRoom - 但我想你已经有了......
我会非常高兴获得任何帮助/建议!
最诚挚的问候, Nirwan
答案 0 :(得分:3)
我有完全相同的问题。更改为以下将无法解决问题。看起来spring绑定会忽略工厂的utils并尝试实例化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这样方便的嵌套路径。您必须确保用户,帐户,地址都不为空。它确实会导致很多问题。这就是我来到这里的原因,看看我是否能找到更好的解决方案。
答案 1 :(得分:1)
如果您实际上不需要列表自动增长,则可以将表单对象存储在会话中,以避免禁用自动增长嵌套路径的令人讨厌的副作用。
@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();
}
}
答案 2 :(得分:0)
请尝试以下行
@SuppressWarnings("unchecked")
private List<IRoom> roomsList = LazyList.decorate(new ArrayList<IRoom>(),
FactoryUtils.instantiateFactory(Room.class));
没有时间自己尝试,但这是有道理的。