Is there a way to override UUID binary length from 255 to 16 globally in a spring-boot project?

Viewed 986

I want to use binary UUID in a MariaDB database used for a spring-boot project, instead of using varchar uuid. For now, I am able to create, save and search a binary UUID, by override the column length to 16 but I have to manually put the annotation @Column(length=16) on any UUID field.

Is there a way to globally made this modification in the project ? In other words, is there a way that, for all UUID field in the project, jpa/hibernate create a column "binary(16)" instead of "binary(255)" ?

My problem is that, by default, an UUID is converted into a binary(255) into MariaDB, and with this configuration, JPA Repositories queries are not able to find any data when searching on a UUID field.

To achieve Jpa repositories queries, I have to add the @Column(length=16) on any UUID field.

I have tried to use a "@Converter" but the Convert annotation should not be used to specify conversion of the following: Id attributes, version attributes, relationship attributes etc... And it doesn't work with an uuid relationship field.

I have also tried to use my own custom hibernate type (example here : https://www.maxenglander.com/2017/09/01/optimized-uuid-with-hibernate.html) but the jpa repositories queries don't find anything.

Now i have this : My abstract entity :

public abstract class GenericEntity {

    @Id
    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2", strategy = "org.hibernate.id.UUIDGenerator")
    @Column(length = 16)
    private UUID id;

    //...
}

When using an uuid in another object :

public abstract class AnotherEntity extends GenericEntity {
    @NotNull
    @Column(length = 16)
    private UUID owner;
    //...
}

I'm looking for a way to override the UUID field generation without putting the "@Column(length = 16)" everywhere.

It would be really great to avoid errors and / or omissions when using the UUID type in others features.

Thanks a lot !

1 Answers

The type descriptor, remapping the binary implementation onto OTHER Hibernate typedef:

import java.sql.Types;
import java.util.UUID;

import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
import org.hibernate.type.descriptor.sql.BinaryTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;

public class MariaDBUuidTypeDescriptor extends BinaryTypeDescriptor {

    private static final long serialVersionUID = 1L;

    public static final MariaDBUuidTypeDescriptor INSTANCE = new MariaDBUuidTypeDescriptor();

    public MariaDBUuidTypeDescriptor() {
        super();
    }

    @Override
    public int getSqlType() {
        return Types.OTHER;
    }
    
    @Override
    @SuppressWarnings("unchecked")
    public BasicJavaDescriptor<UUID> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
        return (BasicJavaDescriptor<UUID>) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( UUID.class );
    }
}

The type itself, wrapping the descriptor above and binding it to the UUID classdef.

import java.util.UUID;

import org.hibernate.type.AbstractSingleColumnStandardBasicType;
import org.hibernate.type.descriptor.java.UUIDTypeDescriptor;

public class MariaDBUuidType extends AbstractSingleColumnStandardBasicType<UUID> {

    private static final long serialVersionUID = 1L;

    public static final MariaDBUuidType INSTANCE = new MariaDBUuidType();

    public MariaDBUuidType() {
        super( MariaDBUuidTypeDescriptor.INSTANCE, UUIDTypeDescriptor.INSTANCE );
    }

    @Override
    public String getName() {
        return "mariadb-uuid-binary";
    }

    @Override
    protected boolean registerUnderJavaType() {
        return true;
    }
}

The modified Hibernate dialect, making use of the type and remapping all its occurrences onto binary(16)

import java.sql.Types;

import org.hibernate.HibernateException;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.dialect.MariaDB103Dialect;
import org.hibernate.service.ServiceRegistry;

public class MariaDB103UuidAwareDialect extends MariaDB103Dialect {

    @Override
    public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
        super.contributeTypes( typeContributions, serviceRegistry );

        registerColumnType( Types.OTHER, "uuid" );
        typeContributions.contributeType( MariaDBUuidType.INSTANCE );
    }

    @Override
    public String getTypeName(int code, long length, int precision, int scale) throws HibernateException {
        String typeName = super.getTypeName(code, length, precision, scale);
        if (Types.OTHER == code && "uuid".equals(typeName)) {
            return "binary(16)";
        } else {
            return typeName;
        }
    }
}

Please note that this is Hibernale-only implementation, i.e. does not matter if you use it along Spring (Boot) or not.

Related