Persisting a custom UUID class as a VARCHAR


#1

Hi guys, I’m currently trying to integrate Hibernate into my existing app to persist my game-state to a database.
Currently I’m stuck on defining a database SQL-Type for a custom class of mine.
In this case I have a class called “com.leo.commons.utils.UUID” and I want to persist every UUID to the database as a varchar(255).
Is there a way to do this? I already have a UUIDConverter that looks like this:

@Converter(autoApply = true)
public class UUIDConverter implements AttributeConverter<UUID, String> {
    @Override
    public String convertToDatabaseColumn(UUID uuid) {
        return uuid.toString();
    }

    @Override
    public UUID convertToEntityAttribute(String dbData) {
        return new UUID(dbData);
    }
}

My Entity looks like this:

@Entity
public class SphDatabaseEntity {
    @Id
    private UUID id;

    ....
}

When adding “@Column(columnDefinition = “varchar(255)”)” to the ID it seems to register the Type correctly, however I would need to add this line to every UUID in my code and I want to define it for every UUID in one place to avoid copy-pasting.

After some time debugging through the Hibernate-Implementation I found the place that seems to be responsible for determining the Hibernate-Type (which is then translated to the sqlType later): org.hibernate.type.TypeFactory#byClass

However the Type here can only be defined by extending the UUID with the “org.hibernate.type.Type”-class. This is not possible for me because “com.leo.commons.utils.UUID” does not know about hibernate and I would need to add the dependency to the project, which I want to avoid since this project has nothing to do with the persistence layer.

Currently when starting my app I get greeted with this dialog:
Could not determine type for: com.leo.commons.utils.UUID, at table: SphDatabaseEntity, for columns: [org.hibernate.mapping.Column(id)]

What other options do I have? Using “private String id” instead and creating the UUID in my buisness-code would be an option but I hope that there is another way that I just missed.

Would appreciate you advice :slight_smile:

PS: If there is documentation to this that I missed please link me to it. Everything google is giving me are articles on how to do it with Spring Boot… :frowning:


#2

Instead of using a UUIDConverter, you could create a Hibernate custom Type instead and register that with Hibernate.

Check out this article for an example. Basically, you will have to provide the following @TypeDef after you created your custom UUIDType:

@TypeDef(
	name = "custom-uuid", 
	typeClass = CustomUUIDType.class, 
	defaultForType = com.leo.commons.utils.UUID.class
)

And then you don’t really need to do anything in the UUID entity property mapping.


#3

Worked like a charm, thank you! :slight_smile:


#4

The intended way is to register a custom org.hibernate.type.descriptor.java.JavaTypeDescriptor with the JavaTypeDescriptorRegistry. Then the AttributeConverter would simply work.

The JavaTypeDescriptorRegistry can be accessed from the org.hibernate.type.spi.TypeConfiguration which in turn can be accessed via:

  1. org.hibernate.boot.internal.BootstrapContextImpl#getTypeConfiguration
  2. SessionFactoryImplementor#getMetamodel -> MetamodelImplementor#getTypeConfiguration
  3. org.hibernate.boot.spi.MetadataImplementor#getTypeConfiguration

depending on where you are in the SessionFactory lifecycle.

The easiest way to register JavaTypeDescriptor (or other type system extensions) is a custom org.hibernate.boot.model.TypeContributor implementation which Hibernate will discover using Java’s standard ServiceLoader mechanism.


#5

That’s a great tip. I will add a Jira issue to document this scenario as well.


#6

Just be sure to notate it as incubating. This changes quite a bit in 6.0. In fact we backported the TypeConfiguration stuff from 6.0 to 5.x, but had to adapt it to things in 5.x that we decided should not change before a major release (6.0).


#7

I added HHH-12987 and marked it for 6.0.