Spring MVC Form:抽象类列表的数据绑定

我inheritance了一些我需要添加function的代码,它涉及一个基于Spring和Spring Form构建的程序,带有一个列表和绑定的抽象元素

所以我们有一个像下面这样的抽象类

public abstract class A { private int id; private String name; private int type; ....getters and setters below } 

还有一些实现如

 public class AImplOne extends A { private String text; ...getters, setters etc } public class AImplTwo extends A { private int mediaID; ...getters, setters etc } 

所以AImpl类实现了A,但是根据实现类型有一个额外的信息。

然后我们有一个B类,它包含A对象列表,其中包含A实现的列表(可以是不同实现类型的混合列表)

 public class B { private List aList; public B() { aList = new ArrayList(); } ..getters and setters, etc } 

现在我们有一个在Spring中构建的表单,用于创建B对象,包括进入aList的A的实现。 以下JSP代码位于具有loopStatus值$ {index}的循环内。 这也是通过具有A类的Controller加载的

以下JSP代码位于循环中,用于为表单创建输入:

 

第一次迭代将为AImplOne对象设置数据

 

然后在下一次迭代中,我们为类AImplTwo类型设置数据

     

所以我遇到的问题是加载这个JSP失败并抛出错误

 Caused by: org.springframework.beans.InvalidPropertyException: Invalid property 'aList[0]' of bean class [B]: Illegal attempt to get property 'aList' threw exception; nested exception is org.springframework.beans.NullValueInNestedPathException: Invalid property 'aList' of bean class [B]: Could not instantiate property type [A] to auto-grow nested property path: java.lang.InstantiationException 

这是完全可以理解的,因为aList具有抽象类A的元素,因此它无法实例化该类A.但是,根据输入我可以确定一个是AImplOne而另一个是AImplTwo

我正在努力做的,本质上是实现可以覆盖Springs默认表单绑定的function,以便能够正确初始化正确的实现并能够动态生成此aList以具有[AImplOne,AImpleTwo],因为它是内容。

是否有一个解析器类或类似的东西,我可以实现为程序提供此自定义function(读取数据并实例化正确的对象)

我正在努力做的,本质上是实现可以覆盖Springs默认表单绑定的function,以便能够正确初始化正确的实现并能够动态生成此aList以具有[AImplOne,AImpleTwo],因为它是内容。

您可以在控制器类中使用自定义init binder方法执行此操作:

 // Additionally using name of object used with @ModelAttribute // as "value" parameter of this annotation is not working in some cases @InitBinder public void initBinder( WebDataBinder webDataBinder, HttpServletRequest httpServletRequest) { // You only want to init this when form is submitted if (!"POST".equalsIgnoreCase(httpServletRequest.getMethod()) { return; } // Filter out all request when we have nothing to do Object nonCastedTarget = webDataBinder.getTarget(); if (nonCastedTarget == null || !(nonCastedTarget instanceof B)) { return; } // TODO: Better cache this in static final field instead Pattern pattern = Pattern.compile("aList\\[(\\d+)]\\.type"); Map types = new HashMap<>(); Enumeration parameterNames = httpServletRequest.getParameterNames(); while (parameterNames.hasMoreElements()) { String element = parameterNames.nextElement(); Matcher matcher = pattern.matcher(element); if (!matcher.matches()) { continue; } types.put( Integer.parseInt(matcher.group(1)), httpServletRequest.getParameter(element) ); } B target = (B) nonCastedTarget; List aList = target.getAList(); if (aList == null) { target.setAList(new ArrayList<>()); } types.keySet().stream().sorted().forEach(key -> { switch (types.get(key)) { case "Type1": target.getAList().add(new AImplOne()); break; case "Type2": target.getAList().add(new AImplTwo()); break; default: throw new IllegalStateException("Unknown type: " + key); } }); } 

上面的代码只是一个简单的工作版本,例如几乎没有实现error handling,没有提取常量 – 所以你必须改进它以使其更加生产就绪。