Skip to content

Commit 4d61441

Browse files
committed
clean up the methods of QueryParameterBindingImpl
1 parent 498f08f commit 4d61441

File tree

3 files changed

+211
-141
lines changed

3 files changed

+211
-141
lines changed

hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingImpl.java

Lines changed: 121 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@
44
*/
55
package org.hibernate.query.internal;
66

7+
import java.util.ArrayList;
78
import java.util.Collection;
9+
import java.util.List;
810

911
import org.checkerframework.checker.nullness.qual.NonNull;
1012
import org.checkerframework.checker.nullness.qual.Nullable;
@@ -117,7 +119,10 @@ public T getBindValue() {
117119

118120
@Override
119121
public void setBindValue(Object value, boolean resolveJdbcTypeIfNecessary) {
120-
if ( !handleAsMultiValue( value, null ) ) {
122+
if ( handleAsMultiValue( value, bindType ) ) {
123+
setBindValues( (Collection<?>) value );
124+
}
125+
else {
121126
final Object coerced = coerce( value );
122127
validate( coerced );
123128
if ( value == null ) {
@@ -126,50 +131,49 @@ public void setBindValue(Object value, boolean resolveJdbcTypeIfNecessary) {
126131
bindNull( resolveJdbcTypeIfNecessary );
127132
}
128133
else {
129-
bindValue( coerced );
134+
initBindType( value );
135+
bindSingleValue( coerced );
130136
}
131137
}
132138
}
133139

134140
@Override
135-
public <A> void setBindValue(A value, @Nullable BindableType<A> clarifiedType) {
136-
if ( !handleAsMultiValue( value, clarifiedType ) ) {
137-
final Object coerced = coerce( value );
138-
validate( 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-
}
141+
public void setBindValue(
142+
Object value,
143+
@SuppressWarnings("deprecation")
144+
TemporalType temporalTypePrecision) {
145+
if ( handleAsMultiValue( value, bindType ) ) {
146+
setBindValues( (Collection<?>) value, temporalTypePrecision );
150147
}
151-
}
152-
153-
@Override
154-
public void setBindValue(Object value, @SuppressWarnings("deprecation") TemporalType temporalTypePrecision) {
155-
if ( !handleAsMultiValue( value, null ) ) {
148+
else {
156149
final Object coerced = coerce( value );
157150
validate( coerced );
158-
bindValue( coerced );
151+
initBindType( value );
152+
bindSingleValue( coerced );
159153
setExplicitTemporalPrecision( temporalTypePrecision );
160154
}
161155
}
162156

163-
private void bindValue(Object value) {
164-
if ( canBindValueBeSet( value, bindType ) ) {
165-
bindType = (BindableType<T>) (BindableType)
157+
@Override
158+
public <A> void setBindValue(A value, @Nullable BindableType<A> clarifiedType) {
159+
// don't coerce, because value is already of the clarified type
160+
validate( value );
161+
clarifyType( value, clarifiedType );
162+
bindSingleValue( value );
163+
}
164+
165+
private void initBindType(Object value) {
166+
if ( bindType == null ) {
167+
@SuppressWarnings("unchecked")
168+
// If there is no bindType set, then this is effectively a
169+
// parameter of the top type. At least arguably safe cast.
170+
final var self = (QueryParameterBindingImpl<Object>) this;
171+
//noinspection UnnecessaryLocalVariable (needed to make javac happy)
172+
final var valueType =
166173
getParameterBindingTypeResolver()
167174
.resolveParameterBindType( value );
175+
self.bindType = valueType;
168176
}
169-
bindValue = cast( value );
170-
isBound = true;
171-
isMultiValued = false;
172-
bindValues = null;
173177
}
174178

175179
private void bindNull(boolean resolveJdbcTypeIfNecessary) {
@@ -185,17 +189,22 @@ private void bindNull(boolean resolveJdbcTypeIfNecessary) {
185189
}
186190

187191
private boolean handleAsMultiValue(Object value, @Nullable BindableType<?> bindableType) {
188-
if ( queryParameter.allowsMultiValuedBinding()
192+
return queryParameter.allowsMultiValuedBinding()
189193
&& value instanceof Collection
190-
&& !( bindableType == null
194+
&& !validInstance( value, bindableType );
195+
}
196+
197+
private void bindSingleValue(Object value) {
198+
bindValue = cast( value );
199+
bindValues = null;
200+
isMultiValued = false;
201+
isBound = true;
202+
}
203+
204+
private boolean validInstance(Object value, @Nullable BindableType<?> bindableType) {
205+
return bindableType == null
191206
? isRegisteredAsBasicType( value.getClass() )
192-
: bindableType.getJavaType().isInstance( value ) ) ) {
193-
setBindValues( (Collection<?>) value );
194-
return true;
195-
}
196-
else {
197-
return false;
198-
}
207+
: bindableType.getJavaType().isInstance( value );
199208
}
200209

201210
private boolean isRegisteredAsBasicType(Class<?> valueClass) {
@@ -215,66 +224,47 @@ public Collection<? extends T> getBindValues() {
215224

216225
@Override
217226
public void setBindValues(Collection<?> values) {
218-
if ( !queryParameter.allowsMultiValuedBinding() ) {
219-
throw new IllegalArgumentException(
220-
"Illegal attempt to bind a collection value to a single-valued parameter"
221-
);
222-
}
223-
227+
assertMultivalued();
224228
final var coerced = values.stream().map( this::coerce ).toList();
225229
coerced.forEach( this::validate );
226-
isBound = true;
227-
isMultiValued = true;
228-
bindValue = null;
229-
bindValues = coerced.stream().map( this::cast ).toList();
230-
231-
final T value = firstNonNull( bindValues );
232-
if ( canBindValueBeSet( value, bindType ) ) {
233-
bindType = (BindableType<T>) (BindableType)
234-
getParameterBindingTypeResolver()
235-
.resolveParameterBindType( value );
236-
}
230+
initBindType( firstNonNull( values ) );
231+
bindMultipleValues( coerced );
237232
}
238233

239-
private static <T> @Nullable T firstNonNull(Collection<? extends T> values) {
240-
final var iterator = values.iterator();
241-
T value = null;
242-
while ( value == null && iterator.hasNext() ) {
243-
value = iterator.next();
244-
}
245-
return value;
234+
@Override
235+
public void setBindValues(
236+
Collection<?> values,
237+
@SuppressWarnings("deprecation") TemporalType temporalTypePrecision) {
238+
setBindValues( values );
239+
setExplicitTemporalPrecision( temporalTypePrecision );
246240
}
247241

248242
@Override
249243
public <V> void setBindValues(Collection<? extends V> values, BindableType<V> clarifiedType) {
244+
assertMultivalued();
245+
// don't coerce, because value is already of the clarified type
246+
values.forEach( this::validate );
247+
clarifyType( values, clarifiedType );
248+
bindMultipleValues( values );
249+
}
250+
251+
private void bindMultipleValues(Collection<?> coerced) {
252+
final List<T> list = new ArrayList<>();
253+
for ( var value : coerced ) {
254+
list.add( cast( value ) );
255+
}
256+
bindValues = list;
257+
bindValue = null;
258+
isMultiValued = true;
259+
isBound = true;
260+
}
261+
262+
private void assertMultivalued() {
250263
if ( !queryParameter.allowsMultiValuedBinding() ) {
251264
throw new IllegalArgumentException(
252265
"Illegal attempt to bind a collection value to a single-valued parameter"
253266
);
254267
}
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-
263-
if ( clarifiedType != null ) {
264-
checkClarifiedType( clarifiedType, values );
265-
@SuppressWarnings("unchecked") // safe
266-
final var newType = (BindableType<T>) clarifiedType;
267-
bindType = newType;
268-
}
269-
}
270-
271-
@Override
272-
public void setBindValues(
273-
Collection<?> values,
274-
@SuppressWarnings("deprecation") TemporalType temporalTypePrecision,
275-
TypeConfiguration typeConfiguration) {
276-
setBindValues( values );
277-
setExplicitTemporalPrecision( temporalTypePrecision );
278268
}
279269

280270
private void setExplicitTemporalPrecision(@SuppressWarnings("deprecation") TemporalType precision) {
@@ -315,14 +305,25 @@ else if ( type instanceof BasicValuedMapping basicValuedMapping ) {
315305
return false;
316306
}
317307

318-
private <A> void checkClarifiedType(@NonNull BindableType<A> clarifiedType, Object value) {
308+
private <V> void clarifyType(Object valueOrValues, BindableType<V> clarifiedType) {
309+
if ( clarifiedType != null ) {
310+
checkClarifiedType( clarifiedType, valueOrValues );
311+
@SuppressWarnings("unchecked") // safe
312+
final var newType = (BindableType<T>) clarifiedType;
313+
bindType = newType;
314+
}
315+
}
316+
317+
private <A> void checkClarifiedType(
318+
@NonNull BindableType<A> clarifiedType,
319+
Object valueOrValues) {
319320
final var parameterType = queryParameter.getParameterType();
320321
if ( parameterType != null ) {
321322
final var clarifiedJavaType = clarifiedType.getJavaType();
322323
if ( !parameterType.isAssignableFrom( clarifiedJavaType ) ) {
323324
throw new QueryArgumentException(
324325
"Given type is incompatible with parameter type",
325-
parameterType, clarifiedJavaType, value
326+
parameterType, clarifiedJavaType, valueOrValues
326327
);
327328
}
328329
}
@@ -332,10 +333,27 @@ private <A> void checkClarifiedType(@NonNull BindableType<A> clarifiedType, Obje
332333
}
333334

334335
private T cast(Object value) {
335-
final var bindableType = getCriteriaBuilder().resolveExpressible( bindType );
336-
return bindableType == null
337-
? (T) value // YOLO
338-
: QueryArguments.cast( value, bindableType.getExpressibleJavaType() );
336+
if ( value == null ) {
337+
return null;
338+
}
339+
else {
340+
final var bindableType =
341+
getCriteriaBuilder()
342+
.resolveExpressible( bindType );
343+
if ( bindableType != null ) {
344+
return QueryArguments.cast( value,
345+
bindableType.getExpressibleJavaType() );
346+
}
347+
else if ( bindType != null ) {
348+
return bindType.getJavaType().cast( value );
349+
}
350+
else {
351+
// no typing information, but in this
352+
// case we can view this as T = Object
353+
// noinspection unchecked
354+
return (T) value;
355+
}
356+
}
339357
}
340358

341359
private void validate(Object value) {
@@ -344,12 +362,12 @@ private void validate(Object value) {
344362

345363
private Object coerce(Object value) {
346364
try {
347-
if ( canValueBeCoerced( bindType ) ) {
365+
if ( bindType != null ) {
348366
return coerce( value, bindType );
349367
}
350-
else if ( canValueBeCoerced( queryParameter.getHibernateType() ) ) {
351-
return coerce( value, queryParameter.getHibernateType() );
352-
}
368+
// else if ( queryParameter.getHibernateType() != null ) {
369+
// return coerce( value, queryParameter.getHibernateType() );
370+
// }
353371
else {
354372
return value;
355373
}
@@ -366,11 +384,13 @@ private Object coerce(Object value, BindableType<T> parameterType) {
366384
.getExpressibleJavaType().coerce( value );
367385
}
368386

369-
private static boolean canValueBeCoerced(BindableType<?> bindType) {
370-
return bindType != null;
387+
private static <T> @Nullable T firstNonNull(Collection<? extends T> values) {
388+
final var iterator = values.iterator();
389+
T value = null;
390+
while ( value == null && iterator.hasNext() ) {
391+
value = iterator.next();
392+
}
393+
return value;
371394
}
372395

373-
private static boolean canBindValueBeSet(Object value, BindableType<?> bindType) {
374-
return value != null && bindType == null;
375-
}
376396
}

0 commit comments

Comments
 (0)