HHH-8452 - Better parameter handling for JPA criteria queries

This commit is contained in:
Steve Ebersole 2013-08-25 01:17:20 -05:00
parent bfe564e810
commit 8cfa73c3a1
12 changed files with 356 additions and 145 deletions

View File

@ -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;
}
};
}

View File

@ -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;
}
};
}
}

View File

@ -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;
}
}
);
}

View File

@ -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;
}

View File

@ -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()
)
);
}
}
}
}

View File

@ -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

View File

@ -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();
}

View File

@ -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).

View File

@ -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) {

View File

@ -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 );

View File

@ -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);
}

View File

@ -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 };