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.  [ 8 posts ] 
Author Message
 Post subject: Is this the correct rule:Private methods can't access fields
PostPosted: Tue Mar 21, 2006 7:12 pm 
Newbie

Joined: Mon Mar 20, 2006 7:40 pm
Posts: 8
I had a problem with the CGLIB proxies in which the proxies were being loaded, but somehow their values weren't being accessed correctly. I was able to work around the problem by forcing the proxies to be loaded eagerly (using outer-join=true in the parent), but that seemed unsatisfying. I persevered, and I think I now understand the answer. Would someone confirm that I now understand the Hibernate approach?

I was finally able to get things to work correctly when I removed all direct accesses to fields from private methods. I changed the methods to have package access, or used (non-private) accessor methods. Is this the right interpretation of Hibernate's requirements: "examine all persistent classes, and ensure that private methods don't access fields."

Thanks,
Chris

Hibernate version: 3.0

Full stack trace of any exception that occurs: No exception, the values in the proxy are merely ignored.

Name and version of the database you are using: hsql 1.8.0

_________________
Chris Hibbert
Prediction Markets
http://zocalo.sourceforge.net/
http://blog.commerce.net


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 21, 2006 7:32 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Unless you change your mapping to use field-level proxying (the default is property-level), then yes, you should never access fields directly even within your class. Read section 5.1.9, "property", of the ref docs for a brief description. I think that there's a fuller description in the ref docs somewhere, but I couldn't find it.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 21, 2006 8:17 pm 
Newbie

Joined: Mon Mar 20, 2006 7:40 pm
Posts: 8
thanks, tenwit, but your phrasing is somewhat broader than mine, and I don't see how it can be correct.

In order to access instance state, some of my methods must access the instance variables directly, even if it's only getters and setters. Is the proper rule that only getters and setters should access fields directly? My code seems (!) to work currently, though I have accesses to fields from other methods. The difference between working and not working hinges on the methods declaring non-private access.

5.1.9 seems to be primarily about how Hibernate gets access to the fields, rather than what restrictions are imposed on the java code in order to get along well with the proxies.

Section 1.2.1 says that constructors must have at least package visibility "for runtime proxy generation and efficient data retrieval without bytecode instrumentation". Section 4.1.1 says "We strongly recommend having a default constructor with at least package visibility for runtime proxy generation in Hibernate." Section 19.1.3 has similar wording. But these are all explicitly about constructors.

I didn't find anything else in the reference manual that talked about method access restrictions.

_________________
Chris Hibbert
Prediction Markets
http://zocalo.sourceforge.net/
http://blog.commerce.net


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 21, 2006 8:24 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
Yes, the getters and setters access the fields directly: when an object is proxied, CGlib-generated methods replace all those getters/setters, and when those generated methods are called, they replace the entire object eith the non-proxied "real" version. If you bypass those getters/setters, no de-proxying can happen.

In section 5.1.9, the bit to which I was referring is:
hibernate ref docs wrote:
The access attribute lets you control how Hibernate will access the property at runtime. By default, Hibernate will call the property get/set pair. If you specify access="field", Hibernate will bypass the get/set pair and access the field directly, using reflection. You may specify your own strategy for property access by naming a class that implements the interface org.hibernate.property.PropertyAccessor.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 21, 2006 8:55 pm 
Newbie

Joined: Mon Mar 20, 2006 7:40 pm
Posts: 8
Yes, that section from 5.1.9 is what I was referring to. It talks about how Hibernate (via the generated proxy) accesses fields. (When it says "Hibernate will call the property get/set pair", I believe it means when reading/writing from the DB, and it's not talking about the proxies.)

I haven't changed from the default access=property. But virtual methods seem to get access to fields.

From looking at the code executing in the debugger, and what I know about Java's execution model, the "real" object is held onto by the proxy, and doesn't replace the proxy in whatever object is holding onto it. (In Smalltalk, the system could use become: in this circumstance, and actually replace the proxy with the real object whereever anyone had a reference. In Java, there's no way to find all the references, so the Proxy hangs around, and continues to intercept calls.)

When a message is sent to the proxy object, it seems to execute in the context of the Proxy. Virtual methods are inherited, and field accesses seem to be turned into accesses to the fields of the hidden real object. Is there a better description somewhere of how inherited virtual methods execute in the proxy, and how they gain access to the state of the hidden instance?

Does the proxy actually forward the virtual method to the hidden real object?

My current guess is that non-private methods are inherited by the proxy, and it forwards them to the real object it has stashed away. But I haven't been able to catch that happening in the debugger, so it may be that the proxy itself is emulating the virtual method, and trapping on field accesses. It could then get or set the fields of the real object. But this seems like more work than forwarding the method and letting the real object handle it directly.

Which does it do? And why emulate, if that's what's happening?

_________________
Chris Hibbert
Prediction Markets
http://zocalo.sourceforge.net/
http://blog.commerce.net


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 21, 2006 9:08 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
The language in that section is confusing, but I think that's deliberate. It's trying to hide the fact that CGlib is used, so it uses "hibernate" to mean real hibernate, CGlib, and methods in your mapped classes, depending on the circumstance.

The proxied objects are really replaced with the real objects when they're de-proxied. You can see this happening in your debugger. If you have a loaded object a with a getB() method and a b private field (currently proxied), then when your step over a bit of your code that calls a.getB(), the private field changes from an instance of a strange class (something like BClass#proxiedByCGLib56433) to an instance of your real class B.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 21, 2006 9:26 pm 
Newbie

Joined: Mon Mar 20, 2006 7:40 pm
Posts: 8
That's not what I see.

I'm executing in A.foo() in the debugger. There's a private field b, currently proxied. I can tell, because the type is listed as net.commerce.zocalo.c$$EnhancerByCGLIB$$2c811531, and the first two instance variables are CGLIB$BOUND and CGLIB$CALLBACK_0. The latter has a field called target, which contains the actual A object.

I call getB(), and nothing changes. When a method is called on b, it is intercepted, and stuff happens that Idea doesn't track. I assume this is happening in the generated bytecodes.

Has Hibernate's behavior here changed between 3.0 and 3.1?

_________________
Chris Hibbert
Prediction Markets
http://zocalo.sourceforge.net/
http://blog.commerce.net


Top
 Profile  
 
 Post subject:
PostPosted: Wed Mar 22, 2006 6:29 pm 
Expert
Expert

Joined: Thu Dec 23, 2004 9:08 pm
Posts: 2008
No. That's all CGlib stuff, anyway. Changes in Hibernate wouldn't change that. Whatever your debugger is showing, you should still see the correct results in your programme if you adopt one of the changes I mentioned: change all access rules to field instead of property, or never use field access except in accessors and mutators.


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