Проживающие в прокси Hibernate прокси и `Object#equals`

При предоставлении #equals Для реализации UDT в Java одним из условий является то, что переданный аргумент должен быть экземпляром текущего класса, в противном случае мы перестанем работать return false см. Эффективная Java (EJ2). Однако, при использовании Hibernate 4 мы можем получить экземпляры прокси-сервера javassist из-за отложенной загрузки, где это #equals условие не выполнится. Что будет лучшим выбором для преодоления этого? Несколько вариантов, которые я могу придумать:

  • продлить equals Реализация принять во внимание случай прокси. Минусы: стоимость сопровождения, аппаратная зависимость от прокси-инфраструктуры Hibernate, хакерские модели, модели сущностей или доменов должны быть независимыми от используемого ORM, т. Е. Поскольку они могут быть повторно использованы в различных контекстах, где нет необходимости в ORM, например, в Swing UI.
  • проверьте, является ли это прокси, прежде чем вызывать equals, Минусы: не всегда возможно, т.е. иметь дело с коллекциями и неявными вызовами equalsНапример, карта.
  • Воздержитесь от использования отложенной загрузки. Минусы: не разумно и не эффективно во всех случаях использования.

ОБНОВИТЬ

Повторно рассматривая EJ2, я считаю, что следующее будет работать для всех сценариев (Type-Type, Type-Proxy, Proxy-Type и Proxy-Proxy), но, как указано в одном из комментариев ниже, оно может зацикливаться вечно, если сравнивать Type с совершенно другой тип, например Person.equals(Employee) и оба используют одинаковые критерии равных EJ2.

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

4 ответа

Решение

Я наткнулся на ту же проблему. То, как я исправил это изменить .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), но используйте метод ge t (other.getId())

У меня нет репутации, чтобы комментировать ответ Виллема де Вит. Чем мне нужно опубликовать новый ответ.

Чтобы решить проблему djechelon, вы должны заменить эту строку:

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

за

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

Затем вы убедитесь, что функции equals будут работать для всех сценариев (Type-Type, Type-Proxy, Proxy-Type и Proxy-Proxy).

У меня нет репутации, чтобы голосовать за твой ответ тоже. Я так несчастен!

Ответ DHansen выше близок, но для меня (с помощью Hibernate) это решило проблему:

if (!Hibernate.getClass(this).equals(Hibernate.getClass(obj))) { return false; } по предложению доктора Ханса-Петера Штерра

Также важно всегда использовать "добытчики", как предложено Виллемом де Витом выше.

Вы можете сделать две вещи: 1. Измените equals, чтобы использовать instanceof вместо равенства классов. Тип прокси-сервера не равен типу объекта, а расширяет тип объекта.

  1. Разверните прокси, чтобы получить саму сущность (есть несколько инструментов гибернации, которые помогут вам сделать это)
Другие вопросы по тегам