2016-06-15 42 views
3

列表结合我继承了一些代码,我需要添加功能,它涉及建立在春天和一个列表Spring表单和有约束力的抽象元素Spring MVC的形式:数据抽象类

所以程序我们有像下面

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 
} 

一个抽象类,所以的AIMP1类实现A,但有一个额外的资料片的电子商务依赖于实现类型。

然后我们有一个具有包含了一个实现列表的对象列表(可以混合不同的实现类型的列表)

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

现在我们有一个形式内置在Spring作为B类以下用于创建B对象,包括进入aList的A的实现。以下JSP代码位于具有loopStatus值$ {index}的循环中。这也通过控制器,其具有类加载的

下面的JSP代码是在该表单创建输入的循环:

<form:form method="POST" modelAttribute="B"> 
</form:form> 

第一次迭代将要AImplOne对象

设定数据
<form:input type="hidden" path="aList[${index}].id" value="0" /> 
<form:input type="hidden" path="aList[${index}].type" value="Type1" />  
<form:input type="hidden" path="aList[${index}].name" value="X" /> 
<form:input type="hidden" path="aList[${index}].text" value="aaaa" /> 

然后在接下来的迭代,我们设定的数据一类AImplTwo型

<form:input type="hidden" path="aList[${index}].id" value="0" /> 
<form:input type="hidden" path="aList[${index}].type" value="Type2" />  
<form:input type="hidden" path="aList[${index}].name" value="X" /> 
<form:input type="hidden" path="aList[${index}].mediaID" value="12" /> 

所以我碰到的问题是,加载该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的元素,因此它无法实例化类。然而,基于输入,我可以确定一个是AImplOne,另一个是AImplTwo

我想要做的,实质上是实现可以覆盖弹簧默认表单绑定的功能,以便能够正确初始化正确的实现,并能够动态地生成这个aList,因为它的内容是[AImplOne,AImpleTwo]。

是否有一个解析器类或沿东西,我可以实现为程序(读出的数据和实例化正确的对象)提供这种定制功能的那些行

回答

0

我试图能够实质上是实现 功能,可以覆盖弹簧默认表单绑定这个 能够正确地初始化正确的实现,并且是 能够动态地生成这个aList,因为它的内容有[AImplOne,AImpleTwo] 。

为此,您可以使用自定义的init方法粘合剂在你的控制器类:

// 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<Integer, String> types = new HashMap<>(); 
    Enumeration<String> 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<A> 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); 
     } 
    }); 
} 

上面的代码只是一个简单的工作版本,例如几乎不会执行错误处理,也不会提取常量 - 因此您必须对其进行改进以使其更符合生产要求。