Win a copy of Kotlin in Action this week in the Kotlin forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Object doesn't equal proxy, I think  RSS feed

 
Kevin Embree
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My first post... Hope I don't screw up describing my problem/Question....

In short my entity object does not equal an equivalent proxy... I think

Now before you say 'check your entity.equals()' read on....

I am using Seam and JPA via Hibernate.

I have a Session scope stateful bean that has a list of entities that has the @Datamodel annotation.
A page which displays a dropdown of this list (specifically displays the 'name' attribute of the entities in the list), is backed by a conversation scoped stateful bean.
The dropdown component utilizes default JSF convertEntity to return the selected object to the backing conversation scoped stateful bean.

Seemingly randomly, a selection of a value will result in a JSF canned 'Invalid selection' error. Which as I've learned means that the value selected doesn't equal one of the values listed.

My attempts to debug the issue have led me to believe the random selection that don't work, are entities that are proxies instead of objects. (The selections that do work are actually objects)

So, as I see it JSF is attempting to assess equality of 2 Entities from different sessions, and when one is a proxy it fails.

This is my current equals()...

and this is the Institution equals it references...


The only attributes not used in the equals are the entity ids.

Any thoughts, guidance, or constructive criticism is greatly appreciated.
 
Tim Holloway
Bartender
Posts: 18709
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
A proxy, by definition, isn't the original, whether you're talking computers or people.

I think, however, that your real problem is that you're expecting to push entities out to a web page and then get one of them back when the page is posted back.

HTML is a text protocol and persistent datamodel objects aren't text. So even to get a datamodel object out to a page would require some sort of mechanism to convert that object to text and then reverse the process on the inbound side. That's what JSF converters are for.

However, object conversion isn't really appropriate for HTML dropdown list (SELECT) controls for a number of reasons. Aside from general awkwardness, there are data security considerations and network overhead.

A select list is organized into key/value pairs, which is why you have to use a SelectItem as a model. The key becomes the VALUE= of the SELECT OPTION, and the SelectItem value is what displays in the list.

For persistent objects, you can generally use the object key as the SelectItem key. When the user selects and submits, the selected key is then received as the new value for the selectOneMenu control (or whatever control is presenting the dropdown list). You can then do an ordinary find by primary key in your action method to obtain the corresponding persistent object without all the fuss and bother of passing a whole raft of objects back and forth.

BTW, although you used the word "proxy", I believe that you were really talking about detached objects. And no, a detached copy is not identical to the same object in an attached state. It will return true on "equals()", but not on "==". Or at least, it's supposed to compare true on equals(), per the spec. You can see this most vividly when you do a merge, which returns an attached copy of an object which will fail the "==" test when compared to the detached object you passed into it.
 
Kevin Embree
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
However, object conversion isn't really appropriate for HTML dropdown list (SELECT) controls for a number of reasons. Aside from general awkwardness, there are data security considerations and network overhead.


I would have thought that JSF would make it simpler (require less coding from the developer) to auto convert a selection (be it dropdown, radio button, whatever...) into it's corresponding object than to have to have the developer write the query for every component. As it turns out I have a lot of selects on lots of pages that represent entities in the datamodel.

So, for me this begs the question when is it appropriate to use ConvertEntity (or any other custom converter for that matter) if not for selection components?

BTW, although you used the word "proxy", I believe that you were really talking about detached objects. And no, a detached copy is not identical to the same object in an attached state. It will return true on "equals()", but not on "==". Or at least, it's supposed to compare true on equals(), per the spec. You can see this most vividly when you do a merge, which returns an attached copy of an object which will fail the "==" test when compared to the detached object you passed into it.


I missing something, that doesn't make sense to me... If they are detached objects (and not proxies) then all the values should fail (because the corresponding session was closed), but only some do, and which ones do fail or work changes at least with simple restarting of the server, if not also with logging in to a new session.

I never use '==' unless I want to test explicitily that 2 object references are the same instance. And in this case since I know the original list is coming from one (session scoped) bean and the returned value is captured in a different conversation bean that has a seperate instance of an EntityManager. I know they won't be the same instance.

Thanks for your help!
 
Tim Holloway
Bartender
Posts: 18709
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It's better to just send out the keys instead of the whole records in cases where the entire record isn't needed on the page display anyway, such as selecting a record from a dropdown list.

First of all, the key is smaller than the entire record, so it's less data to clog up the network.

Secondly - and more importantly - if you pass the record up to the browser and read it back again, Bad People will go in and screw around with the record data. It's much safer when the record never leaves the server.

Having to fetch the record from its key is not a problem, especially when you're using a system that caches like Hibernate. In fact, this is the equivalent of the old EJB passivation scheme. It reduces the amount of RAM required by sessions, since only the key is involved, not the whole record. Which makes the app more scalable.

Converters are generally used for display elements. For example, to convert a Date object into a displayable date String and back again. They're not normally used for wholesale text serialization of complex data structures.
 
Kevin Embree
Greenhorn
Posts: 13
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok, I see both of your points. This leads me to a follow-up question. If a I set the select components key to be the entity key, and do a then do a simple find. I'll get my object, to use as necessary. But what if all I really needed was the key to set it as the foreign key for a new entity that references it. Do you know of a way in JPA (Hibernate) to set that link with just the key and not the object?

It seems ridiculous to fetch the object with the key when all I really needed was the key.
I'm a greenhorn with JPA and Hibernate as well as JSF.

Thanks again for your helping me see the 'light'
 
Tim Holloway
Bartender
Posts: 18709
71
Android Eclipse IDE Linux
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Well, the place to ask down-and-dirty Hibernate/JPA questions is our ORM forum, but I can give a short answer here.

It's a little unsettling, I think, for people with a traditional SQL background to realize that JPA is ultimately about objects. The only time you actually deal with keys is when you use one to find an object or if you extract one from an object.

However, as you've pointed out, sometimes you simply don't want the object. You don't want to go to all the trouble of fetching data you'll never use and cluttering up RAM with it.

Fortunately, JPA has the EntityManager.getReference() method. Unlike the find() method, this one really does return a proxy object. The actual record won't be retrieved unless you de-reference it. Since the return value is an instance of the foreign object (by proxy), you can pass it to the set method of a referencing object. The only restriction is that you can't do this on a detached referencing object, you have to merge (re-attach) and set the reference to the merged object.
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!