Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to programmatically bind Hibernate Type for selected entity fields?

I'm looking a way to bind Type for specific entity fields during entity manager configuration phase. I need it to be able to apply extra "rules" to target entity field using external source without entity class changes.

So basically I'm trying to avoid hardcode @Type annotation way as below:

@Type(type = foo.package.MyType, parameters = {
    @Parameter(name = "fooProperty", value = "fooValue")
})
private String someField;

Instead I would like to set Type for someField while building model programmatically.

like image 798
user9440008 Avatar asked Apr 23 '19 11:04

user9440008


1 Answers

Here's one way I've seen before. It is a little low-level, so I suspect there is a cleaner way to do this.

This uses a custom Persister in Hibernate to allow us to substitute the type while the SessionFactory ( EntityManagerFactory ) is being created.

First, the @Persister annotation is used to declare the custom Persister :

@Entity
@Persister(impl = MyPersister.class)
public class EntityWithPersister {

    private String someField;

Then normally the custom persister should extend SingleTableEntityPersister in Hibernate. If the entity is using a different @Inheritance(strategy), then it may need to extend JoinedSubclassEntityPersister or UnionSubclassEntityPersister instead.

This offers the chance to change a type at the point of construction, for example:

public class MyPersister extends SingleTableEntityPersister {

    public MyPersister(PersistentClass persistentClass,
            EntityDataAccess cacheAccessStrategy,
            NaturalIdDataAccess naturalIdRegionAccessStrategy,
            PersisterCreationContext creationContext)
            throws HibernateException {
        super(modify(persistentClass), cacheAccessStrategy,
                naturalIdRegionAccessStrategy, creationContext);
    }

    private static PersistentClass modify(PersistentClass persistentClass) {
        SimpleValue value = (SimpleValue) persistentClass
                .getProperty("someField").getValue();
        value.setTypeName(MyType.class.getName());
        return persistentClass;
    }
}

If you need to access more of the context you are in, creationContext.getSessionFactory() is probably a good starting point.

like image 163
df778899 Avatar answered Sep 29 '22 01:09

df778899