August 8th, 2008使用seam时,注意实体的equals方法
当你用jsf的<h:selectOneMenu />之类的控件选择实体时,小心你的实体的equals方法,否则你可能就会遇到”value is not valid”的验证错误。比如,如果你的页面里有这样一段:
<h:selectOneMenu value="#{fooAction.foo}"> <s:selectItems value="#{fooList.resultList}" var="foo" label="#{foo.name}"/> <s:convertEntity /> </h:selectOneMenu>
你的Foo实体类的equals方法又是这样写的:
public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; final Foo other = (Area) obj; if (id == null) { if (other.id != null) return false; } else if (!id.equals(other.id)) return false; return true; }
很好,你很可能就有机会遭遇seam下这个神奇的value is not valid验证问题了。到底原因何在?原因就在于seam不仅使用了jsf还使用了hibernate,而你的equals方法没有考虑到被对比的双方可 能一个是实体类,另一个可能是被hibernate动态增强过的类。JSF在客户端提交表单后,会验证客户端选中的元素是否是当初服务端给他的那些元素。 所以,JSF会拿经converter得到的实体与当初的集合里的实体一一调用equals方法对比,如果找不到一个在集合中的实体与提交来的一样,就报 错。如果集合里的对象是hibernate 延迟加载时的一个stub,那正常的对象和这个stub对比时就可能出错。对于上面的例子,getClass() != obj.getClass() 会为真,而 other.id != null 也可能为真。怎么办?改写equals方法,如下:
public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!getClass().isAssignableFrom(obj.getClass())) return false; final Area other = (Area) obj; if (id == null) { if (other.getId() != null) return false; } else if (!id.equals(other.getId())) return false; return true; }
isAssignableFrom方法对子类调用时一样为真。other.getId()时,则会初始化stub,取出id的值。
还有一种更简单的方法,那就是不要让用户选择实体,而是选择实体的id,那就没这个问题了。
October 10th, 2008 at 13:04
我一直用的都不是让用户选择实体,而是选择实体的id,但记忆中已经也报过这种错误,好像是在登陆的时候,而不是在h:selectOneMenu的时候
[回复]