PostgreSQL array of enums does not work with @JdbcType(PostgreSQLEnumJdbcType.class) but works with @Enumerated + @ColumnTransformer

Hi,

I’m trying to map a PostgreSQL array of enum values to a Java Enum[] (or List<Enum>) using Hibernate.

I have a PostgreSQL enum type:

CREATE TYPE "SOME"."ITEMS_TYPE" AS ENUM ('A', 'B', 'C');

And a column defined as:

items ITEMS_TYPE[]

What does NOT work

Using PostgreSQLEnumJdbcType together with SqlTypes.ARRAY does not work:

@JdbcTypeCode(SqlTypes.ARRAY)
@JdbcType(PostgreSQLEnumJdbcType.class)
private ItemsType[] items;

This fails at runtime (binding / type resolution issues).

What DOES work

The following mapping works correctly:

@JdbcTypeCode(SqlTypes.ARRAY)
@Enumerated(EnumType.STRING)
@ColumnTransformer(write = "?::\"SOME\".\"ITEMS_TYPE\"[]")
private ItemsType[] items;

Question

Is this a known limitation of PostgreSQLEnumJdbcType when used with SQL arrays?

  • Is PostgreSQLEnumJdbcType intended to be used only for single enum values, not arrays?

  • Is there a recommended or “official” way in Hibernate to map PostgreSQL enum arrays without relying on @ColumnTransformer?

  • Should a custom JdbcType or UserType be used instead?

Any guidance or clarification would be appreciated.

Sandbox to play around:
GitHub - pavlobalandin/hibernateissue
see: SomeRepositoryITest and AnotherRepositoryITest

Thanks a lot!

2 Likes

Hi. Did you look for reported issues? I don’t know if it’s valid, but this one looks very similar: Jira

Also you might want to clarify what you mean by “does not work”, i.e. what are the symptoms exactly.

Technically there’s an exception and application is not being able to start at all:

Caused by: java.lang.ClassCastException: class org.hibernate.type.internal.ParameterizedTypeImpl cannot be cast to class java.lang.Class (org.hibernate.type.internal.ParameterizedTypeImpl is in unnamed module of loader 'app'; java.lang.Class is in module java.base of loader 'bootstrap')
	at org.hibernate.dialect.type.PostgreSQLEnumJdbcType.getJdbcLiteralFormatter(PostgreSQLEnumJdbcType.java:68) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.type.AbstractStandardBasicType.<init>(AbstractStandardBasicType.java:62) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.type.AbstractSingleColumnStandardBasicType.<init>(AbstractSingleColumnStandardBasicType.java:25) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.type.internal.BasicTypeImpl.<init>(BasicTypeImpl.java:27) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.type.BasicTypeRegistry.resolvedType(BasicTypeRegistry.java:167) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.type.BasicTypeRegistry.lambda$resolve$0(BasicTypeRegistry.java:157) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.type.BasicTypeRegistry.createIfUnregistered(BasicTypeRegistry.java:278) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.type.BasicTypeRegistry.resolve(BasicTypeRegistry.java:249) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.type.BasicTypeRegistry.resolve(BasicTypeRegistry.java:157) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.boot.model.process.internal.InferredBasicValueResolver.from(InferredBasicValueResolver.java:135) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.mapping.BasicValue.resolution(BasicValue.java:643) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.mapping.BasicValue.buildResolution(BasicValue.java:447) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.mapping.BasicValue.buildResolution(BasicValue.java:421) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.mapping.BasicValue.resolve(BasicValue.java:338) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.mapping.BasicValue.resolve(BasicValue.java:328) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.lambda$processValueResolvers$0(InFlightMetadataCollectorImpl.java:1760) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at java.base/java.util.ArrayList.removeIf(ArrayList.java:1773) ~[na:na]
	at java.base/java.util.ArrayList.removeIf(ArrayList.java:1751) ~[na:na]
	at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processValueResolvers(InFlightMetadataCollectorImpl.java:1760) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1749) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.coordinateProcessors(MetadataBuildingProcess.java:330) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:199) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.metadata(EntityManagerFactoryBuilderImpl.java:1392) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.populateSessionFactoryBuilder(EntityManagerFactoryBuilderImpl.java:1472) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl.build(EntityManagerFactoryBuilderImpl.java:1454) ~[hibernate-core-7.2.1.Final.jar:7.2.1.Final]
	at org.springframework.orm.jpa.vendor.SpringHibernateJpaPersistenceProvider.createContainerEntityManagerFactory(SpringHibernateJpaPersistenceProvider.java:66) ~[spring-orm-7.0.3.jar:7.0.3]
	at org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.createNativeEntityManagerFactory(LocalContainerEntityManagerFactoryBean.java:433) ~[spring-orm-7.0.3.jar:7.0.3]
	at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.buildNativeEntityManagerFactory(AbstractEntityManagerFactoryBean.java:416) ~[spring-orm-7.0.3.jar:7.0.3]

I use version 7.2 but looks pretty similar to the one you mentioned above.