-->
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: bug in PersistentSet?
PostPosted: Mon Nov 07, 2005 9:38 pm 
Newbie

Joined: Mon Jan 24, 2005 6:05 pm
Posts: 12
I have two test cases are doing the same thing except one involed with persistentSet and the other one does not. The second one failed because persistentset.contains return false. but when I compared the argument and one that inside the persistentSet from debugger or compare by looping the set, both hashcode and equal evaluate to true. Has anyone out there experiencing the same problem?

Here is snippet of PersistentSet.contains()
Boolean exists = readElementExistence(object);
return exists==null ?
set.contains(object) :
exists.booleanValue();

// Set.contains documnetation
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)).


i really don't know how can following line evaluate to "!false". Please help!!

if (!getUserAddressSet().contains(userAddress)) throw new IllegalArgumentException("user address does not exist");


Code:
// plain pojo test.
public void testRemoveUserAddress() {
    UserAddress userAddress = UserAddress.createUserAddress();
    _person.addUserAddress(userAddress);
    _person.removeUserAddress(userAddress);
    assertNull("address set is null", _person.getUserAddressSet());
    assertEquals("size is not 1", 0, _person.getUserAddressSet().size());
  }

// functional test which involved hiberante and database.
  public void testDeleteUserAddress() {
    Person person = _objectCreateUtil.getPerson(false);
    UserAddress userAddress = _objectCreateUtil.getUserAddress(false);
    assertNotNull("id is null", userAddress.getId());
    person.removeUserAddress(userAddress);
    _userApi.updateObject(person);
    _userApi.commit();
    person = _userApi.loadObject(person.getId());
    assertEquals("address is not empty", 0,       person.getUserAddressSet().size());
}


public Person removeUserAddress(UserAddress userAddress) {
    if (getUserAddressSet() == null) throw new IllegalStateException("Collection is null");
    /*for (UserAddress o : getUserAddressSet()) {
      if(o.equals(userAddress)) {
       throw new IllegalArgumentException("object found");
      }
    }*/
    if (!getUserAddressSet().contains(userAddress)) throw new IllegalArgumentException("user address does not exist");
    getUserAddressSet().remove(userAddress);
    return this;
  }



Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 07, 2005 9:47 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Where in your code is the problem?

What do you mean "hashcode evaluates to true"? hashCode (note the capital C) returns an integer; it's supposed to return a fairly distinct number identifying the object, based on business values.

Are you using the database key in hashCode/equals? You must not do this, as it will cause contains to fail under some circumstances. Read the javadocs in your jdk and the docs in hibernate on how to write equals and hashCode. They're quite clear.


P.S. Thanks for using the code tag :)


Top
 Profile  
 
 Post subject: Thanks you
PostPosted: Mon Nov 07, 2005 10:32 pm 
Newbie

Joined: Mon Jan 24, 2005 6:05 pm
Posts: 12
this is where error occured before i try to remove userAddress from UserAddressSet

Code:
    if (!getUserAddressSet().contains(userAddress)) throw new IllegalArgumentException("user address does not exist");


So, I added follow code to check if persistentset is doing something weird. And it appeared to be the case. Following snippet inside the removeUserAddress actually throws exception. Which implied that contains should return true.

for (UserAddress o : getUserAddressSet()) {
if(o.equals(userAddress)) {
throw new IllegalArgumentException("object found");
}
}

here is what i do in the test case.

1) create new user object.
2) create a new user address and call the convience method add to the user. then call user update.
3) call the convience method remove from user object with the "same user address object that used was added to the user". and call update.
Code:
  public void testUpdateUserAddress_with_required_fields() {
    Person person = _objectCreateUtil.getPerson(false);
    UserAddress userAddress = _objectCreateUtil.getUserAddress(false); // from previous test.
    _objectCreateUtil.setUserAddress(userAddress);
    assertNotNull("city is null", userAddress.getCity());
    assertNotNull("state is null", userAddress.getState());
    assertNotNull("country is null", userAddress.getCountry());
//    person.addUserAddress(userAddress);
    _userApi.updateObject(person);
    _userApi.commit();
    assertNotNull("address id is null", userAddress);
  }


  public void testDeleteUserAddress() {
    Person person = _objectCreateUtil.getPerson(false);
    UserAddress userAddress = _objectCreateUtil.getUserAddress(false);
    assertNotNull("id is null", userAddress.getId());
    person.removeUserAddress(userAddress);
    _userApi.updateObject(person);
    _userApi.commit();
    person = _userApi.loadObject(person.getId());
    assertEquals("address is not empty", 0, person.getUserAddressSet().size());
  }


_objectCreateUtils is used to carry object between different test case.


I am still new to hibernate, so i do not know much about using database key in hashCode/equals can cause problem. I believe that the pitfall is dealing with new object that doesn't have id. That's why I asked in my previous post if it's possible to reserve negative number for new object. This will ensure equals and hashcode always works.

Code:
  public boolean equals(Object rhs) {
    if (rhs == null)
      return false;
    if (! (rhs instanceof Person))
      return false;
    Person that = (Person) rhs;
    if (this.getId() == null || that.getId() == null)
      return false;
    return (this.getId().equals(that.getId()));
  }

  public int hashCode() {
    if (this.hashValue == 0) {
      int result = 17;
      int idValue = this.getId() == null ? 0 : this.getId().hashCode();
      result = result * 37 + idValue;
      this.hashValue = result;
    }
    return this.hashValue;
  }


Top
 Profile  
 
 Post subject:
PostPosted: Mon Nov 07, 2005 10:46 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
The bug is in your equals and hashCode implementations. See your other thread about the solution. For other people reading this thread, please visit this page:

http://www.hibernate.org/109.html


Top
 Profile  
 
 Post subject: thank you for being so helpful.
PostPosted: Mon Nov 07, 2005 11:11 pm 
Newbie

Joined: Mon Jan 24, 2005 6:05 pm
Posts: 12
Thanks


Top
 Profile  
 
 Post subject: thank you for point out
PostPosted: Mon Nov 07, 2005 11:20 pm 
Newbie

Joined: Mon Jan 24, 2005 6:05 pm
Posts: 12
the pitfall of using database id for hashcode and equals. I tested it by change UserAddress hashcode to return 0. All test passed. I will go with customized hashcode and equals. Thanks once again!!!


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.