66
77import java .util .Collection ;
88
9+ import org .checkerframework .checker .nullness .qual .NonNull ;
910import org .checkerframework .checker .nullness .qual .Nullable ;
1011import org .hibernate .HibernateException ;
1112import org .hibernate .engine .spi .SessionFactoryImplementor ;
@@ -131,27 +132,27 @@ public void setBindValue(Object value, boolean resolveJdbcTypeIfNecessary) {
131132 }
132133
133134 @ Override
134- public void setBindValue (Object value , @ Nullable BindableType <? > clarifiedType ) {
135+ public < A > void setBindValue (A value , @ Nullable BindableType <A > clarifiedType ) {
135136 if ( !handleAsMultiValue ( value , clarifiedType ) ) {
136- if ( clarifiedType != null ) {
137- // UNSOUND!!!
138- // We should be creating a whole new object
139- bindType = (BindableType <T >) clarifiedType ;
140- }
141-
142137 final Object coerced = coerce ( value );
143138 validate ( coerced );
144- bindValue ( coerced );
139+ bindValue = cast ( value );
140+ isBound = true ;
141+ isMultiValued = false ;
142+ bindValues = null ;
143+
144+ if ( clarifiedType != null ) {
145+ checkClarifiedType ( clarifiedType , value );
146+ @ SuppressWarnings ("unchecked" ) // safe
147+ final var newType = (BindableType <T >) clarifiedType ;
148+ bindType = newType ;
149+ }
145150 }
146151 }
147152
148153 @ Override
149154 public void setBindValue (Object value , @ SuppressWarnings ("deprecation" ) TemporalType temporalTypePrecision ) {
150155 if ( !handleAsMultiValue ( value , null ) ) {
151- if ( bindType == null ) {
152- bindType = queryParameter .getHibernateType ();
153- }
154-
155156 final Object coerced = coerce ( value );
156157 validate ( coerced );
157158 bindValue ( coerced );
@@ -167,6 +168,8 @@ private void bindValue(Object value) {
167168 }
168169 bindValue = cast ( value );
169170 isBound = true ;
171+ isMultiValued = false ;
172+ bindValues = null ;
170173 }
171174
172175 private void bindNull (boolean resolveJdbcTypeIfNecessary ) {
@@ -219,11 +222,9 @@ public void setBindValues(Collection<?> values) {
219222 }
220223
221224 final var coerced = values .stream ().map ( this ::coerce ).toList ();
222- values .forEach ( this ::validate );
223-
225+ coerced .forEach ( this ::validate );
224226 isBound = true ;
225227 isMultiValued = true ;
226-
227228 bindValue = null ;
228229 bindValues = coerced .stream ().map ( this ::cast ).toList ();
229230
@@ -245,12 +246,26 @@ public void setBindValues(Collection<?> values) {
245246 }
246247
247248 @ Override
248- public void setBindValues (Collection <?> values , BindableType <?> clarifiedType ) {
249+ public <V > void setBindValues (Collection <? extends V > values , BindableType <V > clarifiedType ) {
250+ if ( !queryParameter .allowsMultiValuedBinding () ) {
251+ throw new IllegalArgumentException (
252+ "Illegal attempt to bind a collection value to a single-valued parameter"
253+ );
254+ }
255+
256+ final var coerced = values .stream ().map ( this ::coerce ).toList ();
257+ coerced .forEach ( this ::validate );
258+ isBound = true ;
259+ isMultiValued = true ;
260+ bindValue = null ;
261+ bindValues = coerced .stream ().map ( this ::cast ).toList ();
262+
249263 if ( clarifiedType != null ) {
250- // UNSOUND
251- bindType = (BindableType <T >) clarifiedType ;
264+ checkClarifiedType ( clarifiedType , values );
265+ @ SuppressWarnings ("unchecked" ) // safe
266+ final var newType = (BindableType <T >) clarifiedType ;
267+ bindType = newType ;
252268 }
253- setBindValues ( values );
254269 }
255270
256271 @ Override
@@ -300,6 +315,22 @@ else if ( type instanceof BasicValuedMapping basicValuedMapping ) {
300315 return false ;
301316 }
302317
318+ private <A > void checkClarifiedType (@ NonNull BindableType <A > clarifiedType , Object value ) {
319+ final var parameterType = queryParameter .getParameterType ();
320+ if ( parameterType != null ) {
321+ final var clarifiedJavaType = clarifiedType .getJavaType ();
322+ if ( !parameterType .isAssignableFrom ( clarifiedJavaType ) ) {
323+ throw new QueryArgumentException (
324+ "Given type is incompatible with parameter type" ,
325+ parameterType , clarifiedJavaType , value
326+ );
327+ }
328+ }
329+ else {
330+ assert queryParameter .getHibernateType () == null ;
331+ }
332+ }
333+
303334 private T cast (Object value ) {
304335 final var bindableType = getCriteriaBuilder ().resolveExpressible ( bindType );
305336 return bindableType == null
0 commit comments