hibernate/hibernate-orm · error · UnsupportedOperationException

UserType does not support reading CallableStatement paramete

Error message

UserType does not support reading CallableStatement parameter values: {}

What it means

UserTypeJdbcTypeAdapter.ValueExtractorImpl.extract(CallableStatement, int, WrapperOptions) (UserTypeJdbcTypeAdapter.java:108-122) reads OUT parameters of stored procedures whose Hibernate type is a UserType. It delegates only when the user type implements org.hibernate.type.ProcedureParameterExtractionAware; otherwise it throws this UnsupportedOperationException, meaning OUT values of this custom type cannot be read.

Source

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

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

		@Override
		public J extract(CallableStatement statement, int paramIndex, WrapperOptions options) throws SQLException {
			if ( userType instanceof ProcedureParameterExtractionAware ) {
				//noinspection unchecked
				final J extracted = ( (ProcedureParameterExtractionAware<J>) userType )
						.extract( statement, paramIndex, options.getSession() );
				logExtracted( paramIndex, extracted );
				return extracted;
			}

			throw new UnsupportedOperationException( "UserType does not support reading CallableStatement parameter values: " + userType );
		}

		@Override
		public J extract(CallableStatement statement, String paramName, WrapperOptions options) throws SQLException {
			if ( userType instanceof ProcedureParameterExtractionAware ) {
				//noinspection unchecked
				final J extracted = ( (ProcedureParameterExtractionAware<J>) userType )
						.extract( statement, paramName, options.getSession() );
				logExtracted( paramName, extracted );
				return extracted;
			}

			throw new UnsupportedOperationException( "UserType does not support reading CallableStatement parameter values: " + userType );
		}

		private void logExtracted(int paramIndex, J extracted) {
			if ( JdbcExtractingLogging.LOGGER.isTraceEnabled() ) {
				if ( extracted == null ) {

View on GitHub (pinned to fad1729dce)

Solutions

  1. Implement org.hibernate.type.ProcedureParameterExtractionAware<J> on the UserType and provide the positional extract(CallableStatement, int, SharedSessionContract) implementation that reads the underlying JDBC type and converts it.
  2. Change the stored procedure signature to return a basic type (String/numeric) and convert to your domain type in Java.
  3. Replace the UserType mapping with an AttributeConverter over a standard JDBC type, which supports procedure extraction natively.

Example fix

// before - plain UserType: reading OUT param fails
public class MoneyType implements UserType<Money> { ... }
Money m = query.getOutputParameterValue( 1 );

// after - extraction-aware user type
public class MoneyType implements UserType<Money>, ProcedureParameterExtractionAware<Money> {
    @Override
    public Money extract(CallableStatement statement, int index, SharedSessionContract session)
            throws SQLException {
        return Money.of( statement.getBigDecimal( index ) );
    }
    // ... existing UserType methods
}
Defensive patterns

Strategy: type-guard

Validate before calling

// Before declaring OUT params of a custom type on a stored procedure
if ( !( userType instanceof org.hibernate.type.ProcedureParameterExtractionAware<?> ) ) {
    // change the OUT parameter to a basic type and convert in Java,
    // or implement extraction on the UserType first
}

Type guard

static boolean supportsProcedureExtraction(org.hibernate.usertype.UserType<?> userType) {
    return userType instanceof org.hibernate.type.ProcedureParameterExtractionAware<?>;
}

Try / catch

try {
    query.execute();
    @SuppressWarnings("unchecked")
    Money m = (Money) query.getOutputParameterValue( 1 );
} catch ( UnsupportedOperationException e ) {
    if ( e.getMessage() != null && e.getMessage().contains( "CallableStatement parameter values" ) ) {
        // re-register the OUT param as BigDecimal and convert manually
    } else throw e;
}

Prevention

When it happens

Trigger: A StoredProcedureQuery declares an OUT/INOUT parameter typed with a UserType (registerStoredProcedureParameter(i, MyType.class ...) or @ProcedureParameter on a typed class) and you call execute()/getOutputParameterValue(i); extraction fails unless the UserType implements ProcedureParameterExtractionAware.extract(CallableStatement, int, SharedSessionContract).

Common situations: Domain-specific types (money, codes) reused as stored-procedure parameters; existing UserTypes left unchanged when stored procedures returning those types were introduced.

Related errors


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