{"record":{"id":"0283b7542ea0f151","repo":"hibernate/hibernate-orm","slug":"using-usertype-for-callablestatement-parameter-bin","errorCode":null,"errorMessage":"Using UserType for CallableStatement parameter binding not supported","messagePattern":"Using UserType for CallableStatement parameter binding not supported","errorType":"exception","errorClass":"UnsupportedOperationException","httpStatus":null,"severity":"error","filePath":"hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java","lineNumber":182,"sourceCode":"\t\t\tthis.userType = userType;\n\t\t}\n\n\t\t@Override\n\t\tpublic void bind(PreparedStatement st, J value, int index, WrapperOptions options) throws SQLException {\n\t\t\tif ( JdbcBindingLogging.LOGGER.isTraceEnabled() ) {\n\t\t\t\tif ( value == null ) {\n\t\t\t\t\tJdbcBindingLogging.logNullBinding( index, userType.getSqlType() );\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tJdbcBindingLogging.logBinding( index, userType.getSqlType(), value );\n\t\t\t\t}\n\t\t\t}\n\t\t\tuserType.nullSafeSet( st, value, index, options );\n\t\t}\n\n\t\t@Override\n\t\tpublic void bind(CallableStatement st, J value, String name, WrapperOptions options) {\n\t\t\tthrow new UnsupportedOperationException( \"Using UserType for CallableStatement parameter binding not supported\" );\n\t\t}\n\t}\n}\n","sourceCodeStart":164,"sourceCodeEnd":186,"githubUrl":"https://github.com/hibernate/hibernate-orm/blob/fad1729dce015f908198d57a8d80274a30f905a5/hibernate-core/src/main/java/org/hibernate/type/internal/UserTypeJdbcTypeAdapter.java#L164-L186","documentation":"ValueBinderImpl.bind(CallableStatement, J, String, WrapperOptions) (UserTypeJdbcTypeAdapter.java:178-184) is called when a UserType-mapped value must be bound to a stored-procedure parameter by NAME, and it throws unconditionally: the UserType contract only offers nullSafeSet(PreparedStatement, ...) with positional indexes, so named CallableStatement binding cannot be supported through this adapter.","triggerScenarios":"A StoredProcedureQuery parameter registered with a UserType (e.g. registerStoredProcedureParameter(\"p\", MyType.class, ParameterMode.IN)) and bound via setParameter(\"p\", value): Hibernate routes the named bind to bind(CallableStatement, value, name, options) and gets this UnsupportedOperationException.","commonSituations":"Migrating positional stored-procedure calls to named-parameter style while using custom UserTypes; procedures whose signatures require named binding on drivers/oracle-style call syntax; reusing types that worked fine for ordinary entity persistence.","solutions":["Register and bind the parameter positionally: setParameter(1, value) - the positional bind path (bind with index) delegates to UserType.nullSafeSet and works.","Replace the UserType mapping with an AttributeConverter over a standard JDBC type or a proper JdbcType implementation that implements ProcedureParameterNamedBinder, which does support named binding.","If the value can be represented as a basic type for the call, unwrap/convert it before setParameter."],"exampleFix":"// before - named bind on a UserType parameter -> UnsupportedOperationException\nStoredProcedureQuery q = em.createStoredProcedureQuery(\"calc\");\nq.registerStoredProcedureParameter(\"amount\", Money.class, ParameterMode.IN);\nq.setParameter(\"amount\", money);\n\n// after - positional registration/binding uses UserType.nullSafeSet\nStoredProcedureQuery q = em.createStoredProcedureQuery(\"calc\");\nq.registerStoredProcedureParameter(1, Money.class, ParameterMode.IN);\nq.setParameter(1, money);","handlingStrategy":"validation","validationCode":"// Use positional style whenever a UserType-typed parameter is involved\nStoredProcedureQuery q = em.createStoredProcedureQuery(\"calc\");\nq.registerStoredProcedureParameter(1, Money.class, ParameterMode.IN);\nq.setParameter(1, money); // positional bind delegates to UserType.nullSafeSet\n// rule: never setParameter(\"name\", value) for UserType-mapped parameters","typeGuard":"static boolean isUserTypeMapped(org.hibernate.type.BasicType<?> t) {\n    return t instanceof org.hibernate.type.internal.UserTypeSqlTypeAdapter\n        || t instanceof org.hibernate.type.internal.UserTypeJdbcTypeAdapterMarker;\n}","tryCatchPattern":null,"preventionTips":["Standardize on positional parameter registration/binding for all stored procedures using custom types.","Wrap procedure calls in a DAO layer that knows which types are UserType-mapped and enforces positional binding.","Consider AttributeConverter-based mappings for values that must cross stored-procedure boundaries by name."],"tags":["hibernate","usertype","stored-procedure","callable-statement","named-parameter"],"backgroundTag":"stored-procedure-parameter-unsupported","analyzedSha":"fad1729dce015f908198d57a8d80274a30f905a5","analyzedAt":"2026-08-22T04:13:57.527Z","schemaVersion":2},"datasetVersion":"2026-08-22T09:17:25.309Z"}