{"record":{"id":"8ad4d0e23fe28dce","repo":"hibernate/hibernate-orm","slug":"not-a-basicpluraljavatype","errorCode":null,"errorMessage":"not a BasicPluralJavaType","messagePattern":"not a BasicPluralJavaType","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/ArrayJdbcType.java","lineNumber":93,"sourceCode":"\t\t\tfinal var parameterizedType =\n\t\t\t\t\tnew ParameterizedTypeImpl( javaType.getJavaTypeClass(),\n\t\t\t\t\t\t\tnew Type[0], null );\n\t\t\treturn javaType.createJavaType( parameterizedType, typeConfiguration );\n\t\t}\n\t}\n\n\tprotected static JavaType<?> elementJavaType(JavaType<?> javaTypeDescriptor) {\n\t\tif ( javaTypeDescriptor instanceof ByteArrayJavaType\n\t\t\t|| javaTypeDescriptor instanceof PrimitiveByteArrayJavaType ) {\n\t\t\t// Special handling needed for Byte[] and byte[],\n\t\t\t// because that would conflict with the VARBINARY mapping\n\t\t\treturn ByteJavaType.INSTANCE;\n\t\t}\n\t\telse if ( javaTypeDescriptor instanceof BasicPluralJavaType<?> basicPluralJavaType ) {\n\t\t\treturn basicPluralJavaType.getElementJavaType();\n\t\t}\n\t\telse {\n\t\t\tthrow new IllegalArgumentException(\"not a BasicPluralJavaType\");\n\t\t}\n\t}\n\n\t@Override\n\tpublic <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaTypeDescriptor) {\n\t\treturn new JdbcLiteralFormatterArray<>( javaTypeDescriptor,\n\t\t\t\telementJdbcType.getJdbcLiteralFormatter( elementJavaType( javaTypeDescriptor ) ) );\n\t}\n\n\t@Override\n\tpublic Class<?> getPreferredJavaTypeClass(WrapperOptions options) {\n\t\treturn Object[].class;\n\t}\n\n\tprotected String getElementTypeName(JavaType<?> javaType, SharedSessionContractImplementor session) {\n\t\t// TODO: ideally, we would have the actual size or the actual type/column accessible\n\t\t//       this is something that we would need for supporting composite types anyway\n\t\tif ( elementJdbcType instanceof StructuredJdbcType structJdbcType ) {","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/ArrayJdbcType.java#L75-L111","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: custom descriptor is not plural-aware\npublic class IntListJavaType extends AbstractJavaType<IntList> {\n    public IntListJavaType() { super(IntList.class); }\n}\n// binding/literal rendering -> IllegalArgumentException: not a BasicPluralJavaType\n\n// after: implement BasicPluralJavaType so the element type is derivable\npublic class IntListJavaType extends AbstractJavaType<IntList> implements BasicPluralJavaType<IntList> {\n    public IntListJavaType() { super(IntList.class); }\n    @Override public JavaType<Integer> getElementJavaType() { return IntegerJavaType.INSTANCE; }\n}","handlingStrategy":"type-guard","validationCode":"// Before registering/binding with an array JdbcType, check the descriptor\nJavaType<?> jt = typeConfiguration.getJavaTypeRegistry().findDescriptor(MyList.class);\nif (!(jt instanceof BasicPluralJavaType<?>)\n        && !(jt instanceof ByteArrayJavaType)\n        && !(jt instanceof PrimitiveByteArrayJavaType)) {\n    throw new IllegalStateException(\n        \"ArrayJdbcType needs a BasicPluralJavaType descriptor; got \" + jt.getClass().getName());\n}","typeGuard":"static boolean supportsArrayJdbcType(JavaType<?> jt) {\n    return jt instanceof BasicPluralJavaType<?>\n        || jt instanceof ByteArrayJavaType\n        || jt instanceof PrimitiveByteArrayJavaType;\n}","tryCatchPattern":"try {\n    return arrayJdbcType.getJdbcLiteralFormatter(domainJavaType);\n} catch (IllegalArgumentException e) {\n    if (\"not a BasicPluralJavaType\".equals(e.getMessage())) {\n        // domain descriptor must implement BasicPluralJavaType and expose its element type\n    } else {\n        throw e;\n    }\n}","preventionTips":["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"],"tags":["hibernate","array-mapping","java-type-descriptor","jdbc","custom-type"],"backgroundTag":"array-type-mapping-error","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}