论坛首页 入门技术论坛

Hibernate Bean的Equals方法重载问题

浏览 15514 次
该帖已经被评为新手帖
作者 正文
   发表时间:2009-05-26   最后修改:2009-06-02
代码如下:
	
	/**
	 * 判断当前流程实例上下文中,是否存在Blocking(阻挡性)的任务
	 * 规则
	 * 1.任务未结束 
	 * 2.任务是必办理的
	 * 3.当前任务实例的token和执行上下文的token一致
	 * @param token
	 * @return
	 */
	public boolean hasBlockingTaskInstances(FlowToken token) {
		boolean hasBlockingTasks = false;

		System.out.println("LOC_1 :"  + token.getId());

		Set<TaskInstance> taskInstances = flowInstance.getTaskInstances();
		if (taskInstances!=null) {
			Iterator<TaskInstance> iter = taskInstances.iterator();
			
			while ( (iter.hasNext()) && (!hasBlockingTasks)) {

System.out.println("LOC_2 : "  + taskInstance.getFlowToken().getId());
System.out.println("LOC_3 : "  + token == taskInstance.getFlowToken());
System.out.println("LOC_4 : "  + token.equals(taskInstance.getFlowToken());

				TaskInstance taskInstance = (TaskInstance) iter.next();
				if ( (! taskInstance.hasEnded()) //任务未结束 
						&& (taskInstance.getIsBlocking()) //任务是必办理的
						&& (token!=null) 
						&& (token.equals(taskInstance.getFlowToken())) ) {
					hasBlockingTasks = true;
				}
			}
		}
		return hasBlockingTasks;
	}


上述的 LOC_1 处和 LOC_2 处打印的ID完全相等, LOC_3处输出true(说明对象地址相同),BUT~~ LOC_4处输出是false;


给出FlowToken的equals实现
	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof FlowToken))
			return false;
		final FlowToken other = (FlowToken) obj;
		if (id == null || other.id == null) {
			return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}


跟踪发现,实际进入equals的obj参数根本不是外面传入的那个token对象,中间过程被Hinernate的CGLIBLazyInitializer做了代理处理,发生了底层对象的变换。
开始大家都打死不信有这样的BUG,经过对jvm线程和变量编号的反复跟踪,BUG每次都重现。确认CGLIBLazyInitializer确有问题,但目前在国内互联网上没有找到相同的案例。这里提出,供javaeye上的大牛商讨!

如果我们一群人的诊断是对的,hibernate就隐藏了一个相当恐怖的bug咯!!!
   发表时间:2009-05-26  
补充一下,这样的bug为啥会发生,出现几率如何,目前完全是一抹黑。望各位共同关注
0 请登录后投票
   发表时间:2009-05-26  

equals不是hibernate的注意事项中说得很清楚,如果要用到,需要自己重载,否则就不要通过equals来判断是否equal了。
0 请登录后投票
   发表时间:2009-05-26  
LZ 用的是最新版本?
0 请登录后投票
   发表时间:2009-05-26  
麻烦把 import 部分发一下。
0 请登录后投票
   发表时间:2009-05-27  
严格来说,这个还没研究过!!
0 请登录后投票
   发表时间:2009-05-27  
jianfeng008cn 写道

equals不是hibernate的注意事项中说得很清楚,如果要用到,需要自己重载,否则就不要通过equals来判断是否equal了。

我上面的那段equals代码还不算重载嘛?应该是已经对bean的equals做了自己的实现了啊,请教一下啊!
0 请登录后投票
   发表时间:2009-05-27  
