HHH-8419 - Tie javax.persistence.Parameter instance to javax.persistence.Query instance

This commit is contained in:
Steve Ebersole 2013-08-05 11:23:45 -05:00
parent 742b1b4156
commit 3d595febc5
5 changed files with 194 additions and 63 deletions

View File

@ -61,6 +61,8 @@ import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
import org.hibernate.jpa.spi.AbstractEntityManagerImpl;
import org.hibernate.jpa.spi.AbstractQueryImpl;
import org.hibernate.jpa.spi.ParameterBind;
import org.hibernate.jpa.spi.ParameterRegistration;
import org.hibernate.type.CompositeCustomType;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
@ -112,7 +114,7 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
else if ( descriptor.getExpectedType() != null ) {
javaType = descriptor.getExpectedType().getReturnedClass();
}
registerParameter( new ParameterRegistrationImpl( query, name, javaType ) );
registerParameter( new ParameterRegistrationImpl( this, query, name, javaType ) );
if ( descriptor.isJpaStyle() ) {
if ( jpaPositionalIndices == null ) {
jpaPositionalIndices = new HashSet<Integer>();
@ -125,7 +127,7 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
for ( int i = 0, max = parameterMetadata.getOrdinalParameterCount(); i < max; i++ ) {
final OrdinalParameterDescriptor descriptor = parameterMetadata.getOrdinalParameterDescriptor( i + 1 );
Class javaType = descriptor.getExpectedType() == null ? null : descriptor.getExpectedType().getReturnedClass();
registerParameter( new ParameterRegistrationImpl( query, i+1, javaType ) );
registerParameter( new ParameterRegistrationImpl( this, query, i+1, javaType ) );
Integer position = descriptor.getOrdinalPosition();
if ( jpaPositionalIndices != null && jpaPositionalIndices.contains(position) ) {
LOG.parameterPositionOccurredAsBothJpaAndHibernatePositionalParameter(position);
@ -147,7 +149,8 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
}
private static class ParameterRegistrationImpl<T> implements ParameterRegistration<T> {
private final org.hibernate.Query query;
private final Query jpaQuery;
private final org.hibernate.Query nativeQuery;
private final String name;
private final Integer position;
@ -155,20 +158,35 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
private ParameterBind<T> bind;
private ParameterRegistrationImpl(org.hibernate.Query query, String name, Class<T> javaType) {
this.query = query;
private ParameterRegistrationImpl(
Query jpaQuery,
org.hibernate.Query nativeQuery,
String name,
Class<T> javaType) {
this.jpaQuery = jpaQuery;
this.nativeQuery = nativeQuery;
this.name = name;
this.javaType = javaType;
this.position = null;
}
private ParameterRegistrationImpl(org.hibernate.Query query, Integer position, Class<T> javaType) {
this.query = query;
private ParameterRegistrationImpl(
Query jpaQuery,
org.hibernate.Query nativeQuery,
Integer position,
Class<T> javaType) {
this.jpaQuery = jpaQuery;
this.nativeQuery = nativeQuery;
this.position = position;
this.javaType = javaType;
this.name = null;
}
@Override
public Query getQuery() {
return jpaQuery;
}
@Override
public String getName() {
return name;
@ -202,14 +220,14 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
if ( name != null ) {
if ( value instanceof Collection ) {
query.setParameterList( name, (Collection) value );
nativeQuery.setParameterList( name, (Collection) value );
}
else {
query.setParameter( name, value );
nativeQuery.setParameter( name, value );
}
}
else {
query.setParameter( position-1, value );
nativeQuery.setParameter( position - 1, value );
}
bind = new ParameterBindImpl<T>( value, null );
@ -222,48 +240,48 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
if ( Date.class.isInstance( value ) ) {
if ( name != null ) {
if ( specifiedTemporalType == DATE ) {
query.setDate( name, (Date) value );
nativeQuery.setDate( name, (Date) value );
}
else if ( specifiedTemporalType == TIME ) {
query.setTime( name, (Date) value );
nativeQuery.setTime( name, (Date) value );
}
else if ( specifiedTemporalType == TIMESTAMP ) {
query.setTimestamp( name, (Date) value );
nativeQuery.setTimestamp( name, (Date) value );
}
}
else {
if ( specifiedTemporalType == DATE ) {
query.setDate( position-1, (Date) value );
nativeQuery.setDate( position - 1, (Date) value );
}
else if ( specifiedTemporalType == TIME ) {
query.setTime( position-1, (Date) value );
nativeQuery.setTime( position - 1, (Date) value );
}
else if ( specifiedTemporalType == TIMESTAMP ) {
query.setTimestamp( position-1, (Date) value );
nativeQuery.setTimestamp( position - 1, (Date) value );
}
}
}
else if ( Calendar.class.isInstance( value ) ) {
if ( name != null ) {
if ( specifiedTemporalType == DATE ) {
query.setCalendarDate( name, (Calendar) value );
nativeQuery.setCalendarDate( name, (Calendar) value );
}
else if ( specifiedTemporalType == TIME ) {
throw new IllegalArgumentException( "not yet implemented" );
}
else if ( specifiedTemporalType == TIMESTAMP ) {
query.setCalendar( name, (Calendar) value );
nativeQuery.setCalendar( name, (Calendar) value );
}
}
else {
if ( specifiedTemporalType == DATE ) {
query.setCalendarDate( position-1, (Calendar) value );
nativeQuery.setCalendarDate( position - 1, (Calendar) value );
}
else if ( specifiedTemporalType == TIME ) {
throw new IllegalArgumentException( "not yet implemented" );
}
else if ( specifiedTemporalType == TIMESTAMP ) {
query.setCalendar( position-1, (Calendar) value );
nativeQuery.setCalendar( position - 1, (Calendar) value );
}
}
}

View File

@ -41,6 +41,8 @@ import java.util.List;
import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.LockMode;
import org.hibernate.jpa.spi.ParameterBind;
import org.hibernate.jpa.spi.ParameterRegistration;
import org.hibernate.procedure.NoSuchParameterException;
import org.hibernate.procedure.ParameterStrategyException;
import org.hibernate.procedure.ProcedureCall;
@ -76,7 +78,7 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
super( entityManager );
this.procedureCall = memento.makeProcedureCall( entityManager.getSession() );
for ( org.hibernate.procedure.ParameterRegistration nativeParamReg : procedureCall.getRegisteredParameters() ) {
registerParameter( new ParameterRegistrationImpl( nativeParamReg ) );
registerParameter( new ParameterRegistrationImpl( this, nativeParamReg ) );
}
}
@ -122,6 +124,7 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
entityManager().checkOpen( true );
registerParameter(
new ParameterRegistrationImpl(
this,
procedureCall.registerParameter( position, type, mode )
)
);
@ -134,6 +137,7 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
entityManager().checkOpen( true );
registerParameter(
new ParameterRegistrationImpl(
this,
procedureCall.registerParameter( parameterName, type, mode )
)
);
@ -407,11 +411,15 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
}
private static class ParameterRegistrationImpl<T> implements ParameterRegistration<T> {
private final StoredProcedureQueryImpl query;
private final org.hibernate.procedure.ParameterRegistration<T> nativeParamRegistration;
private ParameterBind<T> bind;
private ParameterRegistrationImpl(org.hibernate.procedure.ParameterRegistration<T> nativeParamRegistration) {
public ParameterRegistrationImpl(
StoredProcedureQueryImpl query,
org.hibernate.procedure.ParameterRegistration<T> nativeParamRegistration) {
this.query = query;
this.nativeParamRegistration = nativeParamRegistration;
}
@ -430,6 +438,11 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
return nativeParamRegistration.getType();
}
@Override
public Query getQuery() {
return query;
}
@Override
public ParameterMode getMode() {
return nativeParamRegistration.getMode();

View File

@ -27,7 +27,6 @@ import javax.persistence.CacheRetrieveMode;
import javax.persistence.CacheStoreMode;
import javax.persistence.FlushModeType;
import javax.persistence.Parameter;
import javax.persistence.ParameterMode;
import javax.persistence.Query;
import javax.persistence.TemporalType;
import java.util.Calendar;
@ -409,7 +408,12 @@ public abstract class BaseQueryImpl implements Query {
protected <X> ParameterRegistration<X> findParameterRegistration(Parameter<X> parameter) {
if ( ParameterRegistration.class.isInstance( parameter ) ) {
return (ParameterRegistration<X>) parameter;
final ParameterRegistration<X> reg = (ParameterRegistration<X>) parameter;
// validate the parameter source
if ( reg.getQuery() != this ) {
throw new IllegalArgumentException( "Passed Parameter was from different Query" );
}
return reg;
}
else {
if ( parameter.getName() != null ) {
@ -440,45 +444,6 @@ public abstract class BaseQueryImpl implements Query {
protected abstract boolean isJpaPositionalParameter(int position);
/**
* Hibernate specific extension to the JPA {@link javax.persistence.Parameter} contract. Used here to track
* information known about the parameter.
*/
protected static interface ParameterRegistration<T> extends Parameter<T> {
/**
* Retrieves the parameter "mode" which describes how the parameter is defined in the actual database procedure
* definition (is it an INPUT parameter? An OUTPUT parameter? etc).
*
* @return The parameter mode.
*/
public ParameterMode getMode();
/**
* Can we bind (set) values on this parameter? Generally this is {@code true}, but would not be in the case
* of parameters with OUT or REF_CURSOR mode.
*
* @return Whether the parameter is bindable (can set be called).
*/
public boolean isBindable();
public void bindValue(T value);
public void bindValue(T value, TemporalType specifiedTemporalType);
public ParameterBind<T> getBind();
}
/**
* Represents the value currently bound to a particular parameter.
*
* @param <T>
*/
protected static interface ParameterBind<T> {
public T getValue();
public TemporalType getSpecifiedTemporalType();
}
protected static class ParameterBindImpl<T> implements ParameterBind<T> {
private final T value;
private final TemporalType specifiedTemporalType;

View File

@ -0,0 +1,49 @@
/*
* 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.spi;
import javax.persistence.TemporalType;
/**
* Represents the value currently bound to a particular (bindable) parameter.
*
* @param <T>
*
* @author Steve Ebersole
*/
public interface ParameterBind<T> {
/**
* Access the bound value
*
* @return The bound value
*/
public T getValue();
/**
* The temporal type that will be used to "interpret" Date-like values (if applicable).
*
* @return The temporal type, or {@code null}
*/
public TemporalType getSpecifiedTemporalType();
}

View File

@ -0,0 +1,86 @@
/*
* 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.spi;
import javax.persistence.Parameter;
import javax.persistence.ParameterMode;
import javax.persistence.Query;
import javax.persistence.TemporalType;
/**
* Hibernate specific extension to the JPA {@link javax.persistence.Parameter} contract as known to the
* {@link javax.persistence.Query} and {@link javax.persistence.StoredProcedureQuery} implementations. Used to track
* information known about the parameter.
* <p/>
* For parameter information as known to JPA criteria queries, see {@link org.hibernate.jpa.criteria.expression.ParameterExpressionImpl}
* instead.
*
* @author Steve Ebersole
*/
public interface ParameterRegistration<T> extends Parameter<T> {
/**
* Access to the query that this parameter belongs to.
*
* @return The defining query
*/
public Query getQuery();
/**
* Retrieves the parameter "mode" which describes how the parameter is defined in the actual database procedure
* definition (is it an INPUT parameter? An OUTPUT parameter? etc).
*
* @return The parameter mode.
*/
public ParameterMode getMode();
/**
* Can we bind (set) values on this parameter? Generally this is {@code true}, but would not be in the case
* of parameters with OUT or REF_CURSOR mode.
*
* @return Whether the parameter is bindable (can set be called).
*/
public boolean isBindable();
/**
* If bindable, bind the value.
*
* @param value The value to bind.
*/
public void bindValue(T value);
/**
* If bindable, bind the value using the specific temporal type.
*
* @param value The value to bind
* @param specifiedTemporalType The temporal type to use in binding
*/
public void bindValue(T value, TemporalType specifiedTemporalType);
/**
* If bindable, get the current binding.
*
* @return The current binding
*/
public ParameterBind<T> getBind();
}