Embeddable attributes set as dirty regardless of equality when using bytecode enhancements

Hello,
i am encountering an issue after enabling Hibernate bytecode enhancements in my project. In particular, the issue is related to dirty checking in embeddables.

In any given entity, if i set a new embeddable equivalent to the one currently set in the entity, the embedded attribute is set as dirty.
I checked the generated code for the write method, it seems that writing an embeddable indeed always sets the attribute as dirty, regardless of equality check. This is the generated code in Hibernate 6.6.7.Final as a reference:

public void $$_hibernate_write_artifact(ArtifactCoordinates var1) {
    if (this.artifact != null) {
        ManagedTypeHelper.asCompositeTracker(this.artifact).$$_hibernate_clearOwner("artifact");
    }

    if (!InlineDirtyCheckerEqualsHelper.areEquals(this, "artifact", var1, this.artifact)) {
        this.$$_hibernate_trackChange("artifact");
    }

    if (this.$$_hibernate_getInterceptor() != null) {
        this.artifact = (ArtifactCoordinates)this.$$_hibernate_getInterceptor().writeObject(this, "artifact", this.artifact, var1);
    } else {
        this.artifact = var1;
    }

    if (this.artifact != null) {
        ManagedTypeHelper.asCompositeTracker(this.artifact).$$_hibernate_setOwner("artifact", this);
    }

    this.$$_hibernate_trackChange("artifact");
}

I don’t understand why $$_hibernate_trackChange is always called at the end of the method, i expected to be called only in case of inequality (the second IF block).
My embeddables implement equals(), but are always flagged as dirty, so an update is triggered even if not necessary.

Can someone clarify this behavior?

Thanks.

1 Like

Hibernate ORM tracks managed state through a separate mechanism (loadedState in EntityEntry). This dirty checking code is just an “approximation” that should improve performance, so there should not be any correctness issue here, right?

I agree that unconditionally tracking the change is not really smart and in fact, the InlineDirtyCheckerEqualsHelper.areEquals call actually tries to make use of the equals implementation of the java type to avoid unnecessarily tracking changes. My suspicion is that this is a mistake due to the way org.hibernate.bytecode.enhance.internal.bytebuddy.InlineDirtyCheckingHandler#wrap is structured. CompositeFieldDirtyCheckingHandler seems to unconditionally track a change on method exit, though it shouldn’t do that when the InlineDirtyCheckingHandler is applied.

Please try to create a reproducer with our test case template and if you are able to reproduce the issue, create a bug ticket in our issue tracker and attach that reproducer.

Thank you for the clear response.

I have created the issue and the reproducer, i leave here the URL to the issue for reference:

The tests pass when the bytecode enhancement is disabled.

In addition to the original message, i have also found out that even setting a field in an embeddable to the same value as before marks it as dirty.

1 Like