-->
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.  [ 10 posts ] 
Author Message
 Post subject: wrap/decorate entity
PostPosted: Mon Sep 12, 2005 1:52 pm 
Regular
Regular

Joined: Thu Dec 11, 2003 4:14 pm
Posts: 86
Location: Hibernate 3 + annotations, Oracle 9i, PostgreSQL 8.0, Java 1.5.0
I try some experiment and maybe need some suggestions.

The idea behind my experiment is to get rid of LazyInitializationException and detached objects in an JSF (or webapp in general) application but still using the session-per-request pattern.
The only exception is StaleObjectException on version conflict - and this is wanted.

I found a way to wrap a entity using cglib and use this wrappped instance as replacement in my code. The wrapper acts like a "transfer object" and when it comes to save it automatically merges the object with the hibernate entity. This works witout great change in my code - only a one-liner to wrap the entity.

The problem I have is that this wrapper (while still have the same signature like to orignial entity just enhanced with cglib) cant be directly used in hibernate, in particular with the criteria api.

Code:
Caused by: org.hibernate.HibernateException: instance not of expected entity type: com.ops.Contact.model.po.Relation
        at org.hibernate.persister.entity.BasicEntityPersister.getSubclassEntityPersister(BasicEntityPersister.java:3083)
        at org.hibernate.impl.SessionImpl.getEntityPersister(SessionImpl.java:1080)
        at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:221)
        at org.hibernate.type.EntityType.getIdentifier(EntityType.java:107)
        at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:72)
        at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:1456)
        at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1518)
        at org.hibernate.loader.Loader.doQuery(Loader.java:638)
        at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:221)
        at org.hibernate.loader.Loader.doList(Loader.java:1959)
        at org.hibernate.loader.Loader.list(Loader.java:1928)
        at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:94)
        at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1314)
        at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:298)


I encapsulated all session methods so there I do not have a problem to "unwrap" my object. But I am not able to do the same with Expression et al.

So what I would like to know if there is a place where I can make a hook to unwrap my entity.
And if there is no place, is it possible to build one - aka Interceptor?

And if not, why is
org.hibernate.criterion.Expression final
and the constructor of org.hibernate.criterion.Restrictions package private.
If we could change this so that I can extend my own Expression class I could unwrap my entity there.

Thanks!


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 13, 2005 7:45 am 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 3:00 pm
Posts: 1816
Location: Austin, TX
AFAICT, all that you are wanting to do can be achieved by plugging in custom tuple implementations (as in stuff from the org.hibernate.tuple package). This is the stuff used by the persisters to manage the various "entity representations". These are the things that tell hibernate how to create proxies for entities, how to marshall propertiy values to/from the entity, how to perform instantiation, etc.

This stuff is in the process of being cleaned up and exposed for configuration starting in 3.1. Usage is documented in the reference manual that comes bundled with any of the 3.1 releases (not yet pushed to the website since 3.1 is not yet final).

Here is an example from the manual:
Code:

<class entity-name="Customer">
    <!--
        Override the dynamic-map entity-mode
        tuplizer for the customer entity
    -->
    <tuplizer entity-mode="dynamic-map"
            class="CustomMapTuplizerImpl"/>

    <id name="id" type="long" column="ID">
        <generator class="sequence"/>
    </id>

    <!-- other properties -->
    ...
</class>


public class CustomMapTuplizerImpl
        extends org.hibernate.tuple.DynamicMapEntityTuplizer {
    // override the buildInstantiator() method to plug in our custom map...
    protected final Instantiator buildInstantiator(
            org.hibernate.mapping.PersistentClass mappingInfo) {
        return new CustomMapInstantiator( mappingInfo );
    }
}

private static final class CustomMapInstantiator
        extends org.hibernate.tuple.DynamicMapInstantitor {
    // override the generateMap() method to return our custom map...
    protected final Map generateMap() {
        return new CustomMap();
    }
}


Have a look at the org.hibernate.tuple.EntityTuplizer interface to get a feel for the kinds of things you can do here...


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 13, 2005 8:15 am 
Regular
Regular

Joined: Thu Dec 11, 2003 4:14 pm
Posts: 86
Location: Hibernate 3 + annotations, Oracle 9i, PostgreSQL 8.0, Java 1.5.0
steve wrote:
This stuff is in the process of being cleaned up and exposed for configuration starting in 3.1. Usage is documented in the reference manual that comes bundled with any of the 3.1 releases (not yet pushed to the website since 3.1 is not yet final).

Oh boy, I search the forums and googled around, but never thought a possible solution could be that near.

Ok, there is much room to learn new stuff now. Will see if I manage to get things running.

Thanks for taking the time!


Top
 Profile  
 
 Post subject: Wrapping objects
PostPosted: Wed Sep 14, 2005 12:02 pm 
Newbie

Joined: Fri Sep 26, 2003 11:44 am
Posts: 13
Hi,

Just to chime in here, I have written code to wrap all entity objects produced by Hibernate, although for a different prupose than lazy loading. I think Steve has already pointed you in the right direction with the instantiator and tupulizer classes. The other change I made was to actually change the Hibernate source code for the Hibernate#getUnderlyingClass so that it can handle my new entity proxy (this is what is causing your error).

Just to be safe, I also changed all calls to Object#getClass() in the Hibernate source code to be Hibernate#getUnderlyingClass(). I am not sure this last step is necessary.

Regards,

Ali

_________________
Ali Ibrahim


Top
 Profile  
 
 Post subject: Re: Wrapping objects
PostPosted: Wed Sep 14, 2005 1:34 pm 
Regular
Regular

Joined: Thu Dec 11, 2003 4:14 pm
Posts: 86
Location: Hibernate 3 + annotations, Oracle 9i, PostgreSQL 8.0, Java 1.5.0
aibrahim wrote:
Hi,
The other change I made was to actually change the Hibernate source code for the Hibernate#getUnderlyingClass so that it can handle my new entity proxy (this is what is causing your error).


YES - YES - YES - YES !!!!!!

I tried the tuplizer stuff but figured out I dont want to decorate all entites.
Only if a entity is going to be detached it should be wrapped.
But then I again raised the exception above.

Did you put your patch into jira?

HIBERNATE DEVELOPERS any chance to get such a patch into the main code?????

But then, its still not enough for me :-(: I also need something like "getUnderlyingEntity"


Top
 Profile  
 
 Post subject: Re: Wrapping objects
PostPosted: Wed Sep 14, 2005 1:37 pm 
Regular
Regular

Joined: Thu Dec 11, 2003 4:14 pm
Posts: 86
Location: Hibernate 3 + annotations, Oracle 9i, PostgreSQL 8.0, Java 1.5.0
aibrahim wrote:
for a different prupose than lazy loading


I dont want to lazy load my objects, I just want to autmaticall attach and merge them to the current session if they are not attached or not initialized (HibernateProxy) on the first property access.

It already works if I unwrap my entity before passing it to hibernate - and its a great new feeling when writing JSF - I dont have to think to update/lock/merge them.
The only exception still thrown is the one if a version-mismatch is detected, but this is wanted.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 1:43 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
The problem with approaches like this is that you have to have a wierd "new" operation. Seems especially dangerous in the context of JSF, where JSF is often responsible for instantiation of the object.

You can try to do stuff like this with AOP but, for various reasons, I think the long session approach is the soundest one.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 1:45 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
Actually, the biggest (killer) problem is maintaining identity. You have no "scope".

So, this approach is actually completely broken and cannot be rescued.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Sep 14, 2005 2:15 pm 
Regular
Regular

Joined: Thu Dec 11, 2003 4:14 pm
Posts: 86
Location: Hibernate 3 + annotations, Oracle 9i, PostgreSQL 8.0, Java 1.5.0
gavin wrote:
Actually, the biggest (killer) problem is maintaining identity. You have no "scope".


I know its not safe to put such wrapped instances into a set/map as they might change its identity.
But this is not that a problem - mostly such instances are put in a member or their state is rendered into the page - or hold in an dataTable.
In any case it is hard to reattach them, but you know this ...
If you have a lot of references its not unlikely that another entity already loaded another entity - if you try to update() or lock() the detached (SAME) entity you know the exception.
The only solution is to merge() but then you will get a new instance of this object which you have to propagate then - even this is sometimes hard.

gavin wrote:
JSF is often responsible for instantiation of the object

What do you mean by this? JSF create manages-beans - the backings - and a backing create new entities or load them from the database.
JSF will never instantiate a entity from its own - at least in my case.


With the wrapping stuff I can get rid of this - and on the first property access this wrapper get an identity (if it is detached) - the same of the underlaying entity.
Every property access is delegated to the real entity.
If the real entity changes its identity you might have problems too - I try to avoid this by using a surrogated key - objectId.

For now I only have Session.save() in my code - all merge/lock is in the wrapper.


Top
 Profile  
 
 Post subject: Patch for getUnderlyingClass
PostPosted: Wed Sep 14, 2005 2:17 pm 
Newbie

Joined: Fri Sep 26, 2003 11:44 am
Posts: 13
Hi,

I am afraid I didn't submit a patch and it is really not suitable for a patch. I changed the method to recognize my own special proxy much as it recognizes Hibernate proxies. I am not using this to handle detached entities or anything like that, but rather for my research purposes (I also have a lot of other custom hacks :)).

Regards,

Ali

_________________
Ali Ibrahim


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