Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -75,23 +75,21 @@ public <P> ProcedureParameterBinding<P> getQueryParameterBinding(ProcedureParame
}

@Override
public <P> ProcedureParameterBinding<P> getBinding(String name) {
public ProcedureParameterBinding<?> getBinding(String name) {
final var parameter = parameterMetadata.getQueryParameter( name );
if ( parameter == null ) {
throw new IllegalArgumentException( "Parameter with name '" + name + "' does not exist" );
}
//noinspection unchecked
return getQueryParameterBinding( (ProcedureParameterImplementor<P>) parameter );
return getQueryParameterBinding( (ProcedureParameterImplementor<?>) parameter );
}

@Override
public <P> ProcedureParameterBinding<P> getBinding(int position) {
public ProcedureParameterBinding<?> getBinding(int position) {
final var parameter = parameterMetadata.getQueryParameter( position );
if ( parameter == null ) {
throw new IllegalArgumentException( "Parameter at position " + position + "does not exist" );
}
//noinspection unchecked
return getQueryParameterBinding( (ProcedureParameterImplementor<P>) parameter );
return getQueryParameterBinding( (ProcedureParameterImplementor<?>) parameter );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,31 @@
*/
public class QueryArgumentException extends IllegalArgumentException {
private final Class<?> parameterType;
private final Class<?> argumentType;
private final Object argument;

public QueryArgumentException(String message, Class<?> parameterType, Object argument) {
super(message);
super( message + " (argument [" + argument + "] is not assignable to " + parameterType.getName() + ")" );
this.parameterType = parameterType;
this.argumentType = argument == null ? null : argument.getClass();
this.argument = argument;
}

public QueryArgumentException(String message, Class<?> parameterType, Class<?> argumentType, Object argument) {
super( message + " (" + argumentType.getName() + " is not assignable to " + parameterType.getName() + ")" );
this.parameterType = parameterType;
this.argumentType = argumentType;
this.argument = argument;
}

public Class<?> getParameterType() {
return parameterType;
}

public Class<?> getArgumentType() {
return argumentType;
}

public Object getArgument() {
return argument;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* SPDX-License-Identifier: Apache-2.0
* Copyright Red Hat Inc. and Hibernate Authors
*/
package org.hibernate.query.internal;

import jakarta.persistence.metamodel.Type;
import org.hibernate.HibernateException;
import org.hibernate.type.BindingContext;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.spi.EntityJavaType;

import java.util.Collection;

import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;

/**
* @since 7.3
*
* @author Gavin King
*/
public class QueryArguments {

private static boolean isInstance(Object value, JavaType<?> javaType) {
try {
// special handling for entity arguments due to
// the possibility of an uninitialized proxy
// (which we don't want or need to fetch)
if ( javaType instanceof EntityJavaType<?> ) {
final var javaTypeClass = javaType.getJavaTypeClass();
final var initializer = extractLazyInitializer( value );
final var valueEntityClass =
initializer != null
? initializer.getPersistentClass()
: value.getClass();
// accept assignability in either direction
return javaTypeClass.isAssignableFrom( valueEntityClass )
|| valueEntityClass.isAssignableFrom( javaTypeClass );
}
else {
// require that the argument be assignable to the parameter
return javaType.isInstance( javaType.coerce( value ) );
}
}
catch (HibernateException ce) {
return false;
}
}

public static boolean isInstance(
Type<?> parameterType, Object value,
BindingContext bindingContext) {
if ( value == null ) {
return true;
}
final var sqmExpressible = bindingContext.resolveExpressible( parameterType );
assert sqmExpressible != null;
final var javaType = sqmExpressible.getExpressibleJavaType();
return isInstance( value, javaType );
}

public static boolean areInstances(
Type<?> parameterType, Collection<?> values,
BindingContext bindingContext) {
if ( values.isEmpty() ) {
return true;
}
final var sqmExpressible = bindingContext.resolveExpressible( parameterType );
assert sqmExpressible != null;
final var javaType = sqmExpressible.getExpressibleJavaType();
for ( Object value : values ) {
if ( !isInstance( value, javaType ) ) {
return false;
}
}
return true;
}

public static boolean areInstances(
Type<?> parameterType, Object[] values,
BindingContext bindingContext) {
if ( values.length == 0 ) {
return true;
}
if ( parameterType.getJavaType()
.isAssignableFrom( values.getClass().getComponentType() ) ) {
return true;
}
final var sqmExpressible = bindingContext.resolveExpressible( parameterType );
assert sqmExpressible != null;
final var javaType = sqmExpressible.getExpressibleJavaType();
for ( Object value : values ) {
if ( !isInstance( value, javaType ) ) {
return false;
}
}
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@
import org.hibernate.query.QueryParameter;
import org.hibernate.query.spi.QueryParameterBinding;
import org.hibernate.query.spi.QueryParameterBindingTypeResolver;
import org.hibernate.query.spi.QueryParameterBindingValidator;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.spi.TypeConfiguration;

import jakarta.persistence.TemporalType;

import static org.hibernate.query.spi.QueryParameterBindingValidator.validate;
import static org.hibernate.type.descriptor.java.JavaTypeHelper.isTemporal;
import static org.hibernate.type.internal.BindingTypeHelper.resolveTemporalPrecision;

Expand Down Expand Up @@ -116,7 +116,7 @@ public T getBindValue() {
public void setBindValue(T value, boolean resolveJdbcTypeIfNecessary) {
if ( !handleAsMultiValue( value, null ) ) {
final Object coerced = coerceIfNotJpa( value );
validate( coerced );
validate( getBindType(), coerced, sessionFactory );

if ( value == null ) {
// needed when setting a null value to the parameter of a native SQL query
Expand Down Expand Up @@ -174,7 +174,7 @@ public void setBindValue(T value, @Nullable BindableType<T> clarifiedType) {
}

final Object coerced = coerce( value );
validate( coerced, clarifiedType );
validate( clarifiedType, coerced, sessionFactory );
bindValue( coerced );
}
}
Expand All @@ -187,7 +187,7 @@ public void setBindValue(T value, TemporalType temporalTypePrecision) {
}

final Object coerced = coerceIfNotJpa( value );
validate( coerced, temporalTypePrecision );
validate( getBindType(), coerced, sessionFactory );
bindValue( coerced );
setExplicitTemporalPrecision( temporalTypePrecision );
}
Expand Down Expand Up @@ -218,15 +218,19 @@ public void setBindValues(Collection<? extends T> values) {
this.bindValue = null;
this.bindValues = values;

final T value = firstNonNull( values );
if ( canBindValueBeSet( value, bindType ) ) {
bindType = getParameterBindingTypeResolver().resolveParameterBindType( value );
}
}

private static <T> @Nullable T firstNonNull(Collection<? extends T> values) {
final var iterator = values.iterator();
T value = null;
while ( value == null && iterator.hasNext() ) {
value = iterator.next();
}

if ( canBindValueBeSet( value, bindType ) ) {
bindType = getParameterBindingTypeResolver().resolveParameterBindType( value );
}
return value;
}

@Override
Expand Down Expand Up @@ -284,18 +288,6 @@ else if ( type instanceof BasicValuedMapping basicValuedMapping ) {
return false;
}

private void validate(Object value) {
QueryParameterBindingValidator.INSTANCE.validate( getBindType(), value, getCriteriaBuilder() );
}

private void validate(Object value, BindableType<?> clarifiedType) {
QueryParameterBindingValidator.INSTANCE.validate( clarifiedType, value, getCriteriaBuilder() );
}

private void validate(Object value, TemporalType clarifiedTemporalType) {
QueryParameterBindingValidator.INSTANCE.validate( getBindType(), value, clarifiedTemporalType, getCriteriaBuilder() );
}

public TypeConfiguration getTypeConfiguration() {
return sessionFactory.getTypeConfiguration();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ private QueryParameterBindingsImpl(
this.parameterBindingMap = linkedMapOfSize( queryParameters.size() );
this.parameterBindingMapByNameOrPosition = mapOfSize( queryParameters.size() );
for ( var queryParameter : queryParameters ) {
parameterBindingMap.put( queryParameter, createBinding( sessionFactory, parameterMetadata, queryParameter ) );
parameterBindingMap.put( queryParameter,
createBinding( sessionFactory, parameterMetadata, queryParameter ) );
}
for ( var entry : parameterBindingMap.entrySet() ) {
final var queryParameter = entry.getKey();
Expand Down Expand Up @@ -129,30 +130,32 @@ public <P> QueryParameterBinding<P> getBinding(QueryParameterImplementor<P> para
"Cannot create binding for parameter reference [" + parameter + "] - reference is not a parameter of this query"
);
}
//noinspection unchecked
return (QueryParameterBinding<P>) binding;
if ( !binding.getQueryParameter().equals( parameter ) ) {
throw new IllegalStateException("Parameter binding corrupted for: " + parameter.getName() );
}
@SuppressWarnings("unchecked") // safe because we checked the parameter
final var castBinding = (QueryParameterBinding<P>) binding;
return castBinding;
}

@Override
public <P> QueryParameterBinding<P> getBinding(int position) {
public QueryParameterBinding<?> getBinding(int position) {
final var binding = parameterBindingMapByNameOrPosition.get( position );
if ( binding == null ) {
// Invoke this method to throw the exception
parameterMetadata.getQueryParameter( position );
}
//noinspection unchecked
return (QueryParameterBinding<P>) binding;
return binding;
}

@Override
public <P> QueryParameterBinding<P> getBinding(String name) {
public QueryParameterBinding<?> getBinding(String name) {
final var binding = parameterBindingMapByNameOrPosition.get( name );
if ( binding == null ) {
// Invoke this method to throw the exception
parameterMetadata.getQueryParameter( name );
}
//noinspection unchecked
return (QueryParameterBinding<P>) binding;
return binding;
}

@Override
Expand Down
Loading
Loading