在完成一個功能的時候遇到一個問題:
在使用h:selectOneMenu時即使已經加了<s:convertEntity>仍然報錯:value is not valide.
后來google了一下,seam 的論壇上幾個帖子分析的原因都是因為實體的equal方法的問題,然后在一篇國內的搏客上看到了一個解決方法:
作者
sulong 分類:
java,
程序
當你用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,那就沒這個問題了。
原文地址:http://www.sulong.info/archives/104
我嘗試了選擇id 的方法,但是總是報錯: identifier of an instance of xx was altered from xx to xx.
等過幾天再解決一下。
另:如果實體中有需要延遲加載的屬性,也可能會報這個錯誤。
http://www.jboss.org/index.html?module=bb&op=viewtopic&p=4127804