UserType not recognised in version 6.5.x

Running a spring boot app which I recently updated from version 3.2.0 to 3.3.5 which updated Hibernate from version 6.3.1 to 6.5.3.
I have DB procedure (PostgreSQL)

create procedure some_procedure(IN data some_custom_db_type[])

custom type

create type some_custom_db_type as
(
    email             text,
    id bigint
);

Then in the app I have a JpaRepository with this method

@Procedure(procedureName = "some_procedure")
void callSomeProcedure(SomeCustomDbType[] data);

record

public record SomeCustomDbType(String email, Long id) implements Serializable {
}

custom UserType

public class SomeCustomDbTypeDefinition implements UserType<SomeCustomDbType[]> {

    public static final String TYPE_NAME = "some_custom_db_type";

    public static final SomeCustomDbTypeDefinition INSTANCE = new SomeCustomDbTypeDefinition();
    
    @Override
    public int getSqlType() {
        return SqlTypes.ARRAY;
    }

    @Override
    public Class<SomeCustomDbType[]> returnedClass() {
        return SomeCustomDbType[].class;
    }
...

custom type registration

public class CustomPostgresqlTypes implements TypeContributor {

    @Override
    public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
        typeContributions.contributeType(SomeCustomDbTypeDefinition.INSTANCE);
    }
}

and registration of CustomPostgresqlTypes in META-INF/services/org.hibernate.boot.model.TypeContributor

This approach worked just fine in version 6.3.1 but stopped working in version 6.5.3.

I tried to find what changed and found out there were some changes on BasicTypeRegistry class. Here’s a diff which causes the problem:

Tried to find the type using the the old approach

getRegisteredType( javaType.getName() );

instead of the new one

getRegisteredType( javaType.getTypeName() );

and it was found just fine.

Basically when the custom type is not found, the parameter is registered as a basic type and an exception is thrown

java.lang.ClassCastException: class [Lcom.db.custom.SomeCustomDbType; cannot be cast to class [B ([Lcom.db.custom.SomeCustomDbType; is in unnamed module of loader 'app'; [B is in module java.base of loader 'bootstrap')

	at org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType$1.doBind(VarbinaryJdbcType.java:100)
	at org.hibernate.type.descriptor.jdbc.BasicBinder.bind(BasicBinder.java:61)
	at org.hibernate.sql.exec.internal.AbstractJdbcParameter.bindParameterValue(AbstractJdbcParameter.java:130)
	at org.hibernate.sql.exec.internal.AbstractJdbcParameter.bindParameterValue(AbstractJdbcParameter.java:101)
	at org.hibernate.procedure.internal.ProcedureCallImpl.buildOutputs(ProcedureCallImpl.java:702)

Is there a problem with my approach in the first place so I was lucky it worked in the old version or is there some problem with the new one?

There is indeed a different for array Class objects between the getName() and getTypeName() methods, for example for String[].class we get

  • getName: [Ljava.lang.String;
  • getTypeName: java.lang.String[]

This might have been an oversight when refactoring the registration methods in the diff you’re showing. I would say this is a bug, so please try to create a simple reproducer test case and attach it to a new issue in our tracker.

I created a new issue as suggested.