-->
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.  [ 5 posts ] 
Author Message
 Post subject: NullPointerEx on flush after upgrading to Hibernate 4.1.3
PostPosted: Mon May 14, 2012 12:55 pm 
Newbie

Joined: Tue May 08, 2012 2:56 am
Posts: 3
Hi,

I have just completed an upgrade from Hibernate 3.6 to 4.1.3 Final and at first everything seemed to go fine. However, one of my colleagues recently tested this an in one scenario he gets a NullPointer being thrown from within Hibernate (and this exception was not being thrown before we upgraded for the exact same DB). It is an incredibly strange scenario. We have an entity called BlogPost that looks like the below and it extends some mapped superclasses (that I have also included):

Code:
@Entity
@Table(name = "blog_post")
public class BlogPost extends CommunityModelObject implements HasFeedPost {

    @Lob
    private String title;
    @Lob
    private String content;
    @Enumerated
    @Column(nullable = false)
    private CBlogPost.Status status = CBlogPost.Status.UNPUBLISHED;
    // Reference to the feed post that indicates that this blog post has been published
    @OneToOne
    @JoinColumn(name = "feed_post_id")
    private FeedPost feedPost;
    @ManyToOne
    @JoinColumn(name = "posted_by_employee_id")
    private Employee postedBy;
   
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public CBlogPost.Status getStatus() {
        return status;
    }

    public void setStatus(CBlogPost.Status status) {
        this.status = status;
    }

    @Override
    public FeedPost getFeedPost() {
        return feedPost;
    }

    @Override
    public void setFeedPost(FeedPost feedPost) {
        this.feedPost = feedPost;
    }

    public Employee getPostedBy() {
        return postedBy;
    }

    public void setPostedBy(Employee postedBy) {
        this.postedBy = postedBy;
    }
}


Code:
@Filter(name = "tenantFilter", condition = "(tenant_id = :tenantId or tenant_id is null)")
@MappedSuperclass
public abstract class CommunityModelObject extends ModelObject {

    @IndexedEmbedded(prefix = "tenant", indexNullAs = IndexedEmbedded.DEFAULT_NULL_TOKEN)
    @ManyToOne
    @JoinColumn(name = "tenant_id")
    protected Tenant tenant;

    public Tenant getTenant() {
        return tenant;
    }

    public void setTenant(Tenant tenant) {
        this.tenant = tenant;
    }

    /**
     * If the Tenant is null then it can be accessed / viewed by the entire "community" / user base
     */
    public boolean isCommunityObject() {
        return tenant == null;
    }
}


Code:
@MappedSuperclass
public abstract class ModelObject extends BaseModelObject {

    @Id
    @GeneratedValue
    private Long id;

    @Override
    public long getId() {
        return (id == null ? 0 : id);
    }

    public void setId(long id) {
        this.id = (id == 0 ? null : id);
    }
}


Code:
@MappedSuperclass
public abstract class BaseModelObject implements java.io.Serializable {

    // This annotation ensures that a column is not associated with this member (simply omitting the @Column annotation is not enough since
    // that annotation is completely optional)
    @Transient
    private boolean doNotAutoUpdateDateUpdated = false;

    @Version
    protected int version;
    @Column(name = "date_created")
    protected Date dateCreated;
    @Column(name = "date_updated")
    protected Date dateUpdated;

    public abstract long getId();

    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }

    public Date getDateCreated() {
        return dateCreated;
    }

    public Date getDateUpdated() {
        return dateUpdated;
    }

    /**
     * This will set the dateUpdated to whatever is passed through and it will cause the auto update (pre-update) to NOT occur
     *
     * @param dateUpdated
     */
    public void setDateUpdated(Date dateUpdated) {
        doNotAutoUpdateDateUpdated = true;
        this.dateUpdated = dateUpdated;
    }

    public void touch() {
        // By setting date updated to null this triggers an update which results in onUpdate being called and the nett
        // result is dateUpdated = new Date()
        dateUpdated = null;
    }

    @PrePersist
    protected void onCreate() {
        dateCreated = new Date();
    }

    @PreUpdate
    protected void onUpdate() {
        if (!doNotAutoUpdateDateUpdated) {
            dateUpdated = new Date();
        }
    }

    @Override
    public boolean equals(Object obj) {
        long id = getId();

        if (id == 0) {
            return this == obj;
        }
        //Use Hibernate.getClass() because objects might be proxies
        return obj != null &&
                obj instanceof BaseModelObject &&
                Hibernate.getClass(this) == Hibernate.getClass(obj) &&
                getId() == ((BaseModelObject)obj).getId();
    }

    @Override
    public int hashCode() {
        Long id = getId();
        return id == 0 ? super.hashCode() : id.intValue();
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() + "-" + getId();
    }
}


