1

I have a class, User, which acts as the Persistence model for a table of Users in a database:

public class User {
@Id
@Basic(optional = false)
@Column(name = "USER_ID")
private Long userId;

@JoinColumn(name = "LAST_CHANGED_USER_ID", referencedColumnName = "USER_ID")
@ManyToOne(fetch = FetchType.LAZY)
private User lastChangedUser;
...

@Override
public int hashCode() {
    int hash = 0;
    hash += (userId != null ? userId.hashCode() : 0);
    return hash;
}

@Override
public boolean equals(Object object) {
    if (!(object instanceof User)) {
        return false;
    }

    User other = (User) object;
    if ((this.userId == null && other.userId != null) || 
        (this.userId != null && !this.userId.equals(other.userId))) {
        return false;
    }
    return true;
}

@Override
public String toString() {
    return "User[userId=" + userId + "]";
}
}

The field lastChangedUser is updated whenever changes are made to a User instance. Consider the following methods:

private void setUsername(string username, User lastChangedUser){
    this.username = username;
    this.lastChangedUser = lastChangedUser;
}

public void updateUserName(Long userId, Long lastChangedUserId, String username){
    EntityManager em = PersistenceManager.getPersistenceManager()
       .getEntityManager();
    EntityTransaction transaction = em.getTransaction();

    User user = em.find(User.class, userId);
    User lastChangedUser = em.find(User.class, lastChangedUserId);

    transaction.begin();
    user.setUsername(username, lastChangedUser);
    transaction.commit();
}

and the unit test:

public void testUpdateUsername(){
    UserFacade instance = new UserFacade();
    User john = instance.getUserByUserId(new Long(1));
    User jane = instance.getUserByUserId(new Long(2));

    // make the update and persist
    instance.updateUsername("JANE M. DOE", jane.userId, john.userId);

    // assert that john made the change to jane
    jane = instance.getUserByUserId(new Long(2));

    assertTrue(jane.username.equals("JANE M. DOE"));

    User actual = jane.lastChangedUser;
    User expected = john;

    // this assertion passes...
    assertTrue(actual.equals(expected));

    // yet this assertion fails!
    assertTrue(expected.equals(actual));

    // this fails as well.
    assertEquals(expected, actual);
}

Using Netbeans 7.1.1, the test results screen returns the error message:

FAILED: expected: User[id=1], but was: User[id=1].

Upon inspection, the object actual is not of type User, but that of a Proxy object. I assume this is due to the LAZY fetch annotation. As such, the object's userid has a value of null and expected.equals(actual) returns false. Yet, actual.equals(expected) returns true. To add to my confusion, the failure message shows that actual.userId is not null, but equal to the expected id!

What quirk of Hibernate or JUnit is causing the actual User object to appear after failure?

  • For clarity, assume that the `setUsername` method is located in the `User` class. – Nathan Simpson Apr 13 '12 at 19:41
  • Does `PersistenceManager.getPersistenceManager().getEntityManager();` always return the same entity manager in this scenario? Entities from different instances of EntityManagers may not like each other. – ɲeuroburɳ Apr 13 '12 at 23:55
  • I'm guessing you've overridden `equals()` on your entities. What does your `equals()` method look like? – Tim Pote Apr 14 '12 at 14:08
  • ɲeuroburɳ, the `getEntityManager()` method does not always return same instance of `EntityManager`. How does this factor into this scenario? Tim, the `equals` method is overriden; see the first code block for the implementation. – Nathan Simpson Apr 16 '12 at 14:06

1 Answers1

1

Some friends and I figured out the solution thanks to a question about obtaining ids without fetching the entire object. Since the object is a proxy, directly refrencing the field userid in equals yields a null value. However using the getter method for the userid results in fetching the actual value from the database. Hence, the equals method should look like this:

@Override
public boolean equals(Object object){
    if (!(object instanceof User)) {
        return false;
    }
    User other = (User) object;
    if ((this.getUserId() == null && other.getUserId() != null) || 
        (this.getUserId() != null && 
        !this.getUserId().equals(other.getUserId()))) {
        return false;
    }
    return true;
}

and now the assertions will hold true.

Community
  • 1
  • 1