{"record":{"id":"9132386689867d75","repo":"hibernate/hibernate-orm","slug":"collectionpersister-used-for-does-not-support","errorCode":null,"errorMessage":"CollectionPersister used for [{}] does not support SQL AST","messagePattern":"CollectionPersister used for \\[(.+?)\\] does not support SQL AST","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java","lineNumber":111,"sourceCode":" *\n * @author Gavin King\n */\npublic interface CollectionPersister extends Restrictable {\n\t/**\n\t * The NavigableRole for this collection.\n\t */\n\tNavigableRole getNavigableRole();\n\n\t/**\n\t * Get the name of this collection role (the fully qualified class name,\n\t * extended by a \"property path\")\n\t */\n\tdefault String getRole() {\n\t\treturn getNavigableRole().getFullPath();\n\t}\n\n\tdefault PluralAttributeMapping getAttributeMapping() {\n\t\tthrow new UnsupportedOperationException( \"CollectionPersister used for [\" + getRole() + \"] does not support SQL AST\" );\n\t}\n\n\t/**\n\t * Decomposes a collection recreate action into planned operations.\n\t */\n\tvoid decompose(\n\t\t\tCollectionRecreateAction action,\n\t\t\tint ordinalBase,\n\t\t\tSharedSessionContractImplementor session,\n\t\t\tDecompositionContext decompositionContext,\n\t\t\tConsumer<FlushOperation> operationConsumer);\n\n\t/**\n\t * Removes the collection:<ul>\n\t *     <li>\n\t *         For collections with a collection-table, this will execute a DELETE based\n\t *         on the {@linkplain org.hibernate.engine.spi.CollectionKey collection-key}\n\t *     </li>","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java#L93-L129","documentation":"CollectionPersister#getAttributeMapping is a default method that throws UnsupportedOperationException unless the persister implements SQL AST support. Only the AbstractCollectionPersister family (AbstractCollectionPersister/BasicCollectionPersister/OneToManyPersister) provides real mappings; a custom or legacy persister that implements the interface directly (or delegates the default) fails as soon as any SQL AST machinery needs the attribute mapping.","triggerScenarios":"A custom CollectionPersister implementation that does not extend AbstractCollectionPersister is used with APIs that call getAttributeMapping(): criteria/HQL paths over the collection, entity graph application, mutation query planning, or SQM-to-SQL translation touching the role.","commonSituations":"Legacy integrations with hand-rolled persisters upgraded to Hibernate 6+, where the interface gained SQL AST default methods; test doubles / mocks for persisters passed into runtime paths; custom sharding or archive persisters built before the SQL AST rewrite.","solutions":["Rebase the custom persister on AbstractCollectionPersister (or OneToManyPersister/BasicCollectionPersister) so attribute mappings come for free","Override getAttributeMapping() (and the other SQL AST defaults: filters, entity graph, decompose) in the custom persister with real implementations","Route queries/loads for such collections through APIs that do not require the SQL AST mapping (native SQL, custom loaders)"],"exampleFix":"// before\nclass ArchiveCollectionPersister implements CollectionPersister {\n  // interface implemented directly; getAttributeMapping() default throws\n}\n\n// after\nclass ArchiveCollectionPersister extends BasicCollectionPersister {\n  // inherits getAttributeMapping() and SQL AST support from AbstractCollectionPersister\n}","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Before any SQL AST use of a collection role, confirm the persister supports it\nstatic boolean supportsSqlAst(CollectionPersister p) {\n  return p instanceof org.hibernate.persister.collection.AbstractCollectionPersister;\n}\n// usage\nif (!supportsSqlAst(persister)) {\n  // skip criteria/entity-graph/mutation planning; fall back to native SQL or legacy loaders\n}","tryCatchPattern":"try {\n  return persister.getAttributeMapping();\n} catch (UnsupportedOperationException e) {\n  if (e.getMessage() != null && e.getMessage().contains(\"does not support SQL AST\")) {\n    // custom persister without SQL AST support — route this role through non-SQL-AST loading\n    return null;\n  }\n  throw e;\n}","preventionTips":["Base every custom CollectionPersister on AbstractCollectionPersister/Basic/OneToMany, never on the bare interface","After a Hibernate major upgrade, smoke-test criteria/HQL over every collection role backed by custom persisters","Treat UnsupportedOperationException on default interface methods as a build-time signal: add an integration test that walks getAttributeMapping() for each custom persister"],"tags":["hibernate","custom-persister","sql-ast","internal-api","upgrade"],"backgroundTag":"custom-persister-incompatibility","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}