hibernate/hibernate-orm · error · UnsupportedOperationException

CollectionPersister used for [{}] does not support SQL AST

Error message

CollectionPersister used for [{}] does not support SQL AST

What it means

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.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/persister/collection/CollectionPersister.java:111

 *
 * @author Gavin King
 */
public interface CollectionPersister extends Restrictable {
	/**
	 * The NavigableRole for this collection.
	 */
	NavigableRole getNavigableRole();

	/**
	 * Get the name of this collection role (the fully qualified class name,
	 * extended by a "property path")
	 */
	default String getRole() {
		return getNavigableRole().getFullPath();
	}

	default PluralAttributeMapping getAttributeMapping() {
		throw new UnsupportedOperationException( "CollectionPersister used for [" + getRole() + "] does not support SQL AST" );
	}

	/**
	 * Decomposes a collection recreate action into planned operations.
	 */
	void decompose(
			CollectionRecreateAction action,
			int ordinalBase,
			SharedSessionContractImplementor session,
			DecompositionContext decompositionContext,
			Consumer<FlushOperation> operationConsumer);

	/**
	 * Removes the collection:<ul>
	 *     <li>
	 *         For collections with a collection-table, this will execute a DELETE based
	 *         on the {@linkplain org.hibernate.engine.spi.CollectionKey collection-key}
	 *     </li>

View on GitHub (pinned to fad1729dce)

Solutions

  1. Rebase the custom persister on AbstractCollectionPersister (or OneToManyPersister/BasicCollectionPersister) so attribute mappings come for free
  2. Override getAttributeMapping() (and the other SQL AST defaults: filters, entity graph, decompose) in the custom persister with real implementations
  3. Route queries/loads for such collections through APIs that do not require the SQL AST mapping (native SQL, custom loaders)

Example fix

// before
class ArchiveCollectionPersister implements CollectionPersister {
  // interface implemented directly; getAttributeMapping() default throws
}

// after
class ArchiveCollectionPersister extends BasicCollectionPersister {
  // inherits getAttributeMapping() and SQL AST support from AbstractCollectionPersister
}
Defensive patterns

Strategy: type-guard

Type guard

// Before any SQL AST use of a collection role, confirm the persister supports it
static boolean supportsSqlAst(CollectionPersister p) {
  return p instanceof org.hibernate.persister.collection.AbstractCollectionPersister;
}
// usage
if (!supportsSqlAst(persister)) {
  // skip criteria/entity-graph/mutation planning; fall back to native SQL or legacy loaders
}

Try / catch

try {
  return persister.getAttributeMapping();
} catch (UnsupportedOperationException e) {
  if (e.getMessage() != null && e.getMessage().contains("does not support SQL AST")) {
    // custom persister without SQL AST support — route this role through non-SQL-AST loading
    return null;
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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