linliangyi2007 写道
代码如下:
	
	/**
	 * 判断当前流程实例上下文中,是否存在Blocking(阻挡性)的任务
	 * 规则
	 * 1.任务未结束 
	 * 2.任务是必办理的
	 * 3.当前任务实例的token和执行上下文的token一致
	 * @param token
	 * @return
	 */
	public boolean hasBlockingTaskInstances(FlowToken token) {
		boolean hasBlockingTasks = false;

		System.out.println("LOC_1 :"  + token.getId());

		Set<TaskInstance> taskInstances = flowInstance.getTaskInstances();
		if (taskInstances!=null) {
			Iterator<TaskInstance> iter = taskInstances.iterator();
			
			while ( (iter.hasNext()) && (!hasBlockingTasks)) {

System.out.println("LOC_2 : "  + taskInstance.getFlowToken().getId());
System.out.println("LOC_3 : "  + token == taskInstance.getFlowToken());
System.out.println("LOC_4 : "  + token.equals(taskInstance.getFlowToken());

				TaskInstance taskInstance = (TaskInstance) iter.next();
				if ( (! taskInstance.hasEnded()) //任务未结束 
						&& (taskInstance.getIsBlocking()) //任务是必办理的
						&& (token!=null) 
						&& (token.equals(taskInstance.getFlowToken())) ) {
					hasBlockingTasks = true;
				}
			}
		}
		return hasBlockingTasks;
	}


上述的 LOC_1 处和 LOC_2 处打印的ID完全相等, LOC_3处输出true(说明对象地址相同),BUT~~ LOC_4处输出是false;


给出FlowToken的equals实现
	/* (non-Javadoc)
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof FlowToken))
			return false;
		final FlowToken other = (FlowToken) obj;
		if (id == null || other.id == null) {
			return false;
		} else if (!id.equals(other.id))
			return false;
		return true;
	}


跟踪发现,实际进入equals的obj参数根本不是外面传入的那个token对象,中间过程被Hinernate的CGLIBLazyInitializer做了代理处理,发生了底层对象的变换。
开始大家都打死不信有这样的BUG,经过对jvm线程和变量编号的反复跟踪,BUG每次都重现。确认CGLIBLazyInitializer确有问题,但目前在国内互联网上没有找到相同的案例。这里提出,供javaeye上的大牛商讨!

如果我们一群人的诊断是对的,hibernate就隐藏了一个相当恐怖的bug咯!!!



session.load 这类方法本来就返回的Cglib代理你不会刚知道吧

来分析下equals
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
// 以上2条可以不用测试if (!(obj instanceof FlowToken))
return false;
// System.out.println(obj.getClass()) 正确返回Cglib代理 这条正确通过
final FlowToken other = (FlowToken) obj;
// 问题来了 other.id? 难道你用的public Integer id?
if (id == null || other.id == null) {
// 就是这条出错了
// 测试结果id=0

return false;
} else if (!id.equals(other.id))
return false;
return true;
}


原因分析:
当一个类实例传入到另一个同类型的类中可以直接调用他的private字段
p.setId(1);
public void setPeople(People p)
{
p.id=100;
System.out.println(p.id);
//输出100
System.out.println(p.getId());
//输出1
}
具体为什么我也从来没在什么地方看到过,希望了解的指点一下

所以other.id是问题的关键
other.getId()看看
0 请登录后投票
   发表时间:2009-05-27  
jianfeng008cn 写道
麻烦把 import 部分发一下。

import java.sql.Timestamp;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import com.shine.wfm.WfmConfiguration;
import com.shine.wfm.WfmContext;
import com.shine.wfm.db.AsynJobSession;
import com.shine.wfm.db.HibernateSessionFactory;
import com.shine.wfm.def.FlowDefine;
import com.shine.wfm.def.Node;
import com.shine.wfm.def.Transition;

/**
 * 流程执行令牌对象
 * 
 * @author 林良益
 * 2008-06-27
 * @version 1.0
 */
public class FlowToken implements java.io.Serializable {

0 请登录后投票
   发表时间:2009-05-27   最后修改:2009-05-27
jianfeng008cn 写道
麻烦把 import 部分发一下。



页面更新了没看到,和上面同学一样,我想说的是cgilb增强时正常现象,至于为什么不能equal,我也不知道。
0 请登录后投票
论坛首页 入门技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics