-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 
Author Message
 Post subject: Hibernate and equals
PostPosted: Tue Mar 18, 2008 12:37 pm 
Newbie

Joined: Tue Mar 18, 2008 12:34 pm
Posts: 6
Hi all,
I'm unit testing some classes and I've faced some problems with equals and hibernate. I read the topic (http://forum.hibernate.org/viewtopic.ph ... &start=105) but didn't get it yet.

I have an artist class which has a List of biography class.

My equals method is pasted bellow:

Artist
Code:
public boolean equals( Object object )
{
   Artist artist = (Artist)object;
   return getName().equals( artist.getName() ) && getBiographies().equals( artist.getBiographies() );
}


Biography
Code:
public boolean equals( Object object )
{
   Biography bio = (Biography)object;
   return this.text.equals( bio.text );
}


Consider the following example. Given the objects:
Code:
Artist artist1 = new Artist( "Name" );
artist1.getBios().add( new Biography( "Biography" ) );

Artist artist2 = new Artist( "Name" );
artist2.getBios().add( new Biography( "Biography" ) );


The results are the following:
Code:
artist1.equals( artist2 ); // true, ok
artist2.equals( artist1 ); // true, ok


The problem is if I persist artist1 I have the following results:
Code:
MyDao.save( artist1 );
artist1.equals( artist2 ); // false, not ok.
artist2.equals( artist1 ); // true, ok


artist1 is equals artist2 considering my equals method, but my List<Biography>.equals returns false and Biography.equals is not even called.
It seems to me that it has something to do with hibernate proxy.

Any help is apreciated.
Code:
Code:


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 18, 2008 1:50 pm 
Newbie

Joined: Sun Jul 29, 2007 9:10 am
Posts: 8
Hi

First of all I suggest you change the implementation of you equals method to accomodate other cases like a null Object or an object of a different class. Otherwise you could run into some more weird errors. The equals/hashCode situation is pretty nicely described in Josh Bloch's Effective Java Programming and other related articles you can find across the internet. There's even an article on the Hibernate website providing various additional links.

Regarding your problem: The only reason for the equals method returning false I can imagine right now is that it is not initialized (the elements are lazy loaded) and therefore the general contract of java.util.Set.equals is not fulfilled. It states that both collections need to be of the same size. The wrapper class around java.util.Set provided by Hibernate, org.hibernate.collections.PersistentSet, provides an equals method that forwards to the standard implementation for stes but does NOT initialize the collection. Could this be your problem? Btw, did you use a debugger and take a look at the variables' values and types?

Cheers
Martin

EDIT: On the other hand I just realized that your comparison returns true the other way around. So maybe it's something else than what I guessed above ;)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 18, 2008 2:40 pm 
Newbie

Joined: Fri Feb 29, 2008 3:31 pm
Posts: 5
Location: USA
I think Martin is correct. The implementation of the equals() method in java.util.ArrayList could be different from the Hibernate's implementation of it.

I suspect that its checking for hashcode of the list's component objects. So your problem should be solved if you implement hashcode functions for Biography class.


and yes, while you are it go ahead and put in std equals and hashcode methods in all of your entity classes.

_________________
-- Renewing my interest in RDBMS-es. So please pardon any gaffes ;) --


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 18, 2008 3:45 pm 
Newbie

Joined: Sun Jul 29, 2007 9:10 am
Posts: 8
@ritesh:
The implementations of the equals() method in the Hibernate wrapper collections always forward to the wrapped collection which is always a standard Java collection. Thus, the only remarkable fact is that a call to equals() does not initialize the collection.

But, I just thought about something which "could" explain why the second test returns true. The second test passes the persistent object as the parameter to equals. The implementation of the equals() method in java.util.AbstractSet calls size() on and iterates over the passed-in collection, which is a persistent collection. Thus, its elements are initialized. That may be an explanation...

And as ritesh said, I'd try to implement hashCode(), too.

Cheers
Martin


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 18, 2008 7:02 pm 
Newbie

Joined: Fri Feb 29, 2008 3:31 pm
Posts: 5
Location: USA
@Martin
I don't quite understand. Please do explain if you got the time.

I am thinking that since the equals method of Artist calls getRespositry() explicitly, the lazy-initialization would be non issue as the collection would get populated.

So from what I understand, once the equals method of AbstractSet is entered, the size() comparison would return true, and each iteration for object comparison would also return true. So I think (and I guess u agree with me.. ) that it had to fail sometime before it iterated and compares each object.

thanks..

_________________
-- Renewing my interest in RDBMS-es. So please pardon any gaffes ;) --


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 19, 2008 4:50 am 
Newbie

Joined: Sun Jul 29, 2007 9:10 am
Posts: 8
ritesh, sure I'll try to explain. Take the above call

Code:
artist1.equals(artist2);


artist1 is a persistent object, i.e. the collection of Biographies (I'm guessing it's a java.util.Set) is wrapped by org.hibernate.collections.PersistentSet. So you basically call:

Code:
PersistentSet.equals(Set);


This is because artist2 is not yet persistent and is basically just a POJO. The equals() method of PersistentSet looks something like this:

Code:
public boolean equals(Object other) {
  initialize(false);
  return set.equals(other);
}


The variable 'set' in the above method is a reference to the underlying Set of the PersistentSet wrapper, that is, in our case propably a java.util.HashSet. We now call the equals() method on an empty HashSet (because the collection (the PersistentSet wrapper) hasn't initialized the underlying Set) and pass it the not yet persisted Set. So there should be a difference in size of both collections. The persisted one has got a size of 0 and the not yet persisted one has got a size of 1 in our case. Because the size() operation is performed on the wrapped element NOT the wrapper, no initialization takes place. I hope you're with me here ;)

The second test behaves a little bit different: You pass the PersistentSet to the equals() method of a Set. A call to size() on a PersistentSet intializes the collection and thus its size will also be 1. The test returns true.

Did you understand my reasoning? If not, just tell me. Well, I'm not 100% sure that this is the explanation for imp_galo's problem, but at least it could. Anyway, if I'm talking bulls**t here someone please tell me ;)

Cheers
Martin


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 6 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.