-->
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.  [ 14 posts ] 
Author Message
 Post subject: Can't get PersistentSet.remove to work correctly
PostPosted: Tue Oct 03, 2006 9:55 am 
Newbie

Joined: Sat Sep 13, 2003 12:45 am
Posts: 12
Location: Rochester, NY
I have been tracking down a bug in an application and have found the cause to be the remove method on a hibernate created PersistentSet is not working as I would expect it to. I am calling a method to remove a passed in object from a HashSet (which is turned into a PersistenSet by Hibernate). The remove method is not removing the object from the collection, it returns false. I added some debugging code which is attached below. Iterating through the collection shows there is exactly one object in the collection that is equal() to the passed in object. The hash code of the passed in object is the same as the one for the object in the collection that is "equal" to the parameter. Yet the remove() method returns false and does not remove the object from the collection. The object being passed in has its equals and hashcode methods overidden using a method suggested in a posting in the Equals and Hashcode article in the Community Area. If I remove the equals and hashcode methods from the object the remove method works. So it seems likely that there is an issue with my overridden methods, but I can't for the life of me figure out what. I am running version 3.0.5 but have also tried it with 3.1.3 with the same results.

The code in question

Code:
  private Set _picOptions = new HashSet();

  public void removePicOptionFromChart(PicOption picOption) {

    System.out.println("paramater");
    System.out.println("HashCode = " + picOption.hashCode() + " " + " Id = "
        + picOption.getOptionId());
    System.out.println(" ");
   
    System.out.println("Collection");
    for (Iterator it = _picOptions.iterator(); it.hasNext();) {
      PicOption option = (PicOption) it.next();
      System.out.println("Equals = " + option.equals(picOption)
          + " HashCode = " + option.hashCode() + " Id = "
          + option.getOptionId());
    }
    System.out.println(" ");
   
    System.out.println("remove result");
    System.out.println(_picOptions.remove(picOption))


The output from the above

Code:
paramater
HashCode = 33879  Id = 33879

Collection
Equals = false HashCode = 33878 Id = 33878
Equals = false HashCode = 33874 Id = 33874
Equals = false HashCode = 33872 Id = 33872
Equals = false HashCode = 33877 Id = 33877
Equals = false HashCode = 33876 Id = 33876
Equals = false HashCode = 33873 Id = 33873
Equals = true HashCode = 33879 Id = 33879
Equals = false HashCode = 33880 Id = 33880
Equals = false HashCode = 33875 Id = 33875

remove result
false

_________________
Jim


Top
 Profile  
 
 Post subject: Re: Can't get PersistentSet.remove to work correctly
PostPosted: Tue Oct 03, 2006 10:57 pm 
Newbie

Joined: Thu Jul 06, 2006 8:38 am
Posts: 14
jcurry wrote:
If I remove the equals and hashcode methods from the object the remove method works. So it seems likely that there is an issue with my overridden methods, but I can't for the life of me figure out what.


Can you paste the two methods then?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Feb 16, 2007 7:30 pm 
Newbie

Joined: Fri Feb 16, 2007 7:29 pm
Posts: 1
I solved this - take the generator tag out of your hibernate configuration file.


Top
 Profile  
 
 Post subject: Set.contains doesn't work...
PostPosted: Sun Feb 18, 2007 8:19 am 
Beginner
Beginner

Joined: Tue Oct 18, 2005 3:44 am
Posts: 27
Same problem as explained by jcurry. Set.remove and Set.contains doesn't work.
When we make a new java.util.HashSet with the org.hibernate.collections.PersistentSet, and then use hashSet.contains, it works well.
I can post the code but it is similary to this of jcurry : when syso of the hashcode and id element to remove is in the syso of hashcode and id of one element of the collection.
I don't understand the solution of the last post : I need the generator, why do I have to remove hem?
Thx
Cathy


Top
 Profile  
 
 Post subject: Set.contains doesn't work...
PostPosted: Sun Feb 18, 2007 8:20 am 
Beginner
Beginner

Joined: Tue Oct 18, 2005 3:44 am
Posts: 27
Same problem as explained by jcurry. Set.remove and Set.contains doesn't work.
When we make a new java.util.HashSet with the org.hibernate.collections.PersistentSet, and then use hashSet.contains, it works well.
I can post the code but it is similary to this of jcurry : when syso of the hashcode and id element to remove is in the syso of hashcode and id of one element of the collection.
I don't understand the solution of the last post : I need the generator, why do I have to remove hem?
Thx
Cathy


Top
 Profile  
 
 Post subject: Set.contains doesn't work...
PostPosted: Sun Feb 18, 2007 8:20 am 
Beginner
Beginner

Joined: Tue Oct 18, 2005 3:44 am
Posts: 27
Same problem as explained by jcurry. Set.remove and Set.contains doesn't work.
When we make a new java.util.HashSet with the org.hibernate.collections.PersistentSet, and then use hashSet.contains, it works well.
I can post the code but it is similary to this of jcurry : when syso of the hashcode and id element to remove is in the syso of hashcode and id of one element of the collection.
I don't understand the solution of the last post : I need the generator, why do I have to remove hem?
Thx
Cathy


Top
 Profile  
 
 Post subject: Anybody?
PostPosted: Tue Mar 20, 2007 10:05 am 
Newbie

Joined: Fri Mar 02, 2007 10:34 pm
Posts: 6
I'm surprised there haven't been any responses to this - sorry but I also don't understand the comment about the generator. Anyway, I have exactly the same problem. Here's my test code, which fails on the last line:

Code:
    public final void testSet() {
        // Get a CardSet from the database.
        List<CardSet> first =
            cardSetDao.findCardSetsByDescription(DESCRIPTION[0]);
        CardSet cardSet = first.get(0);
       
        Set<Card> cards = cardSet.getCards();

        Card card = cards.iterator().next();

        assertNotNull(cardSet);
        assertNotNull(card);
        assertTrue("Card not found!", cards.contains(card));
    }


Clearly the card must be in the set, since that's where I just got it. So something must be wrong with my equals() or hashCode(), or with Hibernate. Here are my two methods:

Code:
    /**
     * Two cards are the same if they are in the same CardSet and their front
     * and back texts are identical.
     */
    @Override
    public boolean equals(Object other) {
        if (this == other) {
            return true;
        } else if (other instanceof Card) {
            Card otherCard = (Card) other;

            if ((cardSet == null && otherCard.getCardSet() == null)
                || cardSet.equals(otherCard.getCardSet())
                && (front == null && otherCard.getFront() == null)
                || front.equals(otherCard.getFront())
                && (back == null && otherCard.getBack() == null)
                || back.equals(otherCard.getBack()))
            {
                return true;
            }
        }

        return false;
    }


Code:
    public int hashCode() {
        int hashCode = super.hashCode();
       
        if (getCardSet() != null) {
            hashCode = 29 * hashCode + getCardSet().hashCode();
        }
        if (getFront() != null) {
            hashCode = 29 * hashCode + getFront().hashCode();
        }
        if (getBack() != null) {
            hashCode = 29 * hashCode + getBack().hashCode();
        }
       
        return hashCode;
    }


Anybody got any ideas? Help would be much appreciated!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 20, 2007 10:19 am 
Beginner
Beginner

Joined: Tue Oct 18, 2005 3:44 am
Posts: 27
It's really a bug...
We replaced finally all HashSet by TreeSet, and added 'sort="natural"' to all declaration of set in the hbm files, and it works now.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 20, 2007 11:07 am 
Newbie

Joined: Fri Mar 02, 2007 10:34 pm
Posts: 6
Well I figured out my problem, though I'm not sure I like the solution. My Card object used its parent object, a CardSet, in the equals() and hashCode() computations. The idea was that one Card would be equal to another only if they had the same information AND were in the same set. This fits in with the uniqueness constraints in the database, too.

Anyway, the problem came up during initialization. When the Card is added to the CardSet's set (as they're being retrieved from the database), its CardSet field is null. Later, apparently after it's in the set, that field gets initialized to the parent CardSet. What this means is that the hash code changes after the Card is added to the set. That, in turn, means that when you try to look it up, contains() fails because it's looking in the wrong hash bucket.

