hibernate/hibernate-orm · error · UnsupportedOperationException

Dialect does not support structured array types: ${dialectCl

Error message

Dialect does not support structured array types: ${dialectClassName}

What it means

AggregateComponentBinder assigns a SQL type code when a struct aggregate (an @Struct embeddable) is mapped as a plural attribute (array or collection). It maps a preferred array code of SqlTypes.ARRAY to STRUCT_ARRAY and SqlTypes.TABLE to STRUCT_TABLE; any other preferred code - most commonly SqlTypes.JSON, which dialects without native arrays (MySQL/MariaDB family) prefer - has no structured equivalent, so an UnsupportedOperationException naming the dialect class is thrown.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/boot/model/internal/AggregateComponentBinder.java:108

							componentClassDetails,
							inferredData.getPropertyName(),
							context
					)
			);
		}
	}

	private static <T> void registerDescriptor(Class<T> componentClass, TypeConfiguration typeConfiguration, String structName) {
		typeConfiguration.getJavaTypeRegistry()
				.resolveDescriptor( componentClass,
						() -> new EmbeddableAggregateJavaType<>( componentClass, structName ) );
	}

	private static int getStructPluralSqlTypeCode(MetadataBuildingContext context) {
		return switch ( context.getPreferredSqlTypeCodeForArray() ) {
			case SqlTypes.ARRAY -> SqlTypes.STRUCT_ARRAY;
			case SqlTypes.TABLE -> SqlTypes.STRUCT_TABLE;
			default -> throw new UnsupportedOperationException(
					"Dialect does not support structured array types: "
					+ context.getMetadataCollector().getDatabase()
							.getDialect().getClass().getName()
			);
		};
	}

	private static QualifiedName determineStructName(
			PropertyData inferredData,
			ClassDetails returnedClassOrElement,
			MetadataBuildingContext context) {
		final var memberDetails = inferredData.getAttributeMember();
		if ( memberDetails != null ) {
			final var struct = memberDetails.getDirectAnnotationUsage( Struct.class );
			if ( struct != null ) {
				return toQualifiedName( struct, context );
			}
		}

View on GitHub (pinned to fad1729dce)

Solutions

  1. Remove @Struct from the embeddable so elements are no longer bound to a structured SQL type
  2. Run against a database/dialect whose preferred array code is ARRAY (e.g. PostgreSQL, Oracle, DB2)
  3. Undo the JSON preference: remove the hibernate.type.preferred_array_jdbc_type setting or set it to ARRAY (SqlTypes.ARRAY) where struct arrays must work
  4. Remap the plural attribute as a plain basic array (e.g. List<String> or a JSON-mapped type) instead of an aggregate struct

Example fix

// before: struct aggregate inside a plural attribute on a JSON-array dialect
@Embeddable
@Struct(name = "address")
public class Address { ... }

@Entity
public class Customer {
    @Array                       // needs STRUCT_ARRAY/STRUCT_TABLE
    private List<Address> addresses;
}
// with hibernate.type.preferred_array_jdbc_type = JSON (or MySQL dialect) -> UnsupportedOperationException

// after: drop the struct binding, or target an ARRAY dialect
@Embeddable                     // no @Struct: stored as plain aggregate/JSON
public class Address { ... }

// or keep @Struct only when the dialect prefers SqlTypes.ARRAY (PostgreSQL etc.)
Defensive patterns

Strategy: validation

Validate before calling

// Before defining struct arrays: assert the effective array code supports structures
static boolean dialectSupportsStructArrays(Dialect dialect) {
    int code = dialect.getPreferredSqlTypeCodeForArray();
    return code == SqlTypes.ARRAY || code == SqlTypes.TABLE;
}

// In a test: fail fast with a clear message instead of a boot crash
Assume.assumeTrue("Dialect cannot store struct arrays",
        dialectSupportsStructArrays(actualDialect()));

Try / catch

try {
    sessionFactory = metadata.buildSessionFactory();
} catch (UnsupportedOperationException e) {
    if (e.getMessage().startsWith("Dialect does not support structured array types")) {
        throw new IllegalStateException("Struct aggregates in arrays are not usable with this database - "
                + "remove @Struct or switch the dialect", e);
    }
    throw e;
}

Prevention

When it happens

Trigger: Mapping List<StructEmbeddable> or @Array on a @Struct-annotated embeddable while the effective preferred array type code (dialect default, or hibernate.type.preferred_array_jdbc_type / MetadataBuilder.applyPreferredSqlTypeCodeForArray) is JSON or another non-ARRAY/TABLE code.

Common situations: Running the same mapping on PostgreSQL in production but MySQL/H2 in tests; setting a global preferred-array JSON setting for basic arrays and forgetting it also affects struct arrays; migrating from Hibernate 6 to 7 where structured array handling was tightened.

Related errors


AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22). Data as JSON: /api/errors/8e95c5fff09bdb41. Report an issue: GitHub.