5 Replies Latest reply on Aug 10, 2010 10:22 AM by Robin G

    NPE when lazy=false in joined-subclass?

    Robin G Newbie

      I'm trying to add Envers to an existing project with Hibernate 3.5.2 and Spring. Hibernate is configured with mappings, and the annotations are basically limited to me just adding @Entity and @Audited over the various classes. Everything is audited into the database properly (as far as I can tell).

       

      My problem is that a NPE occurs when I try to use getAuditReader().find(...) on a joined-subclass Entity that is set to lazy=false.

       

       

      root cause

      java.lang.NullPointerException
          org.hibernate.tuple.entity.AbstractEntityTuplizer.createProxy(AbstractEntityTuplizer.java:634)
          org.hibernate.persister.entity.AbstractEntityPersister.createProxy(AbstractEntityPersister.java:3713)
          org.hibernate.envers.entities.mapper.relation.ToOneIdMapper.mapToEntityFromMap(ToOneIdMapper.java:90)
          org.hibernate.envers.entities.mapper.MultiPropertyMapper.mapToEntityFromMap(MultiPropertyMapper.java:118)
          org.hibernate.envers.entities.mapper.SubclassPropertyMapper.mapToEntityFromMap(SubclassPropertyMapper.java:67)
          org.hibernate.envers.entities.EntityInstantiator.createInstanceFromVersionsEntity(EntityInstantiator.java:93)
          org.hibernate.envers.entities.EntityInstantiator.addInstancesFromVersionsEntities(EntityInstantiator.java:103)
          org.hibernate.envers.query.impl.EntitiesAtRevisionQuery.list(EntitiesAtRevisionQuery.java:90)
          org.hibernate.envers.query.impl.AbstractAuditQuery.getSingleResult(AbstractAuditQuery.java:105)
          org.hibernate.envers.reader.AuditReaderImpl.find(AuditReaderImpl.java:106)
          MY.APP.persistence.dao.HistoryDAOImpl.getAllBBChangesets(HistoryDAOImpl.java:93)

       

      This problem goes away when I set lazy=true for that Entity in the hibernate mapping, and I can retrieve the Entity just fine, and even then read its attributes and children. Unfortunately our project wasn't designed to support lazy=true in other, unrelated, parts of the code, so setting lazy=true is not really an option.

       

      Here's a trimmed version of our mapping. The Entity that I'm having this problem with is "BusinessProcess", which is a joined-subclass of "BuildingBlock":

       

      <class name="BuildingBlock" table="BB" lazy="true">
          <id name="id" column="ID" type="java.lang.Integer">
            <generator />
          </id>
          <version name="olVersion" column="VERSION" type="integer" unsaved-value="negative" />
          <many-to-one name="buildingBlockType" column="ID_BBT" not-null="true" />
          <set name="owningUserEntities" table="BB_UE" lazy="true">
            <key column="ID_BB" />
            <many-to-many column="ID_UE" fetch="join" />
          </set>
          <set name="attributeValueAssignments" lazy="true" inverse="true" cascade="delete,save-update">
            <key column="ID_BB" />
            <one-to-many />
          </set>
          
          ...
          ...[[MANY JOINED-SUBCLASSES HERE]...
          ...
          
          <joined-subclass name="BusinessProcess" table="BP" lazy="false">
            <key column="ID_BB" />
            <property name="name" column="NAME" length="255" not-null="true" unique="true" />
            <property name="description" column="DESCRIPTION" length="4000" />
            <set name="businessMappings" lazy="true" inverse="true" cascade="delete">
              <key column="ID_BP" />
              <one-to-many />
            </set>
            <set name="businessDomains" table="BP_BD" lazy="true">
              <key column="ID_BP" />
              <many-to-many column="ID_BD" />
            </set>
            <many-to-one name="parent" column="ID_PARENT" insert="true" update="true" />
            <list name="children" lazy="true">
              <key column="ID_PARENT" />
              <list-index column="POS" />
              <one-to-many />
            </list>
            <property name="position" column="POS" type="integer" update="true" insert="true"/>
          </joined-subclass>
          
          ...
      </class>
      

       

      Again, the NPE only occurs when the line, as above, reads:

       

      <joined-subclass name="BusinessProcess" table="BP" lazy="false">
      

       

      If I change it to the below, the NPE does not occur (but that's not really an option for this project, as I mentioned)

       

      <joined-subclass name="BusinessProcess" table="BP" lazy="true">
      

       

      The problem in the Hibernate code seems to be that proxyFactory is null. My issue seems very similar to bug HHH-3854, but I'm unsure, because the current mapping has worked just fine for us with just Hibernate. It's only when Envers tries to retrieve previous revisions of Entities that this issue occurs in our project.

        • 1. Re: NPE when lazy=false in joined-subclass?
          Hernán Chanfreau Master

          Hi!

           

          I think it's the same problem that HHH-3854.

           

          Envers obtains all associations in the lazy way. We needed to mark the relations as lazy instead of the classes in our project. In this case you must put the lazy several times but envers can work properly and it's the same for hibernate.

           

          Regards, Hernán.

          1 of 1 people found this helpful
          • 2. Re: NPE when lazy=false in joined-subclass?
            Robin G Newbie

            So until that bug is fixed, it will be impossible for me to use Envers, unless I set lazy=true?  If so, is there any ETA on a fix?  Thanks for your reply.

            • 3. Re: NPE when lazy=false in joined-subclass?
              Hernán Chanfreau Master

              Hi!

               

              You're right. I don´t know about the fix, maybe Adam could tell us about it.

               

              Some thoughts about this:

              • lazy=true is the default value for tag class, so you can put lazy=true or nothing.
              • You can obtain lazyness behavior marking the relations to a class as lazy instead of the class. (I mean tags like many-to-one, one-to-many, etc, putting lazy=true)

               

               

               

              Hernán.

              • 4. Re: NPE when lazy=false in joined-subclass?
                Robin G Newbie

                I tried setting all the relations to lazy, but that didn't seem to fix the NPE.

                 

                Since 3.1, I think, you no longer have lazy="true" for relations, but rather "proxy" or "no-proxy". It seems that many-to-many only supports "proxy", not "no-proxy", so I've set all of these relations to "proxy". one-to-many didn't seem to support the lazy attribute being specified at all, so I left that alone. many-to-one allowed both "proxy" and "no-proxy", so I've tried setting all to "proxy" as well as setting all to "no-proxy".

                 

                Either way, the NPE remained. It seems necessary to make the class itself lazy="true" rather than just the relations. Since that's not an option in my scenario, I tried altering Hibernate itself.

                 

                The issue HHH-3854 seems to come from the following code in Hibernate 3.5.4's AbstractEntityTuplizer.java:176

                 

                if ( entityMetamodel.isLazy() ) {
                     proxyFactory = buildProxyFactory( mappingInfo, idGetter, idSetter );
                     if (proxyFactory == null) {
                          entityMetamodel.setLazy( false );
                     }
                }
                else {
                     proxyFactory = null;
                }
                

                 

                So the issue is that proxyFactory is always null when an entity is not lazy, causing a NPE. Using the debugger, I made the following change to the code (using 'Change variable'):

                 

                if ( entityMetamodel.isLazy() ) {
                     proxyFactory = buildProxyFactory( mappingInfo, idGetter, idSetter );
                     if (proxyFactory == null) {
                          entityMetamodel.setLazy( false );
                     }
                }
                else {
                     proxyFactory = buildProxyFactory( mappingInfo, idGetter, idSetter );
                }
                

                 

                This fixes my issue. With this, I can retrieve history for objects which are not lazy, which always caused the NPE before.

                 

                I just basically did the dumbest thing that could work, and it worked. So my question is: might this have reprocussions? I'm not familiar with the inner workings of Hibernate. Could this change in the code have side effects, like a decrease in performance or failures of sorts?

                 

                This HHH-3854 issue has been a blocking bug for us, so I'd really like to use this fix until an official one comes along.

                 

                My next step will probably be to try and set up Hibernate in Eclipse, so I can compile a fixed version. Never used Maven before....

                • 5. Re: NPE when lazy=false in joined-subclass?
                  Robin G Newbie

                  Just wanted to update others with this issue (the 14 watchers of the Bug, for example), that changing that one line of code in Hibernate and compiling that with Maven did in fact fix this bug for me. So far, I have not noticed any negative consequences.