For me, the solution was to stop using the CardSet in equals() and hashCode(). That neatly fixes the problem with contains(), but leaves me with a weaker equality method than I would prefer. I need to read through my code and make sure I'm never comparing Cards from different CardSets. So I think my problem is solved, but not really to my satisfaction. I wonder whether Hibernate could be forced to initialize the objects before they're added to the PersistentSet.


Top
 Profile  
 
 Post subject:
PostPosted: Thu May 24, 2007 6:05 am 
Newbie

Joined: Thu May 24, 2007 5:41 am
Posts: 1
I met the same problem, a solution I could find out for now is: after save/update the parent object which has persistent set, use session.refresh(parentObject) to force hibernate to reload the parent object and re-construct the presisent set(so the hashcodes are re-calculated).


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jul 23, 2007 5:29 am 
Newbie

Joined: Wed Jan 17, 2007 11:58 am
Posts: 6
I have had similar issues. What appears to have fixed it for me is adding 'lazy="false" to the relevant container mappings


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 02, 2008 8:33 am 
Newbie

Joined: Tue Sep 02, 2008 8:12 am
Posts: 1
pindleskin wrote:
I met the same problem, a solution I could find out for now is: after save/update the parent object which has persistent set, use session.refresh(parentObject) to force hibernate to reload the parent object and re-construct the presisent set(so the hashcodes are re-calculated).



