Quarkus: Hibernate Panache and Entity lifecycle

Created on 10 Mar 2019  路  12Comments  路  Source: quarkusio/quarkus

// programmer is transient and the method is @Transactional
programmer.language = Programmer.Language.Java;
programmer.status = Person.Status.Alive;
programmer.persist();

// now programmer is persistent and still not on the DB, the transaction is not flushed
programmer.language = Programmer.Language.C_Sharp;

When the method finish and transaction is commit I query the DB and found that language is Java and not C_Sharp as expected.

arepanache kinbug

Most helpful comment

Haha, that actually works.

All 12 comments

So it appears that Hibernate is not enhancing my generated accessors for dirty checking. Perhaps it has to do with them being TRANSIENT, I'm checking.

That's not it. I've also verified that it's running the Hibernate enhancer properly _after_ the Panache enhancer. It's like the Hibernate enhancer does not _see_ the generated accessors.

So, it turns out that bytebuddy will load entities from the classloader even if we pass it the bytes we want to enhance. That's pretty harsh.

@Sanne I believe this is a bug in Hibernate:

    @Override
    public byte[] enhance(String className, byte[] originalBytes) throws EnhancementException {
        //Classpool#describe does not accept '/' in the description name as it expects a class name. See HHH-12545
        final String safeClassName = className.replace( '/', '.' );
        try {
// HERE this is going to resolve the type not from the originalBytes but from the classloader
            final TypeDescription typeDescription = typePool.describe( safeClassName ).resolve();

            return byteBuddyState.rewrite( typePool, safeClassName, byteBuddy -> doEnhance(
                    byteBuddy.ignore( isDefaultFinalizer() ).redefine( typeDescription, ClassFileLocator.Simple.of( safeClassName, originalBytes ) ),
                    typeDescription
            ) );
        }
        catch (RuntimeException e) {
            throw new EnhancementException( "Failed to enhance class " + className, e );
        }
    }

Unless this is fixed in Hibernate I don't know how to work around it. I could perhaps fake a classloader we pass to the Hibernate enhancer context in order to use the byte[] for the type we're enhancing, but that feels really hackish. Naturally all those members are private so I can't reimplement this method outside the class to test how to fix it.

I can try to generate accessors that call the hibernate methods, but given that I don't have them yet I'm not sure it will work.

Haha, that actually works.

Fixed in #1691

awesome @FroMage , I was starting to look at the ORM angle but that's looking like a very though one.

Yeah, I figured. Go and accept my PR then ;)

I will soon :) having a bit of a build queue even locally..

Fixed now.

Was this page helpful?
0 / 5 - 0 ratings