hibernate/hibernate-orm · error · IllegalArgumentException
not a BasicPluralJavaType
Error message
not a BasicPluralJavaType
What it means
ArrayJdbcType (and dialect subclasses such as OracleArrayJdbcType) derives the element Java type from the domain descriptor via the static elementJavaType() helper. That helper accepts only the Byte[]/byte[] special cases and descriptors implementing BasicPluralJavaType; anything else throws IllegalArgumentException('not a BasicPluralJavaType'). The message signals that the domain Java type and the array JDBC type disagree - the domain type is not perceived as an array/collection.
Source
Thrown at hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/ArrayJdbcType.java:93
final var parameterizedType =
new ParameterizedTypeImpl( javaType.getJavaTypeClass(),
new Type[0], null );
return javaType.createJavaType( parameterizedType, typeConfiguration );
}
}
protected static JavaType<?> elementJavaType(JavaType<?> javaTypeDescriptor) {
if ( javaTypeDescriptor instanceof ByteArrayJavaType
|| javaTypeDescriptor instanceof PrimitiveByteArrayJavaType ) {
// Special handling needed for Byte[] and byte[],
// because that would conflict with the VARBINARY mapping
return ByteJavaType.INSTANCE;
}
else if ( javaTypeDescriptor instanceof BasicPluralJavaType<?> basicPluralJavaType ) {
return basicPluralJavaType.getElementJavaType();
}
else {
throw new IllegalArgumentException("not a BasicPluralJavaType");
}
}
@Override
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaTypeDescriptor) {
return new JdbcLiteralFormatterArray<>( javaTypeDescriptor,
elementJdbcType.getJdbcLiteralFormatter( elementJavaType( javaTypeDescriptor ) ) );
}
@Override
public Class<?> getPreferredJavaTypeClass(WrapperOptions options) {
return Object[].class;
}
protected String getElementTypeName(JavaType<?> javaType, SharedSessionContractImplementor session) {
// TODO: ideally, we would have the actual size or the actual type/column accessible
// this is something that we would need for supporting composite types anyway
if ( elementJdbcType instanceof StructuredJdbcType structJdbcType ) {View on GitHub (pinned to fad1729dce)
Solutions
- Make the custom descriptor implement BasicPluralJavaType<T> and return the element type from getElementJavaType().
- Fix the mapping: use array JDBC types only for array/collection attributes (@JdbcTypeCode(SqlTypes.ARRAY) or @Array), keep scalars on scalar JDBC types.
- For byte[]/Byte[]-backed types, ensure the registered descriptors are PrimitiveByteArrayJavaType/ByteArrayJavaType so the special case applies.
Example fix
// before: custom descriptor is not plural-aware
public class IntListJavaType extends AbstractJavaType<IntList> {
public IntListJavaType() { super(IntList.class); }
}
// binding/literal rendering -> IllegalArgumentException: not a BasicPluralJavaType
// after: implement BasicPluralJavaType so the element type is derivable
public class IntListJavaType extends AbstractJavaType<IntList> implements BasicPluralJavaType<IntList> {
public IntListJavaType() { super(IntList.class); }
@Override public JavaType<Integer> getElementJavaType() { return IntegerJavaType.INSTANCE; }
} Defensive patterns
Strategy: type-guard
Validate before calling
// Before registering/binding with an array JdbcType, check the descriptor
JavaType<?> jt = typeConfiguration.getJavaTypeRegistry().findDescriptor(MyList.class);
if (!(jt instanceof BasicPluralJavaType<?>)
&& !(jt instanceof ByteArrayJavaType)
&& !(jt instanceof PrimitiveByteArrayJavaType)) {
throw new IllegalStateException(
"ArrayJdbcType needs a BasicPluralJavaType descriptor; got " + jt.getClass().getName());
} Type guard
static boolean supportsArrayJdbcType(JavaType<?> jt) {
return jt instanceof BasicPluralJavaType<?>
|| jt instanceof ByteArrayJavaType
|| jt instanceof PrimitiveByteArrayJavaType;
} Try / catch
try {
return arrayJdbcType.getJdbcLiteralFormatter(domainJavaType);
} catch (IllegalArgumentException e) {
if ("not a BasicPluralJavaType".equals(e.getMessage())) {
// domain descriptor must implement BasicPluralJavaType and expose its element type
} else {
throw e;
}
} Prevention
- Implement BasicPluralJavaType on every custom array-like JavaType
- Use @JdbcTypeCode(SqlTypes.ARRAY) only on collection/array attributes
- Add an integration test that binds and inlines a literal for each custom array type
When it happens
Trigger: Calling ArrayJdbcType.getJdbcLiteralFormatter(...) - reached when Hibernate inlines an array literal into HQL/criteria SQL - or getElementTypeName(...) - reached when creating a java.sql.Array during binding - with a domain JavaType that is neither byte[]/Byte[] nor a BasicPluralJavaType. Typically a custom JavaType for an array-like type that does not implement BasicPluralJavaType, or an array JdbcType mapped onto a scalar attribute.
Common situations: Custom JavaType implementations for array-backed domain types that forget to implement BasicPluralJavaType; @JdbcType naming an array type while the attribute is a scalar; dialect/Hibernate upgrades that made this previously lenient path throw.
Related errors
- JDBC driver does not support named parameters for setArray.
- Configuration property hibernate.jdbc.time_zone value [{}] i
- Error processing @TypeBinderType annotation '%s' for embedda
- Error processing @TypeBinderType annotation '%s' for entity
- error processing @AttributeBinderType annotation '%s' for at
AI-assisted analysis of hibernate/hibernate-orm@fad1729dce (2026-08-22).
Data as JSON: /api/errors/8ad4d0e23fe28dce.
Report an issue: GitHub.