I must second this.

Suppose you have a "Set<Foo> fooSet" and try to remove "bar" (which is of class Foo).

If you iterate over the set using a foreach and then checking each individual result with .equals you will find it if your equals / hash methods are implemented.

Code:
for (Foo f : fooSet) {
  if(bar.equals(f) {
     System.out.println("Found 'bar' !");
  }
}




This does not mean however that you will always find it using set.contains(object). If set.contains(object) doesn't find the object in question you will not be able to remove it via set.remove(object), even if the previoulsy mentioned iteration over the set finds your object via equals.

Code:
if (!fooSet.contains(bar)) {
  System.out.println("Object 'bar' not found");
}



So the foreach finds your object in question, the contains does not.
I think this is outrageous to be able to find it via iteration but not via contains !.

I agree with the above poster that this is most likely because of hashCode not being updated correctly.

And for everone saying "Well implement equals / hash correctly":
I know of 109.html and not everyone can use a distinct business key which uses "semi"-unique attributes.
And for all who don't have a unique business key, there seems to not be a nonbroken approach:
http://forum.hibernate.org/viewtopic.php?t=928172


Sorry for ranting but I think this behaviour of PersistentSet is unacceptable (especially in combination of NOT noting anythign about this in the contains Method of the ersistentSet-Javadoc)


cheers,

JSFUser


Top
 Profile  
 
 Post subject: Re: Can't get PersistentSet.remove to work correctly
PostPosted: Wed Jun 29, 2011 4:05 am 
Newbie

Joined: Wed Jun 29, 2011 4:01 am
Posts: 1
I breakpointed my #equals() method and it doesn't get called at all when PersistentSet#contains() is invoked. This explains why iterating and calling #equals() directly works.

So for me it wasn't about super fields being null.

Why doesn't Hibernate call the #equals() method? Bit odd.


Top
 Profile  
 
 Post subject: Re: Can't get PersistentSet.remove to work correctly
PostPosted: Tue Jul 19, 2011 10:51 am 
Beginner
Beginner

Joined: Sat Sep 12, 2009 10:20 am
Posts: 44
It isn't that hibernate is not calling the equals method. It is that the HashSet is not calling the equals method.
HashSet first using the hashcode before even trying to run equals, which is why it fast.


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