2012-12-24 15 views
10

W przypadku implementacji implementacji #equals dla UDT w Javie, jednym z warunków jest to, że przekazany obiekt argument musi być instancją bieżącej klasy, w przeciwnym razie będziemy działać bezbłędnie return false zobacz Effective Java (EJ2) . Jednak podczas korzystania z Hibernate 4 możemy skończyć z instancjami proxy javassist z powodu leniwego ładowania, gdzie ten warunek nie powiedzie się. Jaki byłby najlepszy wybór, aby przezwyciężyć to? Oto kilka opcji, które mogę wybrać:Serwery proxy hibernacji i `Obiekt # jest równy`

  • rozszerzyć implementację equals, aby uwzględnić przypadek proxy. Wady: opłata za utrzymanie, zależność hardwired od infrastruktury proxy Hibernacji, modele hacky, encje lub domeny powinny być agnostyczne w stosunku do ORM, tj. Ponieważ mogą być ponownie wykorzystane w różnych kontekstach, gdzie nie ma potrzeby ORM, np. Swing UI.
  • sprawdź, czy jest to proxy przed wywołaniem equals. Wady: nie zawsze jest możliwe, tj. Zajmowanie się kolekcjami i niejawnymi wywołaniami equals, np. Mapą.
  • Powstrzymaj się od używania leniwego ładowania. Wady: nierozsądne ani skuteczne we wszystkich przypadkach użycia.

UPDATE

Przegląd EJ2 znowu wierzę, że dalej będzie działać dla wszystkich scenariuszy (typu, typ-proxy, proxy-Type i Proxy-proxy), ale jak podkreślił w jednym z komentarzy poniżej może zapętlić się na zawsze, jeśli Typ zostanie porównany do zupełnie innego typu, np Person.equals(Employee) i oba używają tego samego kryterium EJ2.

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

tylko upewniając się, że serwer proxy rozszerzy klasę twojej jednostki? –

+0

instancje proxy nie rozszerzają się, zobacz 'InvocationHandler' i warunek' (this.getClass() == anObject.getClass()) ', oczywiście, oceni na false. –

+1

Porzuciłeś opcję: zignoruj ​​porady dotyczące efektywnej wersji Java i zezwól na podklasy w .equals(). –

Odpowiedz

9

Natknąłem się na ten sam problem. Sposób, w jaki naprawiłem, polegał na zmianie metody - .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; 

Sztuką jest nie porównać zajęcia się być takie same, ale użyć isAssignableFrom -method. Druga sztuczka polega na tym, aby nie używać właściwości bezpośrednich (other.id), ale użyć metody get (other.getId())

+0

getClass(). IsAssignableFrom (obj.getClass()) zawsze zwraca mi wartość false –

+0

Zrobiłem to dla mnie. Dla zainteresowanych: tutaj jak to przetestować: Pracownik employeeRef = em.getReference (Employee.class, id); Pracownik pracownika = em.find (Employee.class, id); Asser t.assertTrue (employee.equals (employeeRef)); –

+0

Otrzymuję błąd StackOverflow w pierwszej linii – pozuelog

1

Można zrobić dwie rzeczy: 1. Zmień równa korzystania instanceof zamiast równości klasowej. Typ proxy nie jest równy typowi jednostki, ale raczej rozszerza typ jednostki.

  1. Unwrap proxy, aby uzyskać samą jednostkę (istnieje kilka narzędzi hibernacji, który pomaga zrobić)
+0

Serwery proxy nie rozszerzają się, więc to nie zadziała – Nicktar

6

Nie mam reputacji, aby skomentować odpowiedź Willema de Wita. Następnie muszę opublikować nową odpowiedź.

Aby rozwiązać kwestię djechelon należy zastąpić ten wiersz:

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

dla

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

Wtedy zapewnić, że równe będzie działać dla wszystkich scenariuszy (Type-Type, typ -Proxy, Proxy-Type i Proxy-Proxy).

Nie mam reputacji, aby zagłosować także na twoją odpowiedź. Jestem taki nieszczęśliwy!

1

Odpowiedź przez DHansen powyżej jest blisko, ale dla mnie (przy użyciu hibernacji) to rozwiązało problem:

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

Również ważne jest, aby zawsze użycia „pozyskiwaniu” jak sugeruje Willem de Wit powyżej.

Powiązane problemy