-->
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.  [ 8 posts ] 
Author Message
 Post subject: Many-to-Many Set and the Set.contains() Method
PostPosted: Thu Jan 06, 2005 7:13 pm 
Regular
Regular

Joined: Sun Sep 26, 2004 9:27 pm
Posts: 75
Location: Atlanta, GA, USA
Hibernate version: 2.1.6

Forgive me, but I can't find the manual reference regarding a problem I'm having.

I have a Many-to-Many association between a User object and one or more Group objects to which they may belong. The mapping is set up correctly, groups many be assigned and saved, and when the User is loaded, their Set of Groups is correctly populated.

However, the contains() method is failing to find Groups within the Set. The method User.isInGroup(String pGroupName) does the following:

Code:
Group group = new Group() ;
group.setName(pGroupName) ;
return this.mGroups.contains(pGroupName) ;


I have also redefined the Group.equals() method to consider two Groups equal if the name is equal. As defined in the Set interface, the contains() method:

Quote:
Returns true if this set contains the specified element. More formally, returns true if and only if this set contains an element e such that (o==null ? e==null : o.equals(e)).


From debug statements, I can see all the previous is true.

Furthermore, I've looked at the net.sf.hibernate.collection.Set object used by Hibernate, and it doesn't do anything funky with the contains() method.

Finally, to quote the Hibernate Advanced FAQ, http://www.hibernate.org/117.html

Quote:
What column should I map the <index> tag of an array or List to?
You need a seperate table column holding the array or List index (the i in foo[i])! If your relational model doesn't have an index column, use a Set instead. This seems to put people off who assume that List should just be a more convenient way of accessing an unordered collection. Hibernate collections strictly obey the actual semantics attached to the Set, List and Map interfaces.


So why doesn't my contains() method find the Group?

Thanks for any help or insight.

Lukas


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 06, 2005 7:17 pm 
Regular
Regular

Joined: Sun Sep 26, 2004 9:27 pm
Posts: 75
Location: Atlanta, GA, USA
One more point: the equals() method is never invoked on my Group object! The first debug statement is never shown.

Code:

   /**
    * <p>Compares the given object to this Group.  The two are equal if the given object is non-null, this object's
    * mName is non-null, and
    * <ul>
    *    <ol>The given object is a Group, and the String mName is equal to this Group's mName, or</ol>
    *    <ol>The given object is a String, and it equals this object's String mName.</ol>
    * </ul>
    *
    * <p>Comparing both Group and String objects allows for quick security checks within the Set.contains() methods.</p>
    *
    * @see java.lang.Object#equals(java.lang.Object)
    */
   public boolean equals(Object pArg0)
   {
      Logger.getLogger(Group.class).debug("equals() received " + pArg0 + " on name " + mName) ;
      // Return early if the given object is null, or this object's String mKey is null
      if (mName == null || pArg0 == null)
         return false ;
      
      boolean isEqual = false ;
      if (pArg0 instanceof Group)
      {
         Group group = (Group) pArg0 ;
         // If the names are equal, the groups are equal
         isEqual = mName.equals(group.getName()) ;
      }
      else if (pArg0 instanceof String)
      {
         isEqual = mName.equals(pArg0.toString()) ;
      }
      return isEqual ;
   } // public boolean equals(Object pArg0)


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 06, 2005 7:23 pm 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
Check your hashCode implementation - read http://www.hibernate.org/109.html also the linked background material


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 07, 2005 10:51 am 
Regular
Regular

Joined: Sun Sep 26, 2004 9:27 pm
Posts: 75
Location: Atlanta, GA, USA
Thank you for the response, Michael. I knew this page existed, I just didn't know where.

I understand why the equals() method is necessary to over-ride, and I anticipated this in my implementation. However, I do not understand why the hashCode() implementation will fix my particular problem.

As the Set.contains() implementation does not use operator comparison (==), a hashCode() definition should be unnecssary.

Comments?

Lukas


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 07, 2005 11:06 am 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
Please read all the background material on the page I posted, learn about the equals/hashCode contract and how a HashSet works.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 07, 2005 12:01 pm 
Regular
Regular

Joined: Sun Sep 26, 2004 9:27 pm
Posts: 75
Location: Atlanta, GA, USA
I sincerely appreciate your response, but I have already read those documents. I understand completely the need for hashcode() and equals() implementations, as well as the need for them to follow the contracts laid out in Java.

I've even tried to read the tens of posts in this comprehensive thread, in which you were involved.
http://forum.hibernate.org/viewtopic.php?t=928172

However, I believe the main problem is an omission in the Java documentation regarding the HashSet.contains() method. Apparently, hashcode() is also compared before equals() on the objects. If this were not the case, the equals() method could be over-ridden for simple objects, and it would function as documented. However, this is not the case.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 07, 2005 12:08 pm 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
But it's well documented that if you override equals, you have to override hashCode too for things to work properly. So just implement hashCode correctly, too.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jan 07, 2005 12:32 pm 
Regular
Regular

Joined: Sun Sep 26, 2004 9:27 pm
Posts: 75
Location: Atlanta, GA, USA
Touche.

From Object.equals() docs:

Quote:
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.


I took generally necessary to not be so absolute.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 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.