NullPointerException in @Embeddable dirty tracking writer

Description

When the in-line dirty tracking bytecode enhancement is enabled (the enableDirtyTracking parameter of the hibernate-enhance-maven-plugin's configuration is true), and an entity with an @Embeddable property is constructed by setting this field to null in the constructor, a NullPointerException is thrown from the following location:

java.lang.NullPointerException at com.example.model.MyTestEntity.$$_hibernate_write_myTestEmbeddable(MyTestEntity.java) at com.example.model.MyTestEntity.<init>(MyTestEntity.java:37)

The interesting code snippets in the bytecode enhanced entity are as follows:

private MyTestEmbeddable myTestEmbeddable; @Transient private transient PersistentAttributeInterceptor $$_hibernate_attributeInterceptor; public MyTestEntity(Long id, Integer myTestInteger, MyTestEmbeddable myTestEmbeddable) { this.$$_hibernate_write_id(id); this.$$_hibernate_write_myTestInteger(myTestInteger); this.$$_hibernate_write_myTestEmbeddable(myTestEmbeddable); } public PersistentAttributeInterceptor $$_hibernate_getInterceptor() { return this.$$_hibernate_attributeInterceptor; } public void $$_hibernate_write_myTestEmbeddable(MyTestEmbeddable myTestEmbeddable) { // #1 if (this.myTestEmbeddable != null) { ((CompositeTracker)this.myTestEmbeddable).$$_hibernate_clearOwner("myTestEmbeddable"); } // #2 if (!EqualsHelper.areEqual((Object)this.myTestEmbeddable, (Object)myTestEmbeddable)) { this.$$_hibernate_trackChange("myTestEmbeddable"); } // #3 MyTestEmbeddable myTestEmbeddable2 = myTestEmbeddable; // #4 if (this.$$_hibernate_getInterceptor() != null) { myTestEmbeddable2 = (MyTestEmbeddable)this.$$_hibernate_getInterceptor().writeObject((Object)this, "myTestEmbeddable", (Object)this.myTestEmbeddable, (Object)myTestEmbeddable); } // #5 this.myTestEmbeddable = myTestEmbeddable2; // #6 Object var4_3 = null; // #7 ((CompositeTracker)this.myTestEmbeddable).$$_hibernate_setOwner("myTestEmbeddable", (CompositeOwner)this); // #8 this.$$_hibernate_trackChange("myTestEmbeddable"); }

The myTestEmbeddable argument of the constructor is null, so $$_hibernate_write_myTestEmbeddable() is called with a null argument. The $$_hibernate_attributeInterceptor field is not initialized in the constructor, so $$_hibernate_getInterceptor() always returns null. Because of this, the conditional code #4 is not run. In #3, the null argument is written to a temporary variable, and then in #5, it's written to the myTestEmbeddable field. Afterwards in #7, it's being cast to CompositeTracker, and its $$_hibernate_setOwner is called, while the field is still null. I think this is what throws the NullPointerException.

The Java source files of the original and bytecode enhanced @Entity and @Embeddable classes are attached to this ticket.

The hibernate-enhance-maven-plugin configuration was as follows:

<configuration> <enableLazyInitialization>true</enableLazyInitialization> <enableDirtyTracking>true</enableDirtyTracking> <enableAssociationManagement>false</enableAssociationManagement> <enableExtendedEnhancement>false</enableExtendedEnhancement> </configuration>

The description above is valid for Hibernate 5.0.8, but the same NullPointerException occurs when using Hibernate 5.1.0.

Attachments

4
  • 22 Feb 2016, 03:46 PM
  • 22 Feb 2016, 03:46 PM
  • 22 Feb 2016, 03:46 PM
  • 22 Feb 2016, 03:46 PM

Activity

Steve EbersoleFebruary 26, 2016 at 5:57 PM

Applied Luis' PR. Please give that a try Gabor.

Luis BarreiroFebruary 23, 2016 at 12:12 AM

Hi ,

First, thanks for the detailed description of the issue. Very helpful!

In fact, following your description of the generated bytecode, #7 should have a null check pretty much like #1

I opened a pull request with a fix and test case: https://github.com/hibernate/hibernate-orm/pull/1273

Fixed

Details

Assignee

Reporter

Labels

Components

Fix versions

Affects versions

Priority

Created February 22, 2016 at 3:49 PM
Updated March 15, 2016 at 2:10 AM
Resolved February 26, 2016 at 5:57 PM

Flag notifications