11

I have a service method that calls a DAO which then returns an object from the database. This method is called from numerous parts of the system. However, one particular method is getting a return type of ObjectClass_$$_javassist_somenumber as the type. Which is throwing things off. I call the service method exactly the same as everywhere else, so why would hibernate return the proxy as opposed to the natural object?

I know there are ways to expose the "proxied" object, but I don't feel like I should have to do that.

The query is simply

hibernateTemplate.find("from User u where u.username = ?", username)

I am using hibernate 3.3 btw.

3 Answers3

10

It is a proxied object in order to support lazy loading; basically as soon as you reference a child or lookup object via the accessor/getter methods, if the linked entity is not in the session cache, then the proxy code will go off to the database and load the linked object. It uses javassist to effectively dynamically generate sub-classed implementations of your objects (although I think it can be configured to use CGLIB too).

If it weren't proxied in this way it would be nigh-on impossible to implement seamless lazy loading.

I can't remember off the top-of-my-head whether if you use eager loading then whether the natural object would be returned instead. I wouldn't generally recommend using eager loading though especially if you have lots of linked child entities, as it can soon be a huge performance bottleneck as it will suck in every linked object into memory.

Also, if you need to discriminate on the class type, rather than using obj.getClass(), use Hibernate.getClass(obj) which will give you back the natural object class regardless of whether it is proxed or not: see the Hibernate API Javadocs here.

RedYeti
  • 1,024
  • 14
  • 28
rhu
  • 963
  • 5
  • 9
  • Well the object is eagerly loaded and since I am getting a proxy object in this particular call, I guess you cannot guarentee that the object will be either. Interestingly tho, when I call DAO.getUser(String username) from method A, I get the User object but from method B calling the method in the exact same manor, I get the proxy. –  Apr 07 '10 at 19:10
  • 2
    Usually, the problem is that the proxy *returned in this way* is NOT initialized correctly; otherwise if it was filled properly, things should have gone through normally. Anybody knows why the find method may return an uninitialized proxy? – Amir Moghimi Jul 22 '11 at 03:15
3

Hibernate returns proxies if not all members are resolved, i.e. the object is not complete. This is often a desired feature to improve performance and is (I think) the default setting in hibernate.

If you do not want proxies you can suppress lazy loading in the hbm.xml file, i.e. use eager loading. Please check the hibernate docs for the exact syntax.

To use the proxy object just never access a member directly but only via getter, even within member functions. Hibernate magic fills in the member when you get it. This way you never have to expose the object. Also don't use instanceof on potential proxy objects. But this is a code smell anyway.

openCage
  • 2,735
  • 1
  • 18
  • 24
  • 3
    Instanceof checks will still work, because proxies are still instances of sub classes of your class. What wouldn't work is an equals or identity comparision of the class object (as provided by getClass()). – whiskeysierra Apr 07 '10 at 23:28
  • I am running into this problem but found the statement above to be incorrect, which was how we found the problem. We iterate across a collection and check 'instanceof' for the expected object which fails. I honestly don't know exactly how java handles this internally but we put a println with "instanceof x="+(obj instanceof x) and it printed false. The Hibernate.getClass(obj) works great, but I would like to get to the bottom of why the object was not fully initialized. – mikemil Oct 10 '13 at 15:50
  • @whiskeysierra - Sorry, forgot to include your id for notification of the above comment. – mikemil Oct 10 '13 at 15:58
  • About instanceof problem - if you use lazy proxy in a field with declared class A, then even if you have B class extending A, if you will fetch the object into the A field it will never be "instanceof B". This is because hibernate don't know what will be the real class of the entity before it gets it from the db, and it cannot get it because you explicitly use lazy proxy here. So, it uses declared class (A) to create proxy. I described it more thoroughly here http://lifeinide.com/post/2017-05-28-hibernate-single-side-associations-lazy-fetch/ – Lukasz Frankowski May 28 '17 at 11:36
  • `instanceof` checks will only work if you have no inheritance in your entities. – Hannes Schneidermayer Jul 01 '21 at 10:52
3

In my opinion this expression:

hibernateTemplate.find("from User u where u.username = ?", username)

Should always return POJO, not a proxy. This is because standard HQL/criteria returns non-proxied object, but objects of your original entity classes. This is different from lazy associations fetching:

@Entity
class X {
    @ManyToOne(fetch = FetchType.LAZY)
    private User user;
}

Getting X object from the db here, we will have a lazy proxy in X.user field (a proxied User instance).

Now, it happens that doing from User where [...] you sometimes have POJO and sometimes proxy object. Usually this is because in some executions User object was first fetched from the db through associations (from X where [...] query was called first in given hibernate session). Having already (proxied) User instance, hibernate will reuse this instance even for your plain queries like from User where [...].

Lukasz Frankowski
  • 2,955
  • 1
  • 31
  • 32