The strangest thing is happening when I query BlogPost in some scenarios. If I run the query below, for example, in isolation then it works fine but if I run it in amongst a bunch of other queries then I get the exception below:

Code:
select b from BlogPost b


Code:
java.lang.NullPointerException
   at org.hibernate.event.internal.DefaultFlushEntityEventListener.isUpdateNecessary(DefaultFlushEntityEventListener.java:240)
   at org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:163)
   at org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:225)
   at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:99)
   at org.hibernate.event.internal.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:55)
   at org.hibernate.internal.SessionImpl.autoFlushIfRequired(SessionImpl.java:1153)
   at org.hibernate.internal.SessionImpl.list(SessionImpl.java:1208)
   at org.hibernate.internal.QueryImpl.list(QueryImpl.java:101)
   at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:256)


Now the kicker is that if I take all of the fields from all of the mapped superclasses that I listed above and put them directly into BlogPost and make BlogPost just extend nothing and implement java.io.Serializable then everything works perfectly. This leads me to believe that the bug is either related to mapped superclasses or the Hibernate filter that I am applying to CommunityModelObject.

Any ideas? This is causing major issues for us since we need to upgrade asap in order to upgrade Hibernate Search which we need to do for a critical bug fix.

Also note that the DB we are using is MySQL with the following custom dialect that I wrote when doing this upgrade to handle our BIT columns:

Code:
public class MySQL5InnoDBDialectExt extends MySQL5InnoDBDialect {

    private static final String BIT_STRING = "bit";

    public MySQL5InnoDBDialectExt() {
        super();
        registerColumnType(Types.BOOLEAN, BIT_STRING);
    }
}


Thanks,
Brent


Top
 Profile  
 
 Post subject: Re: NullPointerEx on flush after upgrading to Hibernate 4.1.3
PostPosted: Tue May 15, 2012 3:00 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Code:
239:               if ( event.getEntityEntry().getPersister().getInstrumentationMetadata().isInstrumented() ) {
240:               event.getEntityEntry()
241:                     .getPersister()
242:                     .getInstrumentationMetadata()
243:                     .extractInterceptor( event.getEntity() )
244:                     .clearDirty();
245:             }


Although the stacktrace is accusing DefaultFlushEntityEventListener.java line 240 for the NPE,
the actual NPE was in line 244, otherwise it had already been thrown in line 239.
This means that extractInterceptor( event.getEntity() ) on line 243 returned null,
so there must be a problem in extracting the interceptor for that particular entity...


Top
 Profile  
 
 Post subject: Re: NullPointerEx on flush after upgrading to Hibernate 4.1.3
PostPosted: Tue May 15, 2012 3:05 am 
Newbie

Joined: Tue May 08, 2012 2:56 am
Posts: 3
Ok thanks for the response. Forgive my ignorance, but what exactly does that mean? Is there something incorrect in the way I have defined the entity? What could the cause be and is their a known workaround?


Top
 Profile  
 
 Post subject: Re: NullPointerEx on flush after upgrading to Hibernate 4.1.3
PostPosted: Tue May 15, 2012 3:21 am 
Expert
Expert

Joined: Tue Jun 16, 2009 3:36 am
Posts: 990
Unfortunately I have no experience with interceptors as I never used that feature.
Anyway I suggest you to download hibernate sources and then debug into method extractInterceptor,
maybe debugging you see the reason why the method returns a null.
Another approach could be enable logging by putting a higher level (debug or trace),
maybe these loggings give some useful hints.


Top
 Profile  
 
 Post subject: Re: NullPointerEx on flush after upgrading to Hibernate 4.1.3
PostPosted: Tue May 15, 2012 12:40 pm 
Newbie

Joined: Tue May 08, 2012 2:56 am
Posts: 3
I found the issue. It does not seem to be related to interceptors, rather to either caching or instrumentation. Basically our app automatically includes all entities within a very specific package in our caching scheme and the same classes in our instrumentation. We generally have all of our entities in this package, however this one which was causing the issue was the only one not included in this package. The previous version of EhCache / Hibernate that we were using seemed ok with this, but after upgrading it caused issues.

Anyway, the entity was in the incorrect package, when I refactored it and moved it into the correct package then everything worked! So it was not a bug in Hibernate, just an informative exception that made it difficult to track this issue down (I basically solved it by complete fluke).


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