HHH-8643 corrected TemporalType parameter validation
This commit is contained in:
parent
4fad9a4a8f
commit
cd55718f71
|
@ -23,19 +23,31 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.ejb;
|
package org.hibernate.ejb;
|
||||||
|
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_CACHEABLE;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_CACHE_MODE;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_CACHE_REGION;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_COMMENT;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_FETCH_SIZE;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_FLUSH_MODE;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_READONLY;
|
||||||
|
import static org.hibernate.ejb.QueryHints.HINT_TIMEOUT;
|
||||||
|
import static org.hibernate.ejb.QueryHints.SPEC_HINT_TIMEOUT;
|
||||||
|
|
||||||
|
import java.util.Calendar;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.persistence.CacheRetrieveMode;
|
import javax.persistence.CacheRetrieveMode;
|
||||||
import javax.persistence.CacheStoreMode;
|
import javax.persistence.CacheStoreMode;
|
||||||
import javax.persistence.FlushModeType;
|
import javax.persistence.FlushModeType;
|
||||||
import javax.persistence.Parameter;
|
import javax.persistence.Parameter;
|
||||||
|
import javax.persistence.TemporalType;
|
||||||
import javax.persistence.TransactionRequiredException;
|
import javax.persistence.TransactionRequiredException;
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
|
||||||
import org.hibernate.CacheMode;
|
import org.hibernate.CacheMode;
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
import org.hibernate.HibernateException;
|
import org.hibernate.HibernateException;
|
||||||
|
@ -46,16 +58,7 @@ import org.hibernate.ejb.util.CacheModeHelper;
|
||||||
import org.hibernate.ejb.util.ConfigurationHelper;
|
import org.hibernate.ejb.util.ConfigurationHelper;
|
||||||
import org.hibernate.ejb.util.LockModeTypeHelper;
|
import org.hibernate.ejb.util.LockModeTypeHelper;
|
||||||
import org.hibernate.hql.internal.QueryExecutionRequestException;
|
import org.hibernate.hql.internal.QueryExecutionRequestException;
|
||||||
|
import org.jboss.logging.Logger;
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_CACHEABLE;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_CACHE_MODE;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_CACHE_REGION;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_COMMENT;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_FETCH_SIZE;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_FLUSH_MODE;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_READONLY;
|
|
||||||
import static org.hibernate.ejb.QueryHints.HINT_TIMEOUT;
|
|
||||||
import static org.hibernate.ejb.QueryHints.SPEC_HINT_TIMEOUT;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intended as a base class providing convenience in implementing both {@link javax.persistence.Query} and
|
* Intended as a base class providing convenience in implementing both {@link javax.persistence.Query} and
|
||||||
|
@ -341,11 +344,16 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
|
|
||||||
@SuppressWarnings( {"unchecked"})
|
@SuppressWarnings( {"unchecked"})
|
||||||
protected void registerParameterBinding(Parameter parameter, Object value) {
|
protected void registerParameterBinding(Parameter parameter, Object value) {
|
||||||
|
registerParameterBinding( parameter, value, null );
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings( {"unchecked"})
|
||||||
|
protected void registerParameterBinding(Parameter parameter, Object value, TemporalType temporalType) {
|
||||||
if ( parameter == null ) {
|
if ( parameter == null ) {
|
||||||
throw new IllegalArgumentException( "parameter cannot be null" );
|
throw new IllegalArgumentException( "parameter cannot be null" );
|
||||||
}
|
}
|
||||||
|
|
||||||
validateParameterBinding( parameter, value );
|
validateBinding( parameter.getParameterType(), value, temporalType );
|
||||||
|
|
||||||
if ( parameterBindings == null ) {
|
if ( parameterBindings == null ) {
|
||||||
parameterBindings = new HashMap();
|
parameterBindings = new HashMap();
|
||||||
|
@ -353,90 +361,123 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
||||||
parameterBindings.put( parameter, value );
|
parameterBindings.put( parameter, value );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateParameterBinding(Parameter parameter, Object value) {
|
private void validateBinding(Class parameterType, Object bind, TemporalType temporalType) {
|
||||||
if ( value == null || parameter.getParameterType() == null ) {
|
if ( bind == null || parameterType == null ) {
|
||||||
// nothing we can check
|
// nothing we can check
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( Collection.class.isInstance( value )
|
if ( Collection.class.isInstance( bind ) && ! Collection.class.isAssignableFrom( parameterType ) ) {
|
||||||
&& ! Collection.class.isAssignableFrom( parameter.getParameterType() ) ) {
|
// we have a collection passed in where we are expecting a non-collection.
|
||||||
// we have a collection passed in where we are expecting a non-collection.
|
// NOTE : this can happen in Hibernate's notion of "parameter list" binding
|
||||||
// NOTE : this can happen in Hibernate's notion of "parameter list" binding
|
// NOTE2 : the case of a collection value and an expected collection (if that can even happen)
|
||||||
// NOTE2 : the case of a collection value and an expected collection (if that can even happen)
|
// will fall through to the main check.
|
||||||
// will fall through to the main check.
|
validateCollectionValuedParameterBinding( parameterType, (Collection) bind, temporalType );
|
||||||
validateCollectionValuedParameterMultiBinding( parameter, (Collection) value );
|
}
|
||||||
}
|
else if ( bind.getClass().isArray() ) {
|
||||||
else if ( value.getClass().isArray() ) {
|
validateArrayValuedParameterBinding( parameterType, bind, temporalType );
|
||||||
validateArrayValuedParameterBinding( parameter, value );
|
}
|
||||||
}
|
else {
|
||||||
else {
|
if ( ! isValidBindValue( parameterType, bind, temporalType ) ) {
|
||||||
if ( ! parameter.getParameterType().isInstance( value ) ) {
|
throw new IllegalArgumentException(
|
||||||
throw new IllegalArgumentException(
|
String.format(
|
||||||
String.format(
|
"Parameter value [%s] did not match expected type [%s (%s)]",
|
||||||
"Parameter value [%s] did not match expected type [%s]",
|
bind,
|
||||||
value,
|
parameterType.getName(),
|
||||||
parameter.getParameterType().getName()
|
extractName( temporalType )
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateCollectionValuedParameterMultiBinding(Parameter parameter, Collection value) {
|
private String extractName(TemporalType temporalType) {
|
||||||
// validate the elements...
|
return temporalType == null ? "n/a" : temporalType.name();
|
||||||
for ( Object element : value ) {
|
|
||||||
if ( ! parameter.getParameterType().isInstance( element ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
String.format(
|
|
||||||
"Parameter value element [%s] did not match expected type [%s]",
|
|
||||||
element,
|
|
||||||
parameter.getParameterType().getName()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateArrayValuedParameterBinding(Parameter parameter, Object value) {
|
private void validateCollectionValuedParameterBinding(
|
||||||
if ( ! parameter.getParameterType().isArray() ) {
|
Class parameterType,
|
||||||
throw new IllegalArgumentException(
|
Collection value,
|
||||||
String.format(
|
TemporalType temporalType) {
|
||||||
"Encountered array-valued parameter binding, but was expecting [%s]",
|
// validate the elements...
|
||||||
parameter.getParameterType().getName()
|
for ( Object element : value ) {
|
||||||
)
|
if ( ! isValidBindValue( parameterType, element, temporalType ) ) {
|
||||||
);
|
throw new IllegalArgumentException(
|
||||||
}
|
String.format(
|
||||||
|
"Parameter value element [%s] did not match expected type [%s (%s)]",
|
||||||
if ( value.getClass().getComponentType().isPrimitive() ) {
|
element,
|
||||||
// we have a primitive array. we validate that the actual array has the component type (type odf elements)
|
parameterType.getName(),
|
||||||
// we expect based on the component type of the parameter specification
|
extractName( temporalType )
|
||||||
if ( ! parameter.getParameterType().getComponentType().isAssignableFrom( value.getClass().getComponentType() ) ) {
|
)
|
||||||
throw new IllegalArgumentException(
|
);
|
||||||
String.format(
|
}
|
||||||
"Primitive array-valued parameter bind value type [%s] did not match expected type [%s]",
|
}
|
||||||
value.getClass().getComponentType().getName(),
|
}
|
||||||
parameter.getParameterType().getName()
|
|
||||||
)
|
private void validateArrayValuedParameterBinding(
|
||||||
);
|
Class parameterType,
|
||||||
}
|
Object value,
|
||||||
}
|
TemporalType temporalType) {
|
||||||
else {
|
if ( ! parameterType.isArray() ) {
|
||||||
// we have an object array. Here we loop over the array and physically check each element against
|
throw new IllegalArgumentException(
|
||||||
// the type we expect based on the component type of the parameter specification
|
String.format(
|
||||||
final Object[] array = (Object[]) value;
|
"Encountered array-valued parameter binding, but was expecting [%s (%s)]",
|
||||||
for ( Object element : array ) {
|
parameterType.getName(),
|
||||||
if ( ! parameter.getParameterType().getComponentType().isInstance( element ) ) {
|
extractName( temporalType )
|
||||||
throw new IllegalArgumentException(
|
)
|
||||||
String.format(
|
);
|
||||||
"Array-valued parameter value element [%s] did not match expected type [%s]",
|
}
|
||||||
element,
|
|
||||||
parameter.getParameterType().getName()
|
if ( value.getClass().getComponentType().isPrimitive() ) {
|
||||||
)
|
// we have a primitive array. we validate that the actual array has the component type (type of elements)
|
||||||
);
|
// we expect based on the component type of the parameter specification
|
||||||
}
|
if ( ! parameterType.getComponentType().isAssignableFrom( value.getClass().getComponentType() ) ) {
|
||||||
}
|
throw new IllegalArgumentException(
|
||||||
}
|
String.format(
|
||||||
|
"Primitive array-valued parameter bind value type [%s] did not match expected type [%s (%s)]",
|
||||||
|
value.getClass().getComponentType().getName(),
|
||||||
|
parameterType.getName(),
|
||||||
|
extractName( temporalType )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// we have an object array. Here we loop over the array and physically check each element against
|
||||||
|
// the type we expect based on the component type of the parameter specification
|
||||||
|
final Object[] array = (Object[]) value;
|
||||||
|
for ( Object element : array ) {
|
||||||
|
if ( ! isValidBindValue( parameterType.getComponentType(), element, temporalType ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
String.format(
|
||||||
|
"Array-valued parameter value element [%s] did not match expected type [%s (%s)]",
|
||||||
|
element,
|
||||||
|
parameterType.getName(),
|
||||||
|
extractName( temporalType )
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isValidBindValue(Class expectedType, Object value, TemporalType temporalType) {
|
||||||
|
if ( expectedType.isInstance( value ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( temporalType != null ) {
|
||||||
|
final boolean parameterDeclarationIsTemporal = Date.class.isAssignableFrom( expectedType )
|
||||||
|
|| Calendar.class.isAssignableFrom( expectedType );
|
||||||
|
final boolean bindIsTemporal = Date.class.isInstance( value )
|
||||||
|
|| Calendar.class.isInstance( value );
|
||||||
|
|
||||||
|
if ( parameterDeclarationIsTemporal && bindIsTemporal ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -395,7 +395,7 @@ public class QueryImpl<X> extends org.hibernate.ejb.AbstractQueryImpl<X> impleme
|
||||||
else if ( temporalType == TIMESTAMP ) {
|
else if ( temporalType == TIMESTAMP ) {
|
||||||
query.setTimestamp( name, value );
|
query.setTimestamp( name, value );
|
||||||
}
|
}
|
||||||
registerParameterBinding( getParameter( name ), value );
|
registerParameterBinding( getParameter( name ), value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
catch (QueryParameterException e) {
|
catch (QueryParameterException e) {
|
||||||
|
@ -420,7 +420,7 @@ public class QueryImpl<X> extends org.hibernate.ejb.AbstractQueryImpl<X> impleme
|
||||||
else if ( temporalType == TIMESTAMP ) {
|
else if ( temporalType == TIMESTAMP ) {
|
||||||
query.setCalendar( name, value );
|
query.setCalendar( name, value );
|
||||||
}
|
}
|
||||||
registerParameterBinding( getParameter(name), value );
|
registerParameterBinding( getParameter(name), value, temporalType );
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
catch (QueryParameterException e) {
|
catch (QueryParameterException e) {
|
||||||
|
@ -476,7 +476,7 @@ public class QueryImpl<X> extends org.hibernate.ejb.AbstractQueryImpl<X> impleme
|
||||||
else if ( temporalType == TIMESTAMP ) {
|
else if ( temporalType == TIMESTAMP ) {
|
||||||
query.setTimestamp( position - 1, value );
|
query.setTimestamp( position - 1, value );
|
||||||
}
|
}
|
||||||
registerParameterBinding( getParameter( position ), value );
|
registerParameterBinding( getParameter( position ), value, temporalType );
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
@ -507,7 +507,7 @@ public class QueryImpl<X> extends org.hibernate.ejb.AbstractQueryImpl<X> impleme
|
||||||
else if ( temporalType == TIMESTAMP ) {
|
else if ( temporalType == TIMESTAMP ) {
|
||||||
query.setCalendar( position - 1, value );
|
query.setCalendar( position - 1, value );
|
||||||
}
|
}
|
||||||
registerParameterBinding( getParameter( position ), value );
|
registerParameterBinding( getParameter( position ), value, temporalType );
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue