hibernate/hibernate-orm · error · HibernateException

Could not create JdbcLiteralFormatter because UserType class

Error message

Could not create JdbcLiteralFormatter because UserType class '{}' did not implement EnhancedUserType

What it means

UserTypeJdbcTypeAdapter bridges a UserType to Hibernate's JdbcType SPI; getJdbcLiteralFormatter (UserTypeJdbcTypeAdapter.java:85-93) must render values of the type as inline SQL literals, and it can only do that through EnhancedUserType.toSqlLiteral. If the user type does not implement EnhancedUserType, this HibernateException is thrown the first time Hibernate needs to inline such a value into SQL.

Source

Thrown at hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java:89

	@SuppressWarnings("unchecked")
	public <X> ValueExtractor<X> getExtractor(JavaType<X> javaType) {
		assert javaType.getJavaTypeClass() == null
				|| javaType.getJavaTypeClass().isAssignableFrom( this.javaType.getJavaTypeClass() );
		return (ValueExtractor<X>) valueExtractor;
	}

	@Override
	public JavaType<?> getRecommendedJavaType(
			Integer length,
			Integer scale,
			TypeConfiguration typeConfiguration) {
		return javaType;
	}

	@Override
	public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaType<T> javaType) {
		if ( !( userType instanceof EnhancedUserType<?> ) ) {
			throw new HibernateException( "Could not create JdbcLiteralFormatter because UserType class '"
							+ userType.getClass().getName() + "' did not implement EnhancedUserType" );
		}
		final EnhancedUserType<T> type = (EnhancedUserType<T>) userType;
		return (appender, value, dialect, wrapperOptions) ->
				appender.append( type.toSqlLiteral( value ) );
	}

	private static class ValueExtractorImpl<J> implements ValueExtractor<J> {
		private final UserType<J> userType;

		public ValueExtractorImpl(UserType<J> userType) {
			this.userType = userType;
		}

		@Override
		public J extract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
			final J extracted = userType.nullSafeGet( rs, paramIndex, options );
			logExtracted( paramIndex, extracted );

View on GitHub (pinned to fad1729dce)

Solutions

  1. Implement EnhancedUserType<J> on the user type and provide toSqlLiteral(J) returning the dialect-safe literal text (quoted for strings).
  2. Avoid inlining: pass the value as a bound parameter (setParameter) instead of a literal where possible.
  3. Replace the UserType with an AttributeConverter over a standard basic type, which gets literal formatting for free.

Example fix

// before - plain UserType: literal rendering throws HibernateException
public class IbanType implements UserType<Iban> { ... }
cb.equal( root.get( "iban" ), cb.literal( Iban.of( "DE89..." ) ) );

// after - EnhancedUserType renders the literal
public class IbanType implements UserType<Iban>, EnhancedUserType<Iban> {
    @Override public String toSqlLiteral(Iban value) {
        return "'" + value.text() + "'";
    }
    // ... existing UserType methods
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Before inlining literals of a custom type, verify literal support
if ( !( userType instanceof org.hibernate.usertype.EnhancedUserType<?> ) ) {
    // bind the value as a parameter instead of a literal
    query.setParameter( "v", value );
} else {
    // literal rendering is safe (cb.literal(value), HQL literals)
}

Type guard

static boolean rendersSqlLiteral(org.hibernate.usertype.UserType<?> userType) {
    return userType instanceof org.hibernate.usertype.EnhancedUserType<?>;
}

Prevention

When it happens

Trigger: Rendering a literal for a UserType-mapped value into generated SQL: criteria queries using CriteriaBuilder.literal(value) on such a type, HQL literals compared against a UserType-mapped attribute, and query/dialect paths that inline parameters as literals; all fail unless the UserType implements EnhancedUserType.

Common situations: Long-standing plain UserTypes surviving an ORM upgrade that renders literals more eagerly; generated query code that inlines constants; dialects or settings (literal handling) that favor inlined literals over bind parameters.

Related errors


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