在Spring MVC中使用泛型键入命令对象的擦除

时间:2012-05-30 15:44:09

标签: hibernate generics spring-mvc

在使用Hibernate 4.1的Spring 3.1 MVC应用程序中,场景是:

  • 网页显示记录列表,用户可以使用复选框
  • 选择记录
  • 在POST上,所选记录将被删除

由于此功能也出现在其他地方,我想使用泛型以避免复制类似的代码。

逻辑是:

  • 在GET上,我使用泛型填充列表,该泛型包含hibernate对象和布尔值,我将该列表添加到模型中
  • 在POST上,我从模型中获取该列表,并将其传递给服务以删除所选记录

代码是:

/* list item */
public class SelectionListItem<T> {

    /* holds the hibernate object */
    private T item;
    /* whether the record is selected */
    private boolean selected;

    public SelectionListItem() {

    }

    public SelectionListItem(T item, boolean selected) {
        this.item = item;
        this.selected = selected;
    }

    public T getItem() {
        return item;
    }

    public void setItem(T item) {
        this.item = item;
    }

    public boolean isSelected() {
        return selected;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
    }
}

/* list that holds the records */
public class SelectionList<T> {

    private List<SelectionListItem<T>> list = new ArrayList<SelectionListItem<T>>();

    public SelectionList() {

    }

    public List<SelectionListItem<T>> getList() {
        return list;
    }

    public void setList(List<SelectionListItem<T>> list) {
        this.list = list;
    }
}


/* Controller for GET */
@RequestMapping(value = "/xxx", method = RequestMethod.GET)
public String functionGET(Model model) {
    // Retrieve data from database and prepare the list
    SelectionList<MyDomainObject> selectionList = someService.getRecordsAndPrepareList();

    // Add command object to model
    model.addAttribute("selectionListCommand", selectionList);


    return "xxx";
}

/* Service that retrieves the records and prepares the list */
public SelectionList<MyDomainObject> getRecordsAndPrepareList() {
    List<MyDomainObject> result = sessionFactory.getCurrentSession().createCriteria(MyDomainObject.class).list();

    SelectionList<MyDomainObject> selectionList = new SelectionList<MyDomainObject>();
    for (MyDomainObject item : result) {
        SelectionListItem<MyDomainObject> e = new SelectionListItem<MyDomainObject>(item, false);
        selectionList.getList().add(e);
    }

    return selectionList;
}

/* Controller for POST */
@RequestMapping(value = "/xxx", method = RequestMethod.POST)
public String functionPOST(
    @ModelAttribute("selectionListCommand") SelectionList<MyDomainObject> selectionListCommand,
    BindingResult result, Model model) {

    // Delete record
    someService.deleteSelectedRecords(selectionListCommand);


    return "xxx;
}

/* Service that deletes the selected records*/
public void deleteSelectedRecords(SelectionList<MyDomainObject> selectionList) {
    for (SelectionListItem<MyDomainObject> item : selectionList.getList()) {
        if (item.isSelected()) {
            sessionFactory.getCurrentSession().delete(item.getItem());
        }
    }
}

在GET请求时,SelectionList被正确填充,“T item”的类型为“MyDomainObject”。

在POST时,“T item”的类型为“java.lang.Object”,当执行“sessionFactory.getCurrentSession()。delete(item.getItem())”时,我得到“org.hibernate”。 MappingException:未知实体:java.lang.Object“

有人可以解释导致它的原因以及解决方法吗?

提前谢谢。

2 个答案:

答案 0 :(得分:0)

Hibernate做“一些神奇的事情”,并经常使用反射来访问变量并确定类型。这些类型对于Hibernate决定使用哪个映射非常重要。

在get请求中,您提供了MyDomainObject.class正确的类。这似乎足以让Hibernate找到映射。

发布请求不是这种情况。声明delete(item.getItem())中的Hibernate只获取信息getItem()返回一个对象(由于类型擦除而导致类型T被删除,而Hibernate不可用)。信息“对象”不允许Hibernate查找item的映射。

您可以尝试投放像delete((MyDomainObject)item.getItem())这样的项目,或者先将其放入一个输入良好的变量中

   MyDomainObject mdoItem = item.getItem();
   sessionFactory.getCurrentSession().delete(mdoItem);

(我不确定这两种可能性中哪一种可行。)

答案 1 :(得分:0)

正如我所提到的,问题是在POST时返回了@ModelAttribute(“selectionListCommand”)。

解决方案是:

  • 添加到控制器 - &gt;的 @SessionAttributes( “selectionListCommand”)
  • 将类SelectionList修改为 - &gt; 公共类SelectionList实现java.io.Serializable

我希望将来可以节省别人的时间。