-->
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.  [ 11 posts ] 
Author Message
 Post subject: Strange behavior with set.contains(): it returns false
PostPosted: Sat Oct 22, 2005 11:26 pm 
Beginner
Beginner

Joined: Sat Oct 22, 2005 11:16 pm
Posts: 40
Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp

[b]Hibernate version:[/b] 3.0.5

Ok, here is a strange situation:

I have a User object which contains a set of Tasks. This is all occuring within Tomcat. The User is stored in Tomcat's session.

In one of my JSP tags, I get the User object from the HttpSession. Then I re-attach it by creating a Hibernate session and use session.update(user). Then I get the tasks set:

Set tasks = user.getTasks();

Before doing that, I load the task in by task ID number:

Task task = session.get(Task.class, taskIdNumber);

and I want to see if the task is one of the user's tasks. This is a security check; I want users to be able to look at their own tasks only.

So I use:

if(! tasks.contains(task)) { // access denied!

But it isn't working when it should. I have narrowed the problem down some.

First, the Hibernate session guarantees that objects which are persistent and attached will have:

a == b

if a and b refer to the same row in the DB. This is the case. In fact I can do an iterator through the tasks set and see that the exact same object (object identity, a == b) is within the set.

And yet contains() still returns false!

Can anyone say why this is? It seems like it's a serious violation of the Set contract. I'm totally baffled.

One thing I have done is to write my own equals() and hashCode() methods for Task. They do work correctly.

Any thoughts on this mysterious problem would be appreciated. Thanks.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 23, 2005 12:22 am 
Beginner
Beginner

Joined: Sat Oct 22, 2005 11:16 pm
Posts: 40
Ok, even more bizar:

I know that the set of tasks has more than one Task in it. So I do this:

Code:
Set<Task> tasks = user.getTasks();
Iterator taskIterator = tasks.iterator();
Task t = taskIterator.next();
if(! tasks.contains(t)) System.out.println("The contract for Set has been violated!");


And that prints out, "The contract has been violated" which is very strange. How is it possible that I just got that object out of the set, and then the set doesn't contain it?

I am totally stumped by this.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 23, 2005 12:48 am 
Beginner
Beginner

Joined: Sat Oct 22, 2005 11:16 pm
Posts: 40
Ok, I did some more research and I'm even MORE confused, if that's possible.

I assume that when I get a Set from a persistent object, I'm not getting a java.util.HashSet, but rather, I'm getting a org.hibernate.collection.PersistentSet. So I looked at how that works.

When I get an Iterator from a PersistentSet, it gives me an IteratorProxy which is just a wrapper. So when I get an object from that Iterator that object comes from the underlying Set.

And then when I call PersistentSet.contains(), again, that call is just passed on to the underlying set.

So I can't see how the semantics of PersistentSet and plain old HashSet could be so different, to the extent that I can get an object from it and then find out that the set doesn't contain that object!


Top
 Profile  
 
 Post subject: Re: Strange behavior with set.contains(): it returns false
PostPosted: Sun Oct 23, 2005 3:53 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
SleepyBear wrote:
One thing I have done is to write my own equals() and hashCode() methods for Task. They do work correctly.

Any thoughts on this mysterious problem would be appreciated. Thanks.


That the statement above is false - your equals and hashCode does not work.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 23, 2005 5:28 pm 
Beginner
Beginner

Joined: Sat Oct 22, 2005 11:16 pm
Posts: 40
I replaced the equals method and it works. I can't figure out what was wrong with the old equals, which was only about five lines of code, but whatever.

In any case I've decided to do the whole thing different. It doesn't make sense for a user to have a set of tasks. It makes more sense for every task to have a user. There could be thousands of tasks and I should't keep them in a set; instead I should do queries to only load the small number of tasks I'm interested in at any given time.

It's a different way of thinking about it. I can always do "Get a list of tasks where user = ___". There's nothing like that in POJO.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 23, 2005 5:39 pm 
Expert
Expert

Joined: Mon Jul 04, 2005 5:19 pm
Posts: 720
"It doesn't make sense for a user to have a set of tasks. It makes more sense for every task to have a "

... you can have both w/ a bi-directional relationship. and you don't need to worry about pulling every task into memory because there are things like lazy loading, filters, various fetching stratiegies and several APIs to query the data.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 23, 2005 7:17 pm 
Beginner
Beginner

Joined: Sat Oct 22, 2005 11:16 pm
Posts: 40
Is there any real need to do both? I thought about it and I can't see a reason for both. If I have a user and I want to get ALL of that user's tasks, I just do a query to get them, and I can get them in any order I want also. What would be the reason for the user to even have a set in this case?

I know that in JPH (Java, pre-Hibernate) the user would need to have a set of the tasks and then I would need to write my own filter system to get the tasks I want out of that set, but in JWH (Java with Hibernate) I don't see the need anymore.

The one possible drawback is that without that set, my whole system won't work without Hibernate. One of the points they keep on making in the Hibernate book is that your biz objects should be able to exist and be usable without Hibernate present. But in reality, this whole thing is useless without Hibernate so I might as well use it, right? Persistence can be painless but not truly transparent.


Top
 Profile  
 
 Post subject:
PostPosted: Sun Oct 23, 2005 7:25 pm 
Expert
Expert

Joined: Mon Jul 04, 2005 5:19 pm
Posts: 720
SleepyBear wrote:
Is there any real need to do both? I thought about it and I can't see a reason for both. If I have a user and I want to get ALL of that user's tasks, I just do a query to get them, and I can get them in any order I want also. What would be the reason for the user to even have a set in this case?


fewer lines of code for one thing, but if this is your view, what is the point of mapping relationships in the first place then?

SleepyBear wrote:
I know that in JPH (Java, pre-Hibernate) the user would need to have a set of the tasks and then I would need to write my own filter system to get the tasks I want out of that set, but in JWH (Java with Hibernate) I don't see the need anymore.


are you talking about this?
http://www.hibernate.org/hib_docs/v3/re ... -filtering

SleepyBear wrote:
The one possible drawback is that without that set, my whole system won't work without Hibernate. One of the points they keep on making in the Hibernate book is that your biz objects should be able to exist and be usable without Hibernate present. But in reality, this whole thing is useless without Hibernate so I might as well use it, right? Persistence can be painless but not truly transparent.


a pojo is resusable w/ or w/out a Set. what are you doing w/ your domain model that makes it non-reuseable?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 24, 2005 1:16 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
couple of things:

Your equals and hashcode methods were probably just wrong because of either:
A: it was based on values that changes while it is in the collection (like the ID)
B: hashcode were not returning the same value for equal objects

Not having bidirectional relationships is all ok (likewise is the opposite) if it fits best with the usage. I tend not to use bidirectional associations since it as you mention can result in large collections which is actually never what I want.

It does not mean I come dependent on Hibernate, it instead means I will have some DAO to fetch my associations - that can be implemented in any way necessary. Again, if you know your system will always run with hibernate then just use hibernate more directly - saves you alot of indirection and LOC.

It's all fair choices.

_________________
Max
Don't forget to rate


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 24, 2005 3:00 am 
Beginner
Beginner

Joined: Sat Oct 22, 2005 11:16 pm
Posts: 40
max wrote:
couple of things:
Your equals and hashcode methods were probably just wrong because of either:
A: it was based on values that changes while it is in the collection (like the ID)
B: hashcode were not returning the same value for equal objects

This is how I fixed it: I wrote these methods:
Code:
public boolean equals(Object o) {
  return o instanceof Task;
}

public int hashCode() {
  return 5;
}

Those are not methods you would ever want to use in a real application but they do uphold the contracts of equals and hashCode as required by Set, so I used them to test what if something was wrong with my classes, or what.
Quote:
I tend not to use bidirectional associations since it as you mention can result in large collections which is actually never what I want.

Right, in thinking about it, there will never be a time when I need or want a set with all of a user's tasks in it. It will always be some sub-set of them (tasks which are due next month, tasks related to a certain project, etc), and they will always be in some order. So if a Set doesn't fit what I want in any real use case, I shouldn't bother with a set. I'll always want to do some kind of query to fetch tasks which match query parameters.
Quote:
It does not mean I come dependent on Hibernate, it instead means I will have some DAO to fetch my associations - that can be implemented in any way necessary. Again, if you know your system will always run with hibernate then just use hibernate more directly - saves you alot of indirection and LOC.

It's not that I need Hibernate, I just can't see how I could do this without some kind of query language. I'm sure there are query languages that pull Lists out of Sets according to criteria and order-by rules, but then I'm also going to need persistence so I might as well stick with Hibernate.

The book makes a big deal of how transparent Hibernate is. I'm saying that I'm treating it as a valuable programming tool, not something which I wish were truly transparent (ie, something I could ignore).
[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Mon Oct 24, 2005 3:11 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 6:10 am
Posts: 8615
Location: Neuchatel, Switzerland (Danish)
yes - that equals method is bad since it will always return true for a Task only set ;) ...i'm more interested in seing your original broken equals/hashcode.

I don't think we ever says that hibernate is transparent with respect to be something you can ignore! We say hibernate is transparent in the sense that your domain model does not get infected with hibernate specific code; and the same goes for your service code if you add a DAO layer. Something as important and performance crucial as effective querying and storage is not intended to be ignored.

_________________
Max
Don't forget to rate


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