Replacement for `hydrate` in Hibernate 6.1

I’m migrating Hibernate from 5.6.10 to 6.1.7 (as a part of Spring Boot 3 upgrade) and can’t seem to find a suitable replacement for the hydrate method for intercepting the Resultset and performing a custom unmarshalling (via extending SingleTableEntityPersister which ultimately extends AbstractEntityPersister)

It’s surprising that version 6.1.7 has kept the dehydrate method but not the hydrate method.

Thanks for any pointers.

Hibernate ORM 6 changed how types read/write data and the querying infrastructure, so there is not a simple migration possible. What is it that you want to customize? Chances are, you can easily do that by applying a custom converter or user type.

Thanks for replying. We want to decrypt/encrypt DB results containing some sensitive information and use them within the application.
The current approach we have (with hibernate 5) is to use a combination of @Persistent on entities that need to store some (or all) fields as encrypted with a custom implementation of SingleTableEntityPersister that leverages the hydrate() method to call our custom decryption logic.
Could you guide me as to how custom converters could be used for this purpose?

@saurabh it does indeed sound like you could use attribute converters for this purpose: you can mark the fields of your entities you wish to “encrypt” as @Convert, and implement your data manipulation login in an @AttributeConverter which will automatically encrypt the data before storing it to your database and decrypt it back when reading it.

You can find details and examples of attribute converter usage in Hibernate’s user guide.

@mbladel I tried using @Convert with @AttributeConverter but this doesn’t seem to work for my use case since I also need to know the column name (along with some other attributes of that column) to properly decrypt it. @ColumnTransformer won’t work either since we have a custom encryption/decryption logic.
Any other suggestions?

Use an AttributeConverter per configuration.

@beikov what does that mean? As stated above, I can’t use AttributeConverter because I need to have access to more than just the column value.

So this means you need multiple columns? If so, you will have to implement a CompositeUserType or EmbeddableInstantiator and represent your encrypted/decrypted data with a dedicated type. Hydration as a phase does not exist anymore, you can’t access multiple raw JDBC values at once and mutate data like before. You will have to wrap that logic into an embeddable.

Yep, we have multiple columns within the same entity that have encrypted information. How about implementing a custom Interceptor and leveraging it’s onLoad method?

I don’t know at which level you want/have to implement this, but you can also use @PostLoad lifecycle listeners if you like.

I’d like to implement it at the same level as the hydrate() method.

Currently, we’re making sure that by the time we hit @PostLoad the entity is already decrypted since hydrate() is invoked before that.

Not too sure how to get all the entity data + metadata in @PostLoad.
E.g. I’d like to know the column/field name along with the values and some other annotated stuff. Is that possible with @PostLoad?

I don’t have the code in front of me like you do, so it’s hard to say what is the best approach for you. I gave you enough options already, now try to implement them and see for yourself what works best. The closest you can get to the post-load lifecycle would be by using a CompositeUserType or EmbeddableInstantiator.

The issue with all these approaches is that every time there’s a slight modification in the entity, Hibernate marks the entity as dirty and tries to save it to the DB which we don’t want.
And that’s the reason we chose to use hydrate so that we could “transform” the entity before Hibernate started tracking the entity and so decrypting it won’t dirty it.

Is there any suitable replacement for hydrate which would work at the same level and allow us to modify the entity without making it dirty?

Not sure what you mean. If there is a modification of the state, Hibernate ORM must consider the entity dirty and flush state, that’s the whole point of an ORM.

Is there any suitable replacement for hydrate which would work at the same level and allow us to modify the entity without making it dirty?

You can transform state into “transient” fields, which are invisible to Hibernate ORM.

Refer to this post, where you recommended the use of hydrate. I’m looking for a replacement of the same without using transient fields.

The issue we had was that the act of decrypting was tracked as a change to the state of the entity, thus every load dirtied the object and translated into a write at the end of the transaction, whether anything changed or not.

We successfully used hydrate and dehydrate to perform the work transparently, intercepting the process of loading the ResultSets into the entities, so that by the time Hibernate started tracking state, the decryption was already done. This was a really nice and transparent solution for us, and it’s unfortunate to hear that functionality will be gone in 6.0.

Cluttering entities with dozens of Transient fields looks a lot like the ORM/encryption/decryption implementation leaking into the application code and getting in the way, rather than operating seamlessly and without modification to the entity classes as it does prior to v6.

If Hibernate had some other way of intercepting the load process, which could see the entire ResultSet row and the entirety of the entity the way @SingleTableEntityPersister used to, that would still satisfy the need, but making a Transient field for every other field is far from ideal. Even if we had to subclass and tweak some existing Hibernate class and then tell Hibernate to use our implementation instead of the default, that would work; we can handle tracking changes to parent classes between releases if we must.

That answer you’re referring to is from 2021 and was targeting Hibernate ORM 5. You’re asking about Hibernate ORM 6 here and I gave you an answer, but I’ll repeat it once more for you.
There is no direct replacement for hydrate, because the whole process of how data is read from JDBC and built into objects changed fundamentally.

If you don’t want to introduce transient fields in your entities, you can use an embeddable type to wrap the encrypted data e.g.

@Embeddable
public class EncryptedString {
    private String encryptedData;
    @Column(insertable = false, updatable = false)
    private String key;
    private transient String plainData;

    @PostLoad
    void init() {
        this.plainData = decrypt(encryptedData, key);
    }

    public void setPlainData(String data) {
        this.plainData = data;
        this.encryptedData = encrypt(data, key);
    }
}