Hibernate javassist proxies和`Object#equals`

时间:2012-12-24 18:09:36

标签: java hibernate orm javassist

在Java中为UDT提供#equals实现时,其中一个条件是传递的参数对象必须是当前类的实例,否则我们会快速return falseEffective Java (EJ2)。但是,在使用Hibernate 4时,由于延迟加载,#equals条件将失败,因此我们最终可能会遇到javassist代理实例。什么是克服这个问题的最佳选择?我能想到的几个选择是:

  • 扩展equals实施以考虑代理案例。缺点:可维护性收费,对Hibernate代理基础设施的硬连线依赖,hacky,实体或域模型应该与所使用的ORM无关,即因为它们可能在不需要ORM的不同上下文中重用,例如Swing UI。
  • 在调用equals之前检查它是否是代理。缺点:并非总是可行,即处理equals的集合和隐式调用,例如Map。
  • 避免使用延迟加载。缺点:在所有用例中都不合理也没有效率。

更新

再次回顾EJ2我认为以下内容适用于所有场景(Type-Type,Type-Proxy,Proxy-Type和Proxy-Proxy),但正如下面的一条评论中指出的那样,它可能会永远循环比较完全不同的类型,例如Person.equals(Employee)并且两者都使用相同的等于EJ2标准。

    if (this.getClass() != anObject.getClass())
    {
        return anObject.equals(this);
    }

4 个答案:

答案 0 :(得分:11)

我偶然发现了同样的问题。我修复的方法是更改​​.equals - 方法。

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!getClass().isAssignableFrom(obj.getClass()))
        return false;
    AbstractEntity other = (AbstractEntity) obj;
    if (getId() == null) {
        if (other.getId() != null)
            return false;
    } else if (!getId().equals(other.getId()))
        return false;
    return true;

诀窍是不要将类比较为相同但使用isAssignableFrom - 方法。另一个技巧是不使用直接属性(other.id),但使用get方法(other.getId()

答案 1 :(得分:7)

我对Willem de Wit的回答不予置评。我需要发布一个新答案。

要解决djechelon的问题,你应该替换这一行:

if (!getClass().isAssignableFrom(obj.getClass()))

if ( !obj.getClass().isAssignableFrom(getClass()) && !getClass().isAssignableFrom(obj.getClass()) )

然后,您将确保equals适用于所有场景(Type-Type,Type-Proxy,Proxy-Type和Proxy-Proxy)。

我也没有声誉来表达你的答案。我太悲惨了!

答案 2 :(得分:1)

你可以做两件事: 1.将equals更改为使用instanceof而不是类相等。代理的类型不等于实体的类型,而是扩展实体的类型。

  1. 解包代理以获取实体本身(有几种hibernate工具可以帮助您实现这一点)

答案 3 :(得分:1)

上面的DHansen的答案很接近,但对我来说(使用Hibernate)这解决了这个问题:

if (!Hibernate.getClass(this).equals(Hibernate.getClass(obj))) { return false; } 正如Dr. Hans-Peter Störr

所建议的那样

同样重要的是始终使用上面Willem de Wit建议的'getters'。