HHH-7957 - Integrate Latest draft(s) of the JPA 2.1 spec
This commit is contained in:
parent
04a9701f8b
commit
84520cd6e3
|
@ -97,7 +97,15 @@ public class EntityManagerImpl extends AbstractEntityManagerImpl implements Sess
|
|||
|
||||
@Override
|
||||
protected void checkOpen() {
|
||||
if( !isOpen() ) {
|
||||
checkOpen( true );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkOpen(boolean markForRollbackIfClosed) {
|
||||
if( ! isOpen() ) {
|
||||
if ( markForRollbackIfClosed ) {
|
||||
markAsRollback();
|
||||
}
|
||||
throw new IllegalStateException( "EntityManager is closed" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,6 @@ import org.hibernate.FlushMode;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.QueryParameterException;
|
||||
import org.hibernate.SQLQuery;
|
||||
import org.hibernate.TypeMismatchException;
|
||||
import org.hibernate.engine.query.spi.NamedParameterDescriptor;
|
||||
import org.hibernate.engine.query.spi.OrdinalParameterDescriptor;
|
||||
|
@ -152,7 +151,7 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
return java.util.Date.class.isAssignableFrom( javaType );
|
||||
}
|
||||
|
||||
private static class ParameterImpl implements Parameter {
|
||||
private static class ParameterImpl implements ParameterImplementor {
|
||||
private final String name;
|
||||
private final Integer position;
|
||||
private final Class javaType;
|
||||
|
@ -180,6 +179,121 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
public Class getParameterType() {
|
||||
return javaType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateBinding(Object bind, TemporalType temporalType) {
|
||||
if ( bind == null || getParameterType() == null ) {
|
||||
// nothing we can check
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Collection.class.isInstance( bind ) && ! Collection.class.isAssignableFrom( getParameterType() ) ) {
|
||||
// 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
|
||||
// NOTE2 : the case of a collection value and an expected collection (if that can even happen)
|
||||
// will fall through to the main check.
|
||||
validateCollectionValuedParameterBinding( (Collection) bind, temporalType );
|
||||
}
|
||||
else if ( bind.getClass().isArray() ) {
|
||||
validateArrayValuedParameterBinding( bind, temporalType );
|
||||
}
|
||||
else {
|
||||
if ( ! isValidBindValue( getParameterType(), bind, temporalType ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Parameter value [%s] did not match expected type [%s (%s)]",
|
||||
bind,
|
||||
getParameterType().getName(),
|
||||
extractName( temporalType )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String extractName(TemporalType temporalType) {
|
||||
return temporalType == null ? "n/a" : temporalType.name();
|
||||
}
|
||||
|
||||
private void validateCollectionValuedParameterBinding(Collection value, TemporalType temporalType) {
|
||||
// validate the elements...
|
||||
for ( Object element : value ) {
|
||||
if ( ! isValidBindValue( getParameterType(), element, temporalType ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Parameter value element [%s] did not match expected type [%s (%s)]",
|
||||
element,
|
||||
getParameterType().getName(),
|
||||
extractName( temporalType )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateArrayValuedParameterBinding(Object value, TemporalType temporalType) {
|
||||
if ( ! getParameterType().isArray() ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Encountered array-valued parameter binding, but was expecting [%s (%s)]",
|
||||
getParameterType().getName(),
|
||||
extractName( temporalType )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
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 ( ! 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 (%s)]",
|
||||
value.getClass().getComponentType().getName(),
|
||||
getParameterType().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( getParameterType().getComponentType(), element, temporalType ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Array-valued parameter value element [%s] did not match expected type [%s (%s)]",
|
||||
element,
|
||||
getParameterType().getName(),
|
||||
extractName( temporalType )
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static 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;
|
||||
}
|
||||
|
||||
public org.hibernate.Query getHibernateQuery() {
|
||||
|
@ -252,11 +366,10 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
query.getLockOptions().setAliasSpecificLockMode( alias, lockMode );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "RedundantCast" })
|
||||
public List<X> getResultList() {
|
||||
getEntityManager().checkOpen( true );
|
||||
try {
|
||||
return query.list();
|
||||
}
|
||||
|
@ -271,11 +384,10 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked", "RedundantCast" })
|
||||
public X getSingleResult() {
|
||||
getEntityManager().checkOpen( true );
|
||||
try {
|
||||
final List<X> result = query.list();
|
||||
|
||||
|
@ -310,7 +422,9 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> TypedQuery<X> setParameter(Parameter<T> param, T value) {
|
||||
getEntityManager().checkOpen( true );
|
||||
if ( ! parameters.contains( param ) ) {
|
||||
throw new IllegalArgumentException( "Specified parameter was not found in query" );
|
||||
}
|
||||
|
@ -324,7 +438,9 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedQuery<X> setParameter(Parameter<Date> param, Date value, TemporalType temporalType) {
|
||||
getEntityManager().checkOpen( true );
|
||||
if ( ! parameters.contains( param ) ) {
|
||||
throw new IllegalArgumentException( "Specified parameter was not found in query" );
|
||||
}
|
||||
|
@ -338,7 +454,9 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedQuery<X> setParameter(Parameter<Calendar> param, Calendar value, TemporalType temporalType) {
|
||||
getEntityManager().checkOpen( true );
|
||||
if ( ! parameters.contains( param ) ) {
|
||||
throw new IllegalArgumentException( "Specified parameter was not found in query" );
|
||||
}
|
||||
|
@ -352,10 +470,9 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public TypedQuery<X> setParameter(String name, Object value) {
|
||||
getEntityManager().checkOpen( true );
|
||||
try {
|
||||
if ( value instanceof Collection ) {
|
||||
query.setParameterList( name, (Collection) value );
|
||||
|
@ -363,7 +480,7 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
else {
|
||||
query.setParameter( name, value );
|
||||
}
|
||||
registerParameterBinding( getParameter( name ), value );
|
||||
registerParameterBinding( getParameter( name ), value, null );
|
||||
return this;
|
||||
}
|
||||
catch (QueryParameterException e) {
|
||||
|
@ -374,10 +491,9 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public TypedQuery<X> setParameter(String name, Date value, TemporalType temporalType) {
|
||||
getEntityManager().checkOpen( true );
|
||||
try {
|
||||
if ( temporalType == DATE ) {
|
||||
query.setDate( name, value );
|
||||
|
@ -388,7 +504,7 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
else if ( temporalType == TIMESTAMP ) {
|
||||
query.setTimestamp( name, value );
|
||||
}
|
||||
registerParameterBinding( getParameter( name ), value );
|
||||
registerParameterBinding( getParameter( name ), value, temporalType );
|
||||
return this;
|
||||
}
|
||||
catch (QueryParameterException e) {
|
||||
|
@ -399,10 +515,9 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public TypedQuery<X> setParameter(String name, Calendar value, TemporalType temporalType) {
|
||||
getEntityManager().checkOpen( true );
|
||||
try {
|
||||
if ( temporalType == DATE ) {
|
||||
query.setCalendarDate( name, value );
|
||||
|
@ -413,7 +528,7 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
else if ( temporalType == TIMESTAMP ) {
|
||||
query.setCalendar( name, value );
|
||||
}
|
||||
registerParameterBinding( getParameter(name), value );
|
||||
registerParameterBinding( getParameter(name), value, temporalType );
|
||||
return this;
|
||||
}
|
||||
catch (QueryParameterException e) {
|
||||
|
@ -424,17 +539,16 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public TypedQuery<X> setParameter(int position, Object value) {
|
||||
getEntityManager().checkOpen( true );
|
||||
try {
|
||||
if ( isJpaPositionalParameter( position ) ) {
|
||||
this.setParameter( Integer.toString( position ), value );
|
||||
}
|
||||
else {
|
||||
query.setParameter( position - 1, value );
|
||||
registerParameterBinding( getParameter( position ), value );
|
||||
registerParameterBinding( getParameter( position ), value, null );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -450,10 +564,9 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
return jpaPositionalIndices != null && jpaPositionalIndices.contains( position );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public TypedQuery<X> setParameter(int position, Date value, TemporalType temporalType) {
|
||||
getEntityManager().checkOpen( true );
|
||||
try {
|
||||
if ( isJpaPositionalParameter( position ) ) {
|
||||
String name = Integer.toString( position );
|
||||
|
@ -469,7 +582,7 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
else if ( temporalType == TIMESTAMP ) {
|
||||
query.setTimestamp( position - 1, value );
|
||||
}
|
||||
registerParameterBinding( getParameter( position ), value );
|
||||
registerParameterBinding( getParameter( position ), value, temporalType );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -481,10 +594,9 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public TypedQuery<X> setParameter(int position, Calendar value, TemporalType temporalType) {
|
||||
getEntityManager().checkOpen( true );
|
||||
try {
|
||||
if ( isJpaPositionalParameter( position ) ) {
|
||||
String name = Integer.toString( position );
|
||||
|
@ -500,7 +612,7 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
else if ( temporalType == TIMESTAMP ) {
|
||||
query.setCalendar( position - 1, value );
|
||||
}
|
||||
registerParameterBinding( getParameter( position ), value );
|
||||
registerParameterBinding( getParameter( position ), value, temporalType );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -512,17 +624,15 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Set<Parameter<?>> getParameters() {
|
||||
getEntityManager().checkOpen( false );
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Parameter<?> getParameter(String name) {
|
||||
getEntityManager().checkOpen( false );
|
||||
if ( name == null ) {
|
||||
throw new IllegalArgumentException( "Name of parameter to locate cannot be null" );
|
||||
}
|
||||
|
@ -534,10 +644,9 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
throw new IllegalArgumentException( "Unable to locate parameter named [" + name + "]" );
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public Parameter<?> getParameter(int position) {
|
||||
getEntityManager().checkOpen( false );
|
||||
if ( isJpaPositionalParameter( position ) ) {
|
||||
return getParameter( Integer.toString( position ) );
|
||||
}
|
||||
|
@ -551,43 +660,49 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public <T> Parameter<T> getParameter(String name, Class<T> type) {
|
||||
getEntityManager().checkOpen( false );
|
||||
Parameter param = getParameter( name );
|
||||
if ( param.getParameterType() != null ) {
|
||||
// we were able to determine the expected type during analysis, so validate it here
|
||||
throw new IllegalArgumentException(
|
||||
"Parameter type [" + param.getParameterType().getName() +
|
||||
"] is not assignment compatible with requested type [" +
|
||||
type.getName() + "]"
|
||||
);
|
||||
if ( ! param.getParameterType().isAssignableFrom( type ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Parameter type [%s] is not assignment compatible with requested type [%s] for parameter named [%s]",
|
||||
param.getParameterType().getName(),
|
||||
type.getName(),
|
||||
name
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public <T> Parameter<T> getParameter(int position, Class<T> type) {
|
||||
getEntityManager().checkOpen( false );
|
||||
Parameter param = getParameter( position );
|
||||
if ( param.getParameterType() != null ) {
|
||||
// we were able to determine the expected type during analysis, so validate it here
|
||||
throw new IllegalArgumentException(
|
||||
"Parameter type [" + param.getParameterType().getName() +
|
||||
"] is not assignment compatible with requested type [" +
|
||||
type.getName() + "]"
|
||||
);
|
||||
if ( ! param.getParameterType().isAssignableFrom( type ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Parameter type [%s] is not assignment compatible with requested type [%s] for parameter position [%s]",
|
||||
param.getParameterType().getName(),
|
||||
type.getName(),
|
||||
position
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
return param;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public <T> T unwrap(Class<T> tClass) {
|
||||
if ( org.hibernate.Query.class.isAssignableFrom( tClass ) ) {
|
||||
|
@ -613,6 +728,7 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public TypedQuery<X> setLockMode(javax.persistence.LockModeType lockModeType) {
|
||||
getEntityManager().checkOpen( true );
|
||||
if (! getEntityManager().isTransactionInProgress()) {
|
||||
throw new TransactionRequiredException( "no transaction is in progress" );
|
||||
}
|
||||
|
@ -634,6 +750,7 @@ public class QueryImpl<X> extends AbstractQueryImpl<X> implements TypedQuery<X>,
|
|||
|
||||
@Override
|
||||
public javax.persistence.LockModeType getLockMode() {
|
||||
getEntityManager().checkOpen( false );
|
||||
return jpaLockMode;
|
||||
}
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public StoredProcedureQuery registerStoredProcedureParameter(int position, Class type, ParameterMode mode) {
|
||||
entityManager().checkOpen( true );
|
||||
procedureCall.registerParameter( position, type, mode );
|
||||
return this;
|
||||
}
|
||||
|
@ -103,6 +104,7 @@ public class StoredProcedureQueryImpl extends BaseQueryImpl implements StoredPro
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public StoredProcedureQuery registerStoredProcedureParameter(String parameterName, Class type, ParameterMode mode) {
|
||||
entityManager().checkOpen( true );
|
||||
procedureCall.registerParameter( parameterName, type, mode );
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import javax.persistence.CacheRetrieveMode;
|
|||
import javax.persistence.CacheStoreMode;
|
||||
import javax.persistence.FlushModeType;
|
||||
import javax.persistence.Parameter;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.TransactionRequiredException;
|
||||
import javax.persistence.TypedQuery;
|
||||
import java.util.Collection;
|
||||
|
@ -93,6 +94,7 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
|||
@Override
|
||||
@SuppressWarnings({ "ThrowableInstanceNeverThrown" })
|
||||
public int executeUpdate() {
|
||||
entityManager.checkOpen( true );
|
||||
try {
|
||||
if ( ! entityManager.isTransactionInProgress() ) {
|
||||
entityManager.throwPersistenceException( new TransactionRequiredException( "Executing an update/delete query" ) );
|
||||
|
@ -123,6 +125,7 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
|||
|
||||
@Override
|
||||
public TypedQuery<X> setMaxResults(int maxResult) {
|
||||
entityManager.checkOpen( true );
|
||||
if ( maxResult < 0 ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Negative value (" + maxResult + ") passed to setMaxResults"
|
||||
|
@ -139,6 +142,7 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
|||
|
||||
@Override
|
||||
public int getMaxResults() {
|
||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
||||
return maxResults == -1
|
||||
? Integer.MAX_VALUE // stupid spec... MAX_VALUE??
|
||||
: maxResults;
|
||||
|
@ -155,6 +159,7 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
|||
|
||||
@Override
|
||||
public TypedQuery<X> setFirstResult(int firstResult) {
|
||||
entityManager.checkOpen( true );
|
||||
if ( firstResult < 0 ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Negative value (" + firstResult + ") passed to setFirstResult"
|
||||
|
@ -167,6 +172,7 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
|||
|
||||
@Override
|
||||
public int getFirstResult() {
|
||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
||||
return firstResult;
|
||||
}
|
||||
|
||||
|
@ -174,6 +180,7 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
|||
|
||||
@Override
|
||||
public Map<String, Object> getHints() {
|
||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
||||
return hints;
|
||||
}
|
||||
|
||||
|
@ -202,6 +209,7 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
|||
@Override
|
||||
@SuppressWarnings( {"deprecation"})
|
||||
public TypedQuery<X> setHint(String hintName, Object value) {
|
||||
entityManager.checkOpen( true );
|
||||
boolean skipped = false;
|
||||
try {
|
||||
if ( HINT_TIMEOUT.equals( hintName ) ) {
|
||||
|
@ -316,6 +324,7 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
|||
|
||||
@Override
|
||||
public TypedQuery<X> setFlushMode(FlushModeType jpaFlushMode) {
|
||||
entityManager.checkOpen( true );
|
||||
this.jpaFlushMode = jpaFlushMode;
|
||||
// TODO : treat as hint?
|
||||
if ( jpaFlushMode == FlushModeType.AUTO ) {
|
||||
|
@ -334,20 +343,26 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
|||
|
||||
@Override
|
||||
public FlushModeType getFlushMode() {
|
||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
||||
return jpaFlushMode != null
|
||||
? jpaFlushMode
|
||||
: entityManager.getFlushMode();
|
||||
}
|
||||
|
||||
|
||||
private Map parameterBindings;
|
||||
|
||||
protected static interface ParameterImplementor<T> extends Parameter<T> {
|
||||
public void validateBinding(Object bind, TemporalType temporalType);
|
||||
}
|
||||
|
||||
@SuppressWarnings( {"unchecked"})
|
||||
protected void registerParameterBinding(Parameter parameter, Object value) {
|
||||
protected void registerParameterBinding(Parameter parameter, Object value, TemporalType temporalType) {
|
||||
if ( parameter == null ) {
|
||||
throw new IllegalArgumentException( "parameter cannot be null" );
|
||||
}
|
||||
|
||||
validateParameterBinding( parameter, value );
|
||||
( (ParameterImplementor) parameter ).validateBinding( value, temporalType );
|
||||
|
||||
if ( parameterBindings == null ) {
|
||||
parameterBindings = new HashMap();
|
||||
|
@ -355,52 +370,7 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
|||
parameterBindings.put( parameter, value );
|
||||
}
|
||||
|
||||
private void validateParameterBinding(Parameter parameter, Object value) {
|
||||
if ( value == null || parameter.getParameterType() == null ) {
|
||||
// nothing we can check
|
||||
return;
|
||||
}
|
||||
|
||||
if ( Collection.class.isInstance( value )
|
||||
&& ! Collection.class.isAssignableFrom( parameter.getParameterType() ) ) {
|
||||
// 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
|
||||
// NOTE2 : the case of a collection value and an expected collection (if that can even happen)
|
||||
// will fall through to the main check.
|
||||
validateCollectionValuedParameterMultiBinding( parameter, (Collection) value );
|
||||
}
|
||||
else if ( value.getClass().isArray() ) {
|
||||
validateArrayValuedParameterBinding( parameter, value );
|
||||
}
|
||||
else {
|
||||
if ( ! parameter.getParameterType().isInstance( value ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"Parameter value [%s] did not match expected type [%s]",
|
||||
value,
|
||||
parameter.getParameterType().getName()
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateCollectionValuedParameterMultiBinding(Parameter parameter, Collection value) {
|
||||
// validate the elements...
|
||||
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 validateArrayValuedParameterBinding(ParameterImplementor parameter, Object value) {
|
||||
if ( ! parameter.getParameterType().isArray() ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
|
@ -443,12 +413,14 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
|||
|
||||
@Override
|
||||
public boolean isBound(Parameter<?> param) {
|
||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
||||
return parameterBindings != null && parameterBindings.containsKey( param );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public <T> T getParameterValue(Parameter<T> param) {
|
||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
||||
if ( parameterBindings == null ) {
|
||||
throw new IllegalStateException( "No parameters have been bound" );
|
||||
}
|
||||
|
@ -466,11 +438,13 @@ public abstract class AbstractQueryImpl<X> implements TypedQuery<X> {
|
|||
|
||||
@Override
|
||||
public Object getParameterValue(String name) {
|
||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
||||
return getParameterValue( getParameter( name ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getParameterValue(int position) {
|
||||
entityManager.checkOpen( false ); // technically this should rollback the txn
|
||||
return getParameterValue( getParameter( position ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,6 +98,8 @@ public abstract class BaseQueryImpl implements Query {
|
|||
|
||||
@Override
|
||||
public BaseQueryImpl setFirstResult(int firstResult) {
|
||||
entityManager().checkOpen( true );
|
||||
|
||||
if ( firstResult < 0 ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Negative value (" + firstResult + ") passed to setFirstResult"
|
||||
|
@ -110,6 +112,7 @@ public abstract class BaseQueryImpl implements Query {
|
|||
|
||||
@Override
|
||||
public int getFirstResult() {
|
||||
entityManager().checkOpen( false ); // technically should rollback
|
||||
return firstResult;
|
||||
}
|
||||
|
||||
|
@ -122,6 +125,7 @@ public abstract class BaseQueryImpl implements Query {
|
|||
|
||||
@Override
|
||||
public BaseQueryImpl setMaxResults(int maxResult) {
|
||||
entityManager().checkOpen( true );
|
||||
if ( maxResult < 0 ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Negative value (" + maxResult + ") passed to setMaxResults"
|
||||
|
@ -138,6 +142,7 @@ public abstract class BaseQueryImpl implements Query {
|
|||
|
||||
@Override
|
||||
public int getMaxResults() {
|
||||
entityManager().checkOpen( false ); // technically should rollback
|
||||
return maxResults == -1
|
||||
? Integer.MAX_VALUE // stupid spec... MAX_VALUE??
|
||||
: maxResults;
|
||||
|
@ -153,6 +158,7 @@ public abstract class BaseQueryImpl implements Query {
|
|||
|
||||
@Override
|
||||
public Map<String, Object> getHints() {
|
||||
entityManager().checkOpen( false ); // technically should rollback
|
||||
return hints;
|
||||
}
|
||||
|
||||
|
@ -256,6 +262,7 @@ public abstract class BaseQueryImpl implements Query {
|
|||
@Override
|
||||
@SuppressWarnings( {"deprecation"})
|
||||
public BaseQueryImpl setHint(String hintName, Object value) {
|
||||
entityManager().checkOpen( true );
|
||||
boolean applied = false;
|
||||
try {
|
||||
if ( HINT_TIMEOUT.equals( hintName ) ) {
|
||||
|
@ -360,6 +367,7 @@ public abstract class BaseQueryImpl implements Query {
|
|||
|
||||
@Override
|
||||
public BaseQueryImpl setFlushMode(FlushModeType jpaFlushMode) {
|
||||
entityManager().checkOpen( true );
|
||||
this.jpaFlushMode = jpaFlushMode;
|
||||
// TODO : treat as hint?
|
||||
if ( jpaFlushMode == FlushModeType.AUTO ) {
|
||||
|
@ -378,6 +386,7 @@ public abstract class BaseQueryImpl implements Query {
|
|||
|
||||
@Override
|
||||
public FlushModeType getFlushMode() {
|
||||
entityManager().checkOpen( false );
|
||||
return jpaFlushMode != null
|
||||
? jpaFlushMode
|
||||
: entityManager.getFlushMode();
|
||||
|
@ -478,54 +487,63 @@ public abstract class BaseQueryImpl implements Query {
|
|||
|
||||
@Override
|
||||
public <T> BaseQueryImpl setParameter(Parameter<T> param, T value) {
|
||||
entityManager().checkOpen( true );
|
||||
registerParameterBinding( param, makeBindValue( value ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(Parameter<Calendar> param, Calendar value, TemporalType temporalType) {
|
||||
entityManager().checkOpen( true );
|
||||
registerParameterBinding( param, makeBindValue( value, temporalType ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(Parameter<Date> param, Date value, TemporalType temporalType) {
|
||||
entityManager().checkOpen( true );
|
||||
registerParameterBinding( param, makeBindValue( value, temporalType ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(String name, Object value) {
|
||||
entityManager().checkOpen( true );
|
||||
registerParameterBinding( getParameter( name ), makeBindValue( value ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(String name, Calendar value, TemporalType temporalType) {
|
||||
entityManager().checkOpen( true );
|
||||
registerParameterBinding( getParameter( name ), makeBindValue( value, temporalType ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(String name, Date value, TemporalType temporalType) {
|
||||
entityManager().checkOpen( true );
|
||||
registerParameterBinding( getParameter( name ), makeBindValue( value, temporalType ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(int position, Object value) {
|
||||
entityManager().checkOpen( true );
|
||||
registerParameterBinding( getParameter( position ), makeBindValue( value ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(int position, Calendar value, TemporalType temporalType) {
|
||||
entityManager().checkOpen( true );
|
||||
registerParameterBinding( getParameter( position ), makeBindValue( value, temporalType ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BaseQueryImpl setParameter(int position, Date value, TemporalType temporalType) {
|
||||
entityManager().checkOpen( true );
|
||||
registerParameterBinding( getParameter( position ), makeBindValue( value, temporalType ) );
|
||||
return this;
|
||||
}
|
||||
|
@ -533,11 +551,13 @@ public abstract class BaseQueryImpl implements Query {
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set getParameters() {
|
||||
entityManager().checkOpen( false );
|
||||
return parameterBindingMap().keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameter<?> getParameter(String name) {
|
||||
entityManager().checkOpen( false );
|
||||
if ( parameterBindingMap() != null ) {
|
||||
for ( ParameterImplementor<?> param : parameterBindingMap.keySet() ) {
|
||||
if ( name.equals( param.getName() ) ) {
|
||||
|
@ -551,11 +571,13 @@ public abstract class BaseQueryImpl implements Query {
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Parameter<T> getParameter(String name, Class<T> type) {
|
||||
entityManager().checkOpen( false );
|
||||
return (Parameter<T>) getParameter( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameter<?> getParameter(int position) {
|
||||
entityManager().checkOpen( false );
|
||||
if ( parameterBindingMap() != null ) {
|
||||
for ( ParameterImplementor<?> param : parameterBindingMap.keySet() ) {
|
||||
if ( position == param.getPosition() ) {
|
||||
|
@ -569,11 +591,13 @@ public abstract class BaseQueryImpl implements Query {
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> Parameter<T> getParameter(int position, Class<T> type) {
|
||||
entityManager().checkOpen( false );
|
||||
return (Parameter<T>) getParameter( position );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBound(Parameter<?> param) {
|
||||
entityManager().checkOpen( false );
|
||||
return parameterBindingMap() != null
|
||||
&& parameterBindingMap.get( (ParameterImplementor) param ) != null;
|
||||
}
|
||||
|
@ -581,6 +605,7 @@ public abstract class BaseQueryImpl implements Query {
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getParameterValue(Parameter<T> param) {
|
||||
entityManager().checkOpen( false );
|
||||
if ( parameterBindingMap != null ) {
|
||||
final ParameterValue boundValue = parameterBindingMap.get( (ParameterImplementor) param );
|
||||
if ( boundValue != null ) {
|
||||
|
@ -592,11 +617,13 @@ public abstract class BaseQueryImpl implements Query {
|
|||
|
||||
@Override
|
||||
public Object getParameterValue(String name) {
|
||||
entityManager().checkOpen( false );
|
||||
return getParameterValue( getParameter( name ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getParameterValue(int position) {
|
||||
entityManager().checkOpen( false );
|
||||
return getParameterValue( getParameter( position ) );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,6 +52,19 @@ public interface HibernateEntityManagerImplementor extends HibernateEntityManage
|
|||
*/
|
||||
public HibernateEntityManagerFactory getFactory();
|
||||
|
||||
/**
|
||||
* Used to ensure the EntityManager is open, throwing IllegalStateException if it is closed.
|
||||
*
|
||||
* Depending on the value of {@code markForRollbackIfClosed}, may also rollback any enlisted-in transaction. This
|
||||
* distinction is made across various sections of the spec. Most failed checks should rollback. Section
|
||||
* 3.10.7 (per 2.1 spec) lists cases related to calls on related query objects that should not rollback.
|
||||
*
|
||||
* @param markForRollbackIfClosed If the EM is closed, should the transaction (if one) be marked for rollback?
|
||||
*
|
||||
* @throws IllegalStateException Thrown if the EM is closed
|
||||
*/
|
||||
public void checkOpen(boolean markForRollbackIfClosed) throws IllegalStateException;
|
||||
|
||||
/**
|
||||
* Provides access to whether a transaction is currently in progress.
|
||||
*
|
||||
|
|
|
@ -23,11 +23,14 @@
|
|||
*/
|
||||
package org.hibernate.jpa.test.query;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.List;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.Parameter;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.TemporalType;
|
||||
import javax.persistence.Tuple;
|
||||
|
@ -355,6 +358,24 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
em.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTemporalTypeBinding() {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
em.getTransaction().begin();
|
||||
|
||||
Query query = em.createQuery( "select w from " + Wallet.class.getName() + " w where w.marketEntrance = :me" );
|
||||
Parameter parameter = query.getParameter( "me", Date.class );
|
||||
assertEquals( parameter.getParameterType(), Date.class );
|
||||
|
||||
query.setParameter( "me", new Date() );
|
||||
query.setParameter( "me", new Date(), TemporalType.DATE );
|
||||
query.setParameter( "me", new GregorianCalendar(), TemporalType.DATE );
|
||||
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPositionalParameterForms() throws Exception {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
|
|
Loading…
Reference in New Issue