HHH-8452 - Better parameter handling for JPA criteria queries
This commit is contained in:
parent
bfe564e810
commit
8cfa73c3a1
|
@ -30,6 +30,7 @@ import javax.persistence.criteria.Predicate;
|
|||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.criteria.Subquery;
|
||||
import javax.persistence.metamodel.EntityType;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
|
@ -123,11 +124,13 @@ public abstract class AbstractManipulationCriteriaQuery<T> implements Compilable
|
|||
HibernateEntityManagerImplementor entityManager,
|
||||
final InterpretedParameterMetadata interpretedParameterMetadata) {
|
||||
|
||||
final Map<String,Class> implicitParameterTypes = extractTypeMap( interpretedParameterMetadata.implicitParameterBindings() );
|
||||
|
||||
QueryImpl jpaqlQuery = entityManager.createQuery(
|
||||
jpaqlString,
|
||||
null,
|
||||
null,
|
||||
new HibernateEntityManagerImplementor.Options() {
|
||||
new HibernateEntityManagerImplementor.QueryOptions() {
|
||||
@Override
|
||||
public List<ValueHandlerFactory.ValueHandler> getValueHandlers() {
|
||||
return null;
|
||||
|
@ -135,7 +138,7 @@ public abstract class AbstractManipulationCriteriaQuery<T> implements Compilable
|
|||
|
||||
@Override
|
||||
public Map<String, Class> getNamedParameterExplicitTypes() {
|
||||
return interpretedParameterMetadata.implicitParameterTypes();
|
||||
return implicitParameterTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -151,6 +154,14 @@ public abstract class AbstractManipulationCriteriaQuery<T> implements Compilable
|
|||
|
||||
return jpaqlQuery;
|
||||
}
|
||||
|
||||
private Map<String, Class> extractTypeMap(List<ImplicitParameterBinding> implicitParameterBindings) {
|
||||
final HashMap<String,Class> map = new HashMap<String, Class>();
|
||||
for ( ImplicitParameterBinding implicitParameter : implicitParameterBindings ) {
|
||||
map.put( implicitParameter.getParameterName(), implicitParameter.getJavaType() );
|
||||
}
|
||||
return map;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ package org.hibernate.jpa.criteria;
|
|||
import java.io.Serializable;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -44,8 +44,6 @@ import javax.persistence.metamodel.EntityType;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.jpa.internal.QueryImpl;
|
||||
import org.hibernate.jpa.criteria.compile.CompilableCriteria;
|
||||
import org.hibernate.jpa.criteria.compile.CriteriaInterpretation;
|
||||
|
@ -333,11 +331,13 @@ public class CriteriaQueryImpl<T> extends AbstractNode implements CriteriaQuery<
|
|||
@SuppressWarnings("unchecked")
|
||||
public Query buildCompiledQuery(HibernateEntityManagerImplementor entityManager, final InterpretedParameterMetadata parameterMetadata) {
|
||||
|
||||
final Map<String,Class> implicitParameterTypes = extractTypeMap( parameterMetadata.implicitParameterBindings() );
|
||||
|
||||
QueryImpl jpaqlQuery = entityManager.createQuery(
|
||||
jpaqlString,
|
||||
getResultType(),
|
||||
getSelection(),
|
||||
new HibernateEntityManagerImplementor.Options() {
|
||||
new HibernateEntityManagerImplementor.QueryOptions() {
|
||||
@Override
|
||||
public List<ValueHandlerFactory.ValueHandler> getValueHandlers() {
|
||||
SelectionImplementor selection = (SelectionImplementor) queryStructure.getSelection();
|
||||
|
@ -348,12 +348,12 @@ public class CriteriaQueryImpl<T> extends AbstractNode implements CriteriaQuery<
|
|||
|
||||
@Override
|
||||
public Map<String, Class> getNamedParameterExplicitTypes() {
|
||||
return parameterMetadata.implicitParameterTypes();
|
||||
return implicitParameterTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultMetadataValidator getResultMetadataValidator() {
|
||||
return new HibernateEntityManagerImplementor.Options.ResultMetadataValidator() {
|
||||
return new HibernateEntityManagerImplementor.QueryOptions.ResultMetadataValidator() {
|
||||
@Override
|
||||
public void validate(Type[] returnTypes) {
|
||||
SelectionImplementor selection = (SelectionImplementor) queryStructure.getSelection();
|
||||
|
@ -377,7 +377,8 @@ public class CriteriaQueryImpl<T> extends AbstractNode implements CriteriaQuery<
|
|||
}
|
||||
}
|
||||
}
|
||||
}; }
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -388,10 +389,17 @@ public class CriteriaQueryImpl<T> extends AbstractNode implements CriteriaQuery<
|
|||
return new CriteriaQueryTypeQueryAdapter(
|
||||
entityManager,
|
||||
jpaqlQuery,
|
||||
parameterMetadata.explicitParameterMapping(),
|
||||
parameterMetadata.explicitParameterNameMapping()
|
||||
parameterMetadata.explicitParameterInfoMap()
|
||||
);
|
||||
}
|
||||
|
||||
private Map<String, Class> extractTypeMap(List<ImplicitParameterBinding> implicitParameterBindings) {
|
||||
final HashMap<String,Class> map = new HashMap<String, Class>();
|
||||
for ( ImplicitParameterBinding implicitParameter : implicitParameterBindings ) {
|
||||
map.put( implicitParameter.getParameterName(), implicitParameter.getJavaType() );
|
||||
}
|
||||
return map;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,10 +56,10 @@ public class CriteriaCompiler implements Serializable {
|
|||
public Query compile(CompilableCriteria criteria) {
|
||||
criteria.validate();
|
||||
|
||||
final Map<ParameterExpression<?>,String> explicitParameterMapping = new HashMap<ParameterExpression<?>,String>();
|
||||
final Map<String,ParameterExpression<?>> explicitParameterNameMapping = new HashMap<String,ParameterExpression<?>>();
|
||||
final Map<ParameterExpression<?>, ExplicitParameterInfo<?>> explicitParameterInfoMap =
|
||||
new HashMap<ParameterExpression<?>, ExplicitParameterInfo<?>>();
|
||||
|
||||
final List<ImplicitParameterBinding> implicitParameterBindings = new ArrayList<ImplicitParameterBinding>();
|
||||
final Map<String,Class> implicitParameterTypes = new HashMap<String, Class>();
|
||||
|
||||
RenderingContext renderingContext = new RenderingContext() {
|
||||
private int aliasCount = 0;
|
||||
|
@ -73,22 +73,37 @@ public class CriteriaCompiler implements Serializable {
|
|||
return "param" + explicitParameterCount++;
|
||||
}
|
||||
|
||||
public String registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter) {
|
||||
final String jpaqlParameterName;
|
||||
if ( explicitParameterMapping.containsKey( criteriaQueryParameter ) ) {
|
||||
jpaqlParameterName = explicitParameterMapping.get( criteriaQueryParameter );
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public ExplicitParameterInfo registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter) {
|
||||
ExplicitParameterInfo parameterInfo = explicitParameterInfoMap.get( criteriaQueryParameter );
|
||||
if ( parameterInfo == null ) {
|
||||
if ( StringHelper.isNotEmpty( criteriaQueryParameter.getName() ) ) {
|
||||
parameterInfo = new ExplicitParameterInfo(
|
||||
criteriaQueryParameter.getName(),
|
||||
null,
|
||||
criteriaQueryParameter.getJavaType()
|
||||
);
|
||||
}
|
||||
else if ( criteriaQueryParameter.getPosition() != null ) {
|
||||
parameterInfo = new ExplicitParameterInfo(
|
||||
null,
|
||||
criteriaQueryParameter.getPosition(),
|
||||
criteriaQueryParameter.getJavaType()
|
||||
);
|
||||
}
|
||||
else {
|
||||
parameterInfo = new ExplicitParameterInfo(
|
||||
generateParameterName(),
|
||||
null,
|
||||
criteriaQueryParameter.getJavaType()
|
||||
);
|
||||
}
|
||||
|
||||
explicitParameterInfoMap.put( criteriaQueryParameter, parameterInfo );
|
||||
}
|
||||
else {
|
||||
jpaqlParameterName = generateParameterName();
|
||||
explicitParameterMapping.put( criteriaQueryParameter, jpaqlParameterName );
|
||||
}
|
||||
if ( StringHelper.isNotEmpty( criteriaQueryParameter.getName() ) ) {
|
||||
explicitParameterNameMapping.put(
|
||||
criteriaQueryParameter.getName(),
|
||||
criteriaQueryParameter
|
||||
);
|
||||
}
|
||||
return jpaqlParameterName;
|
||||
|
||||
return parameterInfo;
|
||||
}
|
||||
|
||||
public String registerLiteralParameterBinding(final Object literal, final Class javaType) {
|
||||
|
@ -108,7 +123,6 @@ public class CriteriaCompiler implements Serializable {
|
|||
};
|
||||
|
||||
implicitParameterBindings.add( binding );
|
||||
implicitParameterTypes.put( parameterName, javaType );
|
||||
return parameterName;
|
||||
}
|
||||
|
||||
|
@ -129,24 +143,14 @@ public class CriteriaCompiler implements Serializable {
|
|||
entityManager,
|
||||
new InterpretedParameterMetadata() {
|
||||
@Override
|
||||
public Map<ParameterExpression<?>, String> explicitParameterMapping() {
|
||||
return explicitParameterMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, ParameterExpression<?>> explicitParameterNameMapping() {
|
||||
return explicitParameterNameMapping;
|
||||
public Map<ParameterExpression<?>, ExplicitParameterInfo<?>> explicitParameterInfoMap() {
|
||||
return explicitParameterInfoMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ImplicitParameterBinding> implicitParameterBindings() {
|
||||
return implicitParameterBindings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Class> implicitParameterTypes() {
|
||||
return implicitParameterTypes;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import javax.persistence.TypedQuery;
|
|||
import javax.persistence.criteria.ParameterExpression;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -45,151 +46,187 @@ import org.hibernate.jpa.spi.HibernateEntityManagerImplementor;
|
|||
*/
|
||||
public class CriteriaQueryTypeQueryAdapter<X> implements TypedQuery<X>, HibernateQuery {
|
||||
private final HibernateEntityManagerImplementor entityManager;
|
||||
private final QueryImpl<X> jpaqlQuery;
|
||||
private final Map<ParameterExpression<?>, String> explicitParameterMapping;
|
||||
private final Map<String, ParameterExpression<?>> explicitParameterNameMapping;
|
||||
private final QueryImpl<X> jpqlQuery;
|
||||
private final Map<ParameterExpression<?>, ExplicitParameterInfo<?>> explicitParameterInfoMap;
|
||||
|
||||
public CriteriaQueryTypeQueryAdapter(
|
||||
HibernateEntityManagerImplementor entityManager,
|
||||
QueryImpl<X> jpaqlQuery,
|
||||
Map<ParameterExpression<?>, String> explicitParameterMapping,
|
||||
Map<String, ParameterExpression<?>> explicitParameterNameMapping) {
|
||||
QueryImpl<X> jpqlQuery,
|
||||
Map<ParameterExpression<?>, ExplicitParameterInfo<?>> explicitParameterInfoMap) {
|
||||
this.entityManager = entityManager;
|
||||
this.jpaqlQuery = jpaqlQuery;
|
||||
this.explicitParameterMapping = explicitParameterMapping;
|
||||
this.explicitParameterNameMapping = explicitParameterNameMapping;
|
||||
this.jpqlQuery = jpqlQuery;
|
||||
this.explicitParameterInfoMap = explicitParameterInfoMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query getHibernateQuery() {
|
||||
return jpaqlQuery.getHibernateQuery();
|
||||
return jpqlQuery.getHibernateQuery();
|
||||
}
|
||||
|
||||
public List<X> getResultList() {
|
||||
return jpaqlQuery.getResultList();
|
||||
return jpqlQuery.getResultList();
|
||||
}
|
||||
|
||||
public X getSingleResult() {
|
||||
return jpaqlQuery.getSingleResult();
|
||||
return jpqlQuery.getSingleResult();
|
||||
}
|
||||
|
||||
public int getMaxResults() {
|
||||
return jpaqlQuery.getMaxResults();
|
||||
return jpqlQuery.getMaxResults();
|
||||
}
|
||||
|
||||
public TypedQuery<X> setMaxResults(int i) {
|
||||
jpaqlQuery.setMaxResults( i );
|
||||
jpqlQuery.setMaxResults( i );
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getFirstResult() {
|
||||
return jpaqlQuery.getFirstResult();
|
||||
return jpqlQuery.getFirstResult();
|
||||
}
|
||||
|
||||
public TypedQuery<X> setFirstResult(int i) {
|
||||
jpaqlQuery.setFirstResult( i );
|
||||
jpqlQuery.setFirstResult( i );
|
||||
return this;
|
||||
}
|
||||
|
||||
public Map<String, Object> getHints() {
|
||||
return jpaqlQuery.getHints();
|
||||
return jpqlQuery.getHints();
|
||||
}
|
||||
|
||||
public TypedQuery<X> setHint(String name, Object value) {
|
||||
jpaqlQuery.setHint( name, value);
|
||||
jpqlQuery.setHint( name, value );
|
||||
return this;
|
||||
}
|
||||
|
||||
public FlushModeType getFlushMode() {
|
||||
return jpaqlQuery.getFlushMode();
|
||||
return jpqlQuery.getFlushMode();
|
||||
}
|
||||
|
||||
public TypedQuery<X> setFlushMode(FlushModeType flushModeType) {
|
||||
jpaqlQuery.setFlushMode( flushModeType );
|
||||
jpqlQuery.setFlushMode( flushModeType );
|
||||
return this;
|
||||
}
|
||||
|
||||
public LockModeType getLockMode() {
|
||||
return jpaqlQuery.getLockMode();
|
||||
return jpqlQuery.getLockMode();
|
||||
}
|
||||
|
||||
public TypedQuery<X> setLockMode(LockModeType lockModeType) {
|
||||
jpaqlQuery.setLockMode( lockModeType );
|
||||
jpqlQuery.setLockMode( lockModeType );
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public Set getParameters() {
|
||||
public Set<Parameter<?>> getParameters() {
|
||||
entityManager.checkOpen( false );
|
||||
return explicitParameterMapping.keySet();
|
||||
return new HashSet( explicitParameterInfoMap.values() );
|
||||
}
|
||||
|
||||
public boolean isBound(Parameter<?> param) {
|
||||
entityManager.checkOpen( false );
|
||||
return jpaqlQuery.isBound( param );
|
||||
return jpqlQuery.isBound( param );
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public <T> T getParameterValue(Parameter<T> param) {
|
||||
entityManager.checkOpen( false );
|
||||
return ( T ) jpaqlQuery.getParameterValue( mapToNamedParameter( param ) );
|
||||
final ExplicitParameterInfo parameterInfo = resolveParameterInfo( param );
|
||||
if ( parameterInfo.isNamed() ) {
|
||||
return ( T ) jpqlQuery.getParameterValue( parameterInfo.getName() );
|
||||
}
|
||||
else {
|
||||
return ( T ) jpqlQuery.getParameterValue( parameterInfo.getPosition() );
|
||||
}
|
||||
}
|
||||
|
||||
private <T> ExplicitParameterInfo resolveParameterInfo(Parameter<T> param) {
|
||||
if ( ExplicitParameterInfo.class.isInstance( param ) ) {
|
||||
return (ExplicitParameterInfo) param;
|
||||
}
|
||||
else if ( ParameterExpression.class.isInstance( param ) ) {
|
||||
return explicitParameterInfoMap.get( (ParameterExpression) param );
|
||||
}
|
||||
else {
|
||||
for ( ExplicitParameterInfo parameterInfo : explicitParameterInfoMap.values() ) {
|
||||
if ( param.getName() != null && param.getName().equals( parameterInfo.getName() ) ) {
|
||||
return parameterInfo;
|
||||
}
|
||||
else if ( param.getPosition() != null && param.getPosition().equals( parameterInfo.getPosition() ) ) {
|
||||
return parameterInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException( "Unable to locate parameter [" + param + "] in query" );
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public <T> TypedQuery<X> setParameter(Parameter<T> param, T t) {
|
||||
entityManager.checkOpen( false );
|
||||
jpaqlQuery.setParameter( mapToNamedParameter( param ), t );
|
||||
final ExplicitParameterInfo parameterInfo = resolveParameterInfo( param );
|
||||
if ( parameterInfo.isNamed() ) {
|
||||
jpqlQuery.setParameter( parameterInfo.getName(), t );
|
||||
}
|
||||
else {
|
||||
jpqlQuery.setParameter( parameterInfo.getPosition(), t );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "RedundantCast" })
|
||||
private Parameter mapToNamedParameter(Parameter criteriaParameter) {
|
||||
return jpaqlQuery.getParameter(
|
||||
explicitParameterMapping.get( criteriaParameter )
|
||||
);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public TypedQuery<X> setParameter(Parameter<Calendar> param, Calendar calendar, TemporalType temporalType) {
|
||||
entityManager.checkOpen( false );
|
||||
jpaqlQuery.setParameter( mapToNamedParameter( param ), calendar, temporalType );
|
||||
final ExplicitParameterInfo parameterInfo = resolveParameterInfo( param );
|
||||
if ( parameterInfo.isNamed() ) {
|
||||
jpqlQuery.setParameter( parameterInfo.getName(), calendar, temporalType );
|
||||
}
|
||||
else {
|
||||
jpqlQuery.setParameter( parameterInfo.getPosition(), calendar, temporalType );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public TypedQuery<X> setParameter(Parameter<Date> param, Date date, TemporalType temporalType) {
|
||||
entityManager.checkOpen( false );
|
||||
jpaqlQuery.setParameter( mapToNamedParameter( param ), date, temporalType );
|
||||
final ExplicitParameterInfo parameterInfo = resolveParameterInfo( param );
|
||||
if ( parameterInfo.isNamed() ) {
|
||||
jpqlQuery.setParameter( parameterInfo.getName(), date, temporalType );
|
||||
}
|
||||
else {
|
||||
jpqlQuery.setParameter( parameterInfo.getPosition(), date, temporalType );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> T unwrap(Class<T> cls) {
|
||||
return jpaqlQuery.unwrap( cls );
|
||||
return jpqlQuery.unwrap( cls );
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public Object getParameterValue(String name) {
|
||||
entityManager.checkOpen( false );
|
||||
return getParameterValue( resolveExplicitCriteriaParameterName( name ) );
|
||||
locateParameterByName( name );
|
||||
return jpqlQuery.getParameter( name );
|
||||
}
|
||||
|
||||
private Parameter resolveExplicitCriteriaParameterName(String name) {
|
||||
Parameter parameter = explicitParameterNameMapping.get( name );
|
||||
if ( parameter == null ) {
|
||||
throw new IllegalArgumentException( "Named parameter [" + name + "] not encountered" );
|
||||
private ExplicitParameterInfo locateParameterByName(String name) {
|
||||
for ( ExplicitParameterInfo parameterInfo : explicitParameterInfoMap.values() ) {
|
||||
if ( parameterInfo.isNamed() && parameterInfo.getName().equals( name ) ) {
|
||||
return parameterInfo;
|
||||
}
|
||||
}
|
||||
return parameter;
|
||||
throw new IllegalArgumentException( "Unable to locate parameter registered with that name [" + name + "]" );
|
||||
}
|
||||
|
||||
public Parameter<?> getParameter(String name) {
|
||||
entityManager.checkOpen( false );
|
||||
return mapToNamedParameter( resolveExplicitCriteriaParameterName( name ) );
|
||||
return locateParameterByName( name );
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public <T> Parameter<T> getParameter(String name, Class<T> type) {
|
||||
entityManager.checkOpen( false );
|
||||
Parameter parameter = resolveExplicitCriteriaParameterName( name );
|
||||
Parameter parameter = locateParameterByName( name );
|
||||
if ( type.isAssignableFrom( parameter.getParameterType() ) ) {
|
||||
return parameter;
|
||||
}
|
||||
|
@ -202,55 +239,27 @@ public class CriteriaQueryTypeQueryAdapter<X> implements TypedQuery<X>, Hibernat
|
|||
@SuppressWarnings({ "unchecked" })
|
||||
public TypedQuery<X> setParameter(String name, Object value) {
|
||||
entityManager.checkOpen( true );
|
||||
setParameter(
|
||||
resolveExplicitCriteriaParameterName( name, value ),
|
||||
value
|
||||
);
|
||||
ExplicitParameterInfo parameterInfo = locateParameterByName( name );
|
||||
parameterInfo.validateBindValue( value );
|
||||
jpqlQuery.setParameter( name, value );
|
||||
return this;
|
||||
}
|
||||
|
||||
private Parameter resolveExplicitCriteriaParameterName(String name, Object value) {
|
||||
Parameter parameter = resolveExplicitCriteriaParameterName( name );
|
||||
// todo : is null valid?
|
||||
if ( value != null ) {
|
||||
if ( ! parameter.getParameterType().isInstance( value ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Named parameter [" + name + "] type mismatch; expecting ["
|
||||
+ parameter.getParameterType().getName() + "], found ["
|
||||
+ value.getClass().getName() + "]"
|
||||
);
|
||||
}
|
||||
}
|
||||
return parameter;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public TypedQuery<X> setParameter(String name, Calendar calendar, TemporalType temporalType) {
|
||||
entityManager.checkOpen( true );
|
||||
Parameter parameter = resolveExplicitCriteriaParameterName( name );
|
||||
if ( ! Calendar.class.isAssignableFrom( parameter.getParameterType() ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Named parameter [" + name + "] type mismatch; expecting ["
|
||||
+ Calendar.class.getName() + "], found ["
|
||||
+ parameter.getParameterType().getName() + "]"
|
||||
);
|
||||
}
|
||||
setParameter( parameter, calendar, temporalType );
|
||||
ExplicitParameterInfo parameterInfo = locateParameterByName( name );
|
||||
parameterInfo.validateCalendarBind();
|
||||
jpqlQuery.setParameter( name, calendar, temporalType );
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public TypedQuery<X> setParameter(String name, Date date, TemporalType temporalType) {
|
||||
entityManager.checkOpen( true );
|
||||
Parameter parameter = resolveExplicitCriteriaParameterName( name );
|
||||
if ( ! Date.class.isAssignableFrom( parameter.getParameterType() ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Named parameter [" + name + "] type mismatch; expecting ["
|
||||
+ Date.class.getName() + "], found ["
|
||||
+ parameter.getParameterType().getName() + "]"
|
||||
);
|
||||
}
|
||||
setParameter( parameter, date, temporalType );
|
||||
ExplicitParameterInfo parameterInfo = locateParameterByName( name );
|
||||
parameterInfo.validateDateBind();
|
||||
jpqlQuery.setParameter( name, date, temporalType );
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,153 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.jpa.criteria.compile;
|
||||
|
||||
import javax.persistence.Parameter;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ExplicitParameterInfo<T> implements Parameter<T> {
|
||||
private final String name;
|
||||
private final Integer position;
|
||||
private final Class<T> type;
|
||||
|
||||
public ExplicitParameterInfo(String name, Integer position, Class<T> type) {
|
||||
if ( name == null && position == null ) {
|
||||
throw new IllegalStateException( "Both name and position were null; caller should have generated parameter name" );
|
||||
}
|
||||
if ( name != null && position != null ) {
|
||||
throw new IllegalStateException( "Both name and position were specified" );
|
||||
}
|
||||
|
||||
this.name = name;
|
||||
this.position = position;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public boolean isNamed() {
|
||||
return name != null;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Integer getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<T> getParameterType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders this parameter's JPQL form
|
||||
*
|
||||
* @return The rendered form
|
||||
*/
|
||||
public String render() {
|
||||
return isNamed()
|
||||
? ":" + name
|
||||
: "?" + position.toString();
|
||||
}
|
||||
|
||||
public void validateBindValue(Object value) {
|
||||
if ( value == null ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( ! getParameterType().isInstance( value ) ) {
|
||||
if ( isNamed() ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Named parameter [%s] type mismatch; expecting [%s] but found [%s]",
|
||||
getName(),
|
||||
getParameterType().getSimpleName(),
|
||||
value.getClass().getSimpleName()
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Positional parameter [%s] type mismatch; expecting [%s] but found [%s]",
|
||||
getPosition(),
|
||||
getParameterType().getSimpleName(),
|
||||
value.getClass().getSimpleName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void validateCalendarBind() {
|
||||
if ( ! Calendar.class.isAssignableFrom( getParameterType() ) ) {
|
||||
if ( isNamed() ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Named parameter [%s] type mismatch; Calendar was passed, but parameter defined as [%s]",
|
||||
getName(),
|
||||
getParameterType().getSimpleName()
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Positional parameter [%s] type mismatch; Calendar was passed, but parameter defined as [%s]",
|
||||
getPosition(),
|
||||
getParameterType().getSimpleName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void validateDateBind() {
|
||||
if ( !Date.class.isAssignableFrom( getParameterType() ) ) {
|
||||
if ( isNamed() ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Named parameter [%s] type mismatch; Date was passed, but parameter defined as [%s]",
|
||||
getName(),
|
||||
getParameterType().getSimpleName()
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Positional parameter [%s] type mismatch; Date was passed, but parameter defined as [%s]",
|
||||
getPosition(),
|
||||
getParameterType().getSimpleName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ public interface ImplicitParameterBinding {
|
|||
|
||||
/**
|
||||
* Get the java type of the "thing" that led to the implicit parameter. Used from
|
||||
* {@link org.hibernate.ejb.HibernateEntityManagerImplementor.Options#getNamedParameterExplicitTypes()}
|
||||
* {@link org.hibernate.jpa.spi.HibernateEntityManagerImplementor.QueryOptions#getNamedParameterExplicitTypes()}
|
||||
* in determining "guessed type" overriding.
|
||||
*
|
||||
* @return The java type
|
||||
|
|
|
@ -28,11 +28,15 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Represents information about parameters from a compiled criteria query.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface InterpretedParameterMetadata {
|
||||
public Map<ParameterExpression<?>,String> explicitParameterMapping();
|
||||
public Map<String,ParameterExpression<?>> explicitParameterNameMapping();
|
||||
public Map<ParameterExpression<?>, ExplicitParameterInfo<?>> explicitParameterInfoMap();
|
||||
|
||||
// public Map<ParameterExpression<?>,String> explicitParameterMapping();
|
||||
// public Map<String,ParameterExpression<?>> explicitParameterNameMapping();
|
||||
public List<ImplicitParameterBinding> implicitParameterBindings();
|
||||
public Map<String,Class> implicitParameterTypes();
|
||||
// public Map<String,Class> implicitParameterTypes();
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ public interface RenderingContext {
|
|||
*
|
||||
* @return The JPA-QL parameter name
|
||||
*/
|
||||
public String registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter);
|
||||
public ExplicitParameterInfo registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter);
|
||||
|
||||
/**
|
||||
* Register a parameter that was not part of the criteria query (at least not as a parameter).
|
||||
|
|
|
@ -28,6 +28,7 @@ import javax.persistence.criteria.ParameterExpression;
|
|||
|
||||
import org.hibernate.jpa.criteria.CriteriaBuilderImpl;
|
||||
import org.hibernate.jpa.criteria.ParameterRegistry;
|
||||
import org.hibernate.jpa.criteria.compile.ExplicitParameterInfo;
|
||||
import org.hibernate.jpa.criteria.compile.RenderingContext;
|
||||
|
||||
/**
|
||||
|
@ -85,8 +86,8 @@ public class ParameterExpressionImpl<T>
|
|||
}
|
||||
|
||||
public String render(RenderingContext renderingContext) {
|
||||
final String jpaqlParamName = renderingContext.registerExplicitParameter( this );
|
||||
return ':' + jpaqlParamName;
|
||||
final ExplicitParameterInfo parameterInfo = renderingContext.registerExplicitParameter( this );
|
||||
return parameterInfo.render();
|
||||
}
|
||||
|
||||
public String renderProjection(RenderingContext renderingContext) {
|
||||
|
|
|
@ -83,12 +83,10 @@ import org.hibernate.SQLQuery;
|
|||
import org.hibernate.Session;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.StaleStateException;
|
||||
import org.hibernate.procedure.ProcedureCall;
|
||||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.TypeMismatchException;
|
||||
import org.hibernate.UnresolvableObjectException;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.cfg.NotYetImplementedException;
|
||||
import org.hibernate.dialect.lock.LockingStrategyException;
|
||||
import org.hibernate.dialect.lock.OptimisticEntityLockException;
|
||||
import org.hibernate.dialect.lock.PessimisticEntityLockException;
|
||||
|
@ -552,13 +550,13 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
|||
String jpaqlString,
|
||||
Class<T> resultClass,
|
||||
Selection selection,
|
||||
Options options) {
|
||||
QueryOptions queryOptions) {
|
||||
try {
|
||||
org.hibernate.Query hqlQuery = internalGetSession().createQuery( jpaqlString );
|
||||
|
||||
if ( options.getValueHandlers() == null ) {
|
||||
if ( options.getResultMetadataValidator() != null ) {
|
||||
options.getResultMetadataValidator().validate( hqlQuery.getReturnTypes() );
|
||||
if ( queryOptions.getValueHandlers() == null ) {
|
||||
if ( queryOptions.getResultMetadataValidator() != null ) {
|
||||
queryOptions.getResultMetadataValidator().validate( hqlQuery.getReturnTypes() );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -566,12 +564,12 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
|||
List tupleElements = Tuple.class.equals( resultClass )
|
||||
? ( ( CompoundSelectionImpl<Tuple> ) selection ).getCompoundSelectionItems()
|
||||
: null;
|
||||
if ( options.getValueHandlers() != null || tupleElements != null ) {
|
||||
if ( queryOptions.getValueHandlers() != null || tupleElements != null ) {
|
||||
hqlQuery.setResultTransformer(
|
||||
new CriteriaQueryTransformer( options.getValueHandlers(), tupleElements )
|
||||
new CriteriaQueryTransformer( queryOptions.getValueHandlers(), tupleElements )
|
||||
);
|
||||
}
|
||||
return new QueryImpl<T>( hqlQuery, this, options.getNamedParameterExplicitTypes() );
|
||||
return new QueryImpl<T>( hqlQuery, this, queryOptions.getNamedParameterExplicitTypes() );
|
||||
}
|
||||
catch ( HibernateException he ) {
|
||||
throw convert( he );
|
||||
|
|
|
@ -131,11 +131,13 @@ public interface HibernateEntityManagerImplementor extends HibernateEntityManage
|
|||
*/
|
||||
public LockOptions getLockRequest(LockModeType lockModeType, Map<String, Object> properties);
|
||||
|
||||
public static interface Options {
|
||||
public static interface QueryOptions {
|
||||
public static interface ResultMetadataValidator {
|
||||
public void validate(Type[] returnTypes);
|
||||
}
|
||||
|
||||
public ResultMetadataValidator getResultMetadataValidator();
|
||||
|
||||
/**
|
||||
* Get the conversions for the individual tuples in the query results.
|
||||
*
|
||||
|
@ -150,8 +152,6 @@ public interface HibernateEntityManagerImplementor extends HibernateEntityManage
|
|||
* @return The
|
||||
*/
|
||||
public Map<String, Class> getNamedParameterExplicitTypes();
|
||||
|
||||
public ResultMetadataValidator getResultMetadataValidator();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -160,10 +160,10 @@ public interface HibernateEntityManagerImplementor extends HibernateEntityManage
|
|||
* @param jpaqlString The criteria query rendered as a JPA QL string
|
||||
* @param resultClass The result type (the type expected in the result list)
|
||||
* @param selection The selection(s)
|
||||
* @param options The options to use to build the query.
|
||||
* @param queryOptions The options to use to build the query.
|
||||
* @param <T> The query type
|
||||
*
|
||||
* @return The typed query
|
||||
*/
|
||||
public <T> QueryImpl<T> createQuery(String jpaqlString, Class<T> resultClass, Selection selection, Options options);
|
||||
public <T> QueryImpl<T> createQuery(String jpaqlString, Class<T> resultClass, Selection selection, QueryOptions queryOptions);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
package org.hibernate.jpa.test.criteria;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Parameter;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.ParameterExpression;
|
||||
|
@ -34,6 +35,8 @@ import org.junit.Test;
|
|||
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -73,6 +76,26 @@ public class ParameterTest extends BaseEntityManagerFunctionalTestCase {
|
|||
em.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNamedParameterMetadata() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
CriteriaQuery<MultiTypedBasicAttributesEntity> criteria = em.getCriteriaBuilder()
|
||||
.createQuery( MultiTypedBasicAttributesEntity.class );
|
||||
Root<MultiTypedBasicAttributesEntity> rootEntity = criteria.from( MultiTypedBasicAttributesEntity.class );
|
||||
|
||||
criteria.where(
|
||||
em.getCriteriaBuilder().equal(
|
||||
rootEntity.get( MultiTypedBasicAttributesEntity_.id ),
|
||||
em.getCriteriaBuilder().parameter( Long.class, "id" )
|
||||
)
|
||||
);
|
||||
|
||||
TypedQuery<MultiTypedBasicAttributesEntity> query = em.createQuery( criteria );
|
||||
Parameter parameter = query.getParameter( "id" );
|
||||
assertEquals( "id", parameter.getName() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class[] getAnnotatedClasses() {
|
||||
return new Class[] { MultiTypedBasicAttributesEntity.class };
|
||||
|
|
Loading…
Reference in New Issue