-->
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.  [ 3 posts ] 
Author Message
 Post subject: Constructor for new objects
PostPosted: Wed Apr 06, 2005 12:57 am 
Newbie

Joined: Wed Apr 06, 2005 12:30 am
Posts: 7
Hibernate version:
3.0, working under JBoss 4.0.1SP1 with JTA

I have a bunch of simple objects in a parent/child relationship.

I have an AccountNode object that, when instantiated through the default constructor, instantiates a HashSet member, a UserListNode object and adds the latter to the HashSet, and upon save both objects have rows corresponding to them in the db. However, when I load the objects from the db, all the code in the default constructor still executes, instantiating the HashSet and the UserListNode, only to have them immediately replaced by Hibernate proxies.

I would like to avoid the extra unnecessary steps - there are two immediate solutions that come to mind:
1) create another constructor with a different signature and instantiate the new object using that - it is easy enough to do, but has a hackish feel to it, since the parameter never gets used.

2)create a static "create" method that does the necessary instantiation work. This has more of an EJB home.create() feel to it, and moves instantiation logic out of the constructor, which is fine for simple situations, but complicates initialization of superclasses (a class that derives from AccountNode should call a superconstrucor, not AccountNode.create() )

What would be ideal would be to detect if the constructor is being called by Hibernate or by my own code, but somehow that doesn't feel possible in a Java environment.

Has anyone ran into this situation here? How did you handle it?


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 22, 2005 8:19 am 
Regular
Regular

Joined: Wed May 11, 2005 11:57 pm
Posts: 80
Write an Interceptor that calls a different constructor for Hibernate. For example, add a Constructor like this to your business object:

Code:
   public Campus( Serializable id, byte ignore ) {
      setId( (Long)id );
   }


I added a byte param to the constructor to make it less likely that it would conflict with or be confused with something like Campus(String campusName). Now here's an Interceptor that I wrote that will always use that constructor when Hibernate loads objects from the database:

Code:
   public class HibernateConstructorInterceptor extends EmptyInterceptor {
      private static final Byte fakeParam = new Byte((byte)0);
      private static final Class[] HIBERNATE_SIGNATURE = new Class[] {Serializable.class, byte.class};
      private Map constructors = new HashMap(30);

      public Object instantiate( String entityName, EntityMode entityMode, Serializable id ) {
         if( entityMode != EntityMode.POJO ) return null; //Don't know how to deal with other entity types
         Object cachedValue = constructors.get( entityName );
         if( cachedValue == fakeParam ) return null; //We've already checked, and there's no Hibernate constructor
         try {
            Constructor constructor;
            if( cachedValue != null ) {
               constructor = (Constructor)cachedValue; //Found the constructor in the cache
            } else {
               Class entityClass = Class.forName( entityName ); //Not sure whether this is the safest way to get the class, there might be a better alternative.
               try {
                  constructor = entityClass.getConstructor( HIBERNATE_SIGNATURE );
                  constructors.put( entityName, constructor ); //Found it! Store it in the cache for next time.
               } catch( NoSuchMethodException e ) {
                  constructors.put( entityName, fakeParam ); //No Hibernate constructor. Remember for next time to save the time to check.
                  return null;
               }
            }
            return constructor.newInstance( new Object[] {id, fakeParam} ); //Call Hibernate constructor with id.
         } catch( Exception e ) {
            e.printStackTrace();
            return null;
         }
      }
   }


Now you can put your 'real' business logic in the constructor, knowing that it will only be triggered when you explicitly call it. If you don't create a constructor with that specialized signature, the regular no-arg one will be used.


Top
 Profile  
 
 Post subject: Intercepting default constructors
PostPosted: Wed May 03, 2006 12:48 pm 
Newbie

Joined: Tue May 02, 2006 11:31 am
Posts: 1
I wrote a constructor interceptor as suggested by jbarnum. It worked great. Hibernate now calls the specialized constructor instead of the default constructor. But it only works when actually getting something from persistence. It does not work when Hibernate gets initialized.

When Hibernate first starts up, it runs through the HbmBinder to check the mappings and then through AbstractEntityPersister. AbstractEntityPersister runs through some select, insert, update, and delete statements for each hibernate entity class. When it does that, it calls the class's default constructor. It does not get intercepted by the constructor interceptor.

Is there a way to change this behavior? Or am I forever stuck with Hibernate going into the default constructor when I don't want it to?

Here is a sample of the debug statements displayed as it goes through the default constructor of every class (I'm only displaying statements for 1 class for simplification)


11:29:34,499 DEBUG AbstractEntityPersister:2447 - Static SQL for entity: contract.PolicyGroup
11:29:34,499 DEBUG AbstractEntityPersister:2449 - Version select: select [PolicyGroupPK] from "dbo"."PolicyGroup" where [PolicyGroupPK] =?
11:29:34,509 DEBUG AbstractEntityPersister:2450 - Snapshot select: select policygrou_.[PolicyGroupPK], policygrou_.[GroupName] as GroupName2_46_, policygrou_.[GroupNumber] as GroupNum3_46_, policygrou_.[CaseFK] as CaseFK4_46_ from "dbo"."PolicyGroup" policygrou_ where policygrou_.[PolicyGroupPK]=?
11:29:34,509 DEBUG AbstractEntityPersister:2452 - Insert 0: insert into "dbo"."PolicyGroup" ([GroupName], [GroupNumber], [CaseFK], [PolicyGroupPK]) values (?, ?, ?, ?)
11:29:34,509 DEBUG AbstractEntityPersister:2453 - Update 0: update "dbo"."PolicyGroup" set [GroupName]=?, [GroupNumber]=?, [CaseFK]=? where [PolicyGroupPK]=?
11:29:34,509 DEBUG AbstractEntityPersister:2454 - Delete 0: delete from "dbo"."PolicyGroup" where [PolicyGroupPK]=?


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