HHH-12129 - Fix expected exceptions on various Query methods

This commit is contained in:
Steve Ebersole 2017-11-28 09:27:00 -06:00
parent a4d9841915
commit 58781056a9
15 changed files with 316 additions and 125 deletions

View File

@ -18,6 +18,9 @@ public final class RowSelection {
private Integer fetchSize;
public void setFirstRow(Integer firstRow) {
if ( firstRow != null && firstRow < 0 ) {
throw new IllegalArgumentException( "first-row value cannot be negative : " + firstRow );
}
this.firstRow = firstRow;
}

View File

@ -60,4 +60,6 @@ public interface ParameterMetadata {
Collection<QueryParameter> getNamedParameters();
int getParameterCount();
boolean containsReference(QueryParameter parameter);
}

View File

@ -44,6 +44,7 @@ import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.NonUniqueResultException;
import org.hibernate.PropertyNotFoundException;
import org.hibernate.QueryException;
import org.hibernate.QueryParameterException;
import org.hibernate.ScrollMode;
import org.hibernate.TypeMismatchException;
@ -79,6 +80,8 @@ import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;
import static org.hibernate.LockOptions.WAIT_FOREVER;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT;
@ -102,7 +105,8 @@ import static org.hibernate.jpa.QueryHints.SPEC_HINT_TIMEOUT;
* @author Steve Ebersole
*/
public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
private static final EntityManagerMessageLogger log = HEMLogging.messageLogger( AbstractProducedQuery.class );
private static final EntityManagerMessageLogger MSG_LOGGER = HEMLogging.messageLogger( AbstractProducedQuery.class );
private static final Logger LOGGER = Logger.getLogger( AbstractProducedQuery.class );
private final SharedSessionContractImplementor producer;
private final ParameterMetadata parameterMetadata;
@ -397,6 +401,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
@Override
@SuppressWarnings("unchecked")
public <P> QueryImplementor setParameter(QueryParameter<P> parameter, P value) {
queryParameterBindings.getBinding( (QueryParameter) parameter );
locateBinding( parameter ).setBindValue( value );
return this;
}
@ -758,21 +763,57 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
}
@Override
@SuppressWarnings("unchecked")
public <T> T getParameterValue(Parameter<T> parameter) {
getProducer().checkOpen( false );
return (T) queryParameterBindings.getBinding( (QueryParameter) parameter ).getBindValue();
if ( !parameterMetadata.containsReference( (QueryParameter) parameter ) ) {
throw new IllegalArgumentException( "Parameter reference [" + parameter + "] did not come from this query" );
}
final QueryParameterBinding<T> binding = queryParameterBindings.getBinding( (QueryParameter<T>) parameter );
LOGGER.debugf( "Checking whether parameter reference [%s] is bound : %s", parameter, binding.isBound() );
if ( !binding.isBound() ) {
throw new IllegalStateException( "Parameter value not yet bound : " + parameter.toString() );
}
return binding.getBindValue();
}
@Override
public Object getParameterValue(String name) {
getProducer().checkOpen( false );
return queryParameterBindings.getBinding( name ).getBindValue();
final QueryParameterBinding binding;
try {
binding = queryParameterBindings.getBinding( name );
}
catch (QueryParameterException e) {
throw new IllegalArgumentException( "Could not resolve parameter by name - " + name, e );
}
LOGGER.debugf( "Checking whether named parameter [%s] is bound : %s", name, binding.isBound() );
if ( !binding.isBound() ) {
throw new IllegalStateException( "Parameter value not yet bound : " + name );
}
return binding.getBindValue();
}
@Override
public Object getParameterValue(int position) {
return queryParameterBindings.getBinding( position ).getBindValue();
getProducer().checkOpen( false );
final QueryParameterBinding binding;
try {
binding = queryParameterBindings.getBinding( position );
}
catch (QueryParameterException e) {
throw new IllegalArgumentException( "Could not resolve parameter by position - " + position, e );
}
LOGGER.debugf( "Checking whether positional parameter [%s] is bound : %s", (Integer) position, (Boolean) binding.isBound() );
if ( !binding.isBound() ) {
throw new IllegalStateException( "Parameter value not yet bound : " + position );
}
return binding.getBindValue();
}
@Override
@ -869,8 +910,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
@SuppressWarnings("unchecked")
public QueryImplementor setMaxResults(int maxResult) {
if ( maxResult < 0 ) {
// treat zero and negatives specially as meaning no limit...
queryOptions.setMaxRows( null );
throw new IllegalArgumentException( "max-results cannot be negative" );
}
else {
queryOptions.setMaxRows( maxResult );
@ -890,6 +930,9 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
@SuppressWarnings("unchecked")
public QueryImplementor setFirstResult(int startPosition) {
getProducer().checkOpen();
if ( startPosition < 0 ) {
throw new IllegalArgumentException( "first-result value cannot be negative : " + startPosition );
}
queryOptions.setFirstRow( startPosition );
return this;
}
@ -1036,7 +1079,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
applyAliasSpecificLockModeHint( alias, lockMode );
}
catch ( Exception e ) {
log.unableToDetermineLockModeValue( hintName, value );
MSG_LOGGER.unableToDetermineLockModeValue( hintName, value );
applied = false;
}
}
@ -1049,7 +1092,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
applyEntityGraphQueryHint( new EntityGraphQueryHint( hintName, (EntityGraphImpl) value ) );
}
else {
log.warnf( "The %s hint was set, but the value was not an EntityGraph!", hintName );
MSG_LOGGER.warnf( "The %s hint was set, but the value was not an EntityGraph!", hintName );
}
applied = true;
}
@ -1060,7 +1103,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
applied = applyPassDistinctThrough( ConfigurationHelper.getBoolean( value ) );
}
else {
log.ignoringUnrecognizedQueryHint( hintName );
MSG_LOGGER.ignoringUnrecognizedQueryHint( hintName );
}
}
catch ( ClassCastException e ) {
@ -1068,7 +1111,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
}
if ( !applied ) {
log.debugf( "Skipping unsupported query hint [%s]", hintName );
MSG_LOGGER.debugf( "Skipping unsupported query hint [%s]", hintName );
}
return this;

View File

@ -90,6 +90,13 @@ public class ParameterMetadataImpl implements ParameterMetadata {
return ordinalDescriptorMap.size() + namedDescriptorMap.size();
}
@Override
@SuppressWarnings("SuspiciousMethodCalls")
public boolean containsReference(QueryParameter parameter) {
return ordinalDescriptorMap.containsValue( parameter )
|| namedDescriptorMap.containsValue( parameter );
}
@Override
public boolean hasNamedParameters() {
return !namedDescriptorMap.isEmpty();
@ -213,7 +220,7 @@ public class ParameterMetadataImpl implements ParameterMetadata {
public NamedParameterDescriptor getNamedParameterDescriptor(String name) {
final NamedParameterDescriptor descriptor = namedDescriptorMap.get( name );
if ( descriptor == null ) {
throw new QueryParameterException(
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"Could not locate named parameter [%s], expecting one of [%s]",

View File

@ -10,13 +10,10 @@ import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.stream.Collectors;
import javax.persistence.Parameter;
import org.hibernate.HibernateException;
@ -108,7 +105,18 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
@SuppressWarnings("WeakerAccess")
protected QueryParameterBinding makeBinding(QueryParameter queryParameter) {
return makeBinding( queryParameter.getType() );
assert ! parameterBindingMap.containsKey( queryParameter );
if ( ! parameterMetadata.containsReference( queryParameter ) ) {
throw new IllegalArgumentException(
"Cannot create binding for parameter reference [" + queryParameter + "] - reference is not a parameter of this query"
);
}
final QueryParameterBinding binding = makeBinding( queryParameter.getType() );
parameterBindingMap.put( queryParameter, binding );
return binding;
}
@SuppressWarnings("WeakerAccess")
@ -140,107 +148,38 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
@Override
@SuppressWarnings( "unchecked" )
public boolean isBound(QueryParameter parameter) {
final QueryParameterBinding binding = locateBinding( parameter );
if ( binding != null ) {
return binding.getBindValue() != null;
}
final QueryParameterBinding binding = getBinding( parameter );
final QueryParameterListBinding listBinding = locateQueryParameterListBinding( parameter );
if ( listBinding != null ) {
return listBinding.getBindValues() != null;
}
return false;
return binding.isBound();
}
@SuppressWarnings("unchecked")
public <T> QueryParameterBinding<T> getBinding(QueryParameter<T> parameter) {
final QueryParameterBinding<T> binding = locateBinding( parameter );
QueryParameterBinding<T> binding = parameterBindingMap.get( parameter );
if ( binding == null ) {
if ( ! parameterMetadata.containsReference( parameter ) ) {
throw new IllegalArgumentException(
"Could not resolve QueryParameter reference [" + parameter + "] to QueryParameterBinding"
);
}
binding = makeBinding( parameter );
}
return binding;
}
@SuppressWarnings("unchecked")
public <T> QueryParameterBinding<T> locateBinding(QueryParameter<T> parameter) {
// see if this exact instance is known as a key
if ( parameterBindingMap.containsKey( parameter ) ) {
return parameterBindingMap.get( parameter );
}
// if the incoming parameter has a name, try to find it by name
if ( StringHelper.isNotEmpty( parameter.getName() ) ) {
final QueryParameterBinding binding = locateBinding( parameter.getName() );
if ( binding != null ) {
return binding;
}
}
// if the incoming parameter has a position, try to find it by position
if ( parameter.getPosition() != null ) {
final QueryParameterBinding binding = locateBinding( parameter.getPosition() );
if ( binding != null ) {
return binding;
}
}
return null;
}
protected QueryParameterBinding locateAndRemoveBinding(String name) {
final Iterator<Map.Entry<QueryParameter, QueryParameterBinding>> entryIterator = parameterBindingMap.entrySet().iterator();
while ( entryIterator.hasNext() ) {
final Map.Entry<QueryParameter, QueryParameterBinding> entry = entryIterator.next();
if ( name.equals( entry.getKey().getName() ) ) {
entryIterator.remove();
return entry.getValue();
}
}
return null;
}
@Override
@SuppressWarnings("unchecked")
public QueryParameterBinding getBinding(int position) {
return locateBinding( position );
}
@SuppressWarnings("WeakerAccess")
protected QueryParameterBinding locateBinding(int position) {
final QueryParameter<Object> param = parameterMetadata.getQueryParameter( position );
if ( param == null ) {
throw new IllegalArgumentException( "Unknown ordinal parameter : " + position );
}
return parameterBindingMap.computeIfAbsent(
param,
this::makeBinding
);
return getBinding( parameterMetadata.getQueryParameter( position ) );
}
@Override
@SuppressWarnings("unchecked")
public QueryParameterBinding getBinding(String name) {
return locateBinding( name );
}
@SuppressWarnings("WeakerAccess")
protected QueryParameterBinding locateBinding(String name) {
final QueryParameter<Object> param = parameterMetadata.getQueryParameter( name );
if ( param == null ) {
throw new IllegalArgumentException( "Unknown named parameter : " + name );
}
return parameterBindingMap.computeIfAbsent(
param,
this::makeBinding
);
return getBinding( parameterMetadata.getQueryParameter( name ) );
}
public void verifyParametersBound(boolean reserveFirstParameter) {

View File

@ -170,4 +170,10 @@ public class ProcedureParameterMetadata implements ParameterMetadata {
public int getParameterCount() {
return parameters.size();
}
@Override
@SuppressWarnings("SuspiciousMethodCalls")
public boolean containsReference(QueryParameter parameter) {
return parameters.contains( parameter );
}
}

View File

@ -41,10 +41,10 @@ public class SharedRegionTest extends BaseNonConfigCoreFunctionalTestCase {
}
@Override
protected void applyMetadataSources(MetadataSources metadataSources) {
super.applyMetadataSources( metadataSources );
metadataSources.addAnnotatedClass( StateCodes.class );
metadataSources.addAnnotatedClass( ZipCodes.class );
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( StateCodes.class );
sources.addAnnotatedClass( ZipCodes.class );
}
@Test

View File

@ -60,10 +60,10 @@ public class ExplicitJavaTypeDescriptorTest extends BaseNonConfigCoreFunctionalT
}
@Override
protected void applyMetadataSources(MetadataSources metadataSources) {
super.applyMetadataSources( metadataSources );
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
metadataSources.addAnnotatedClass( TheEntity.class );
sources.addAnnotatedClass( TheEntity.class );
}
@Test

View File

@ -33,10 +33,10 @@ import org.junit.Test;
public class CriteriaAliasFetchTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void applyMetadataSources(MetadataSources metadataSources) {
super.applyMetadataSources( metadataSources );
metadataSources.addAnnotatedClass( Cat.class );
metadataSources.addAnnotatedClass( Kitten.class );
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( Cat.class );
sources.addAnnotatedClass( Kitten.class );
}
@Override

View File

@ -0,0 +1,191 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.test.jpa.compliance;
import java.util.Date;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Parameter;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.hibernate.boot.MetadataSources;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase;
import org.junit.Test;
import static org.junit.Assert.fail;
/**
* @author Steve Ebersole
*/
public class QueryApiTest extends BaseNonConfigCoreFunctionalTestCase {
@Entity( name = "Person" )
@Table( name = "person" )
public static class Person {
@Id
public Integer id;
String name;
@Temporal( TemporalType.DATE )
Date dob;
}
@Override
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( Person.class );
}
@Test
public void testGetParameterNotBound() {
inTransaction(
session -> {
try {
// Query
session.createQuery( "select p from Person p where name = ?1" )
.getParameterValue( 1 );
fail( "expecting failure" );
}
catch (IllegalStateException expected) {
// expected condition
}
// TypedQuery
try {
session.createQuery( "select p from Person p where name = ?1", Person.class )
.getParameterValue( 1 );
fail( "expecting failure" );
}
catch (IllegalStateException expected) {
// expected condition
}
}
);
}
@Test
public void testGetParameterFromAnotherQuery() {
inTransaction(
session -> {
try {
// Query
final QueryImplementor query1 = session.createQuery( "select p from Person p where name = :name1" );
final QueryImplementor query2 = session.createQuery( "select p from Person p where name = :name2" );
final Parameter<?> name1 = query1.getParameter( "name1" );
query2.getParameterValue( name1 );
fail( "expecting failure" );
}
catch (IllegalArgumentException expected) {
// expected condition
}
// TypedQuery
try {
session.createQuery( "select p from Person p where name = ?1", Person.class )
.getParameterValue( 1 );
fail( "expecting failure" );
}
catch (IllegalStateException expected) {
// expected condition
}
}
);
}
@Test
public void testGetParameterValueByUnknownName() {
inTransaction(
session -> {
try {
// Query
final QueryImplementor query1 = session.createQuery( "select p from Person p where name = :name1" );
query1.getParameterValue( "name2" );
fail( "expecting failure" );
}
catch (IllegalArgumentException expected) {
// expected condition
}
}
);
}
@Test
public void testGetParameterValueByUnknownPosition() {
inTransaction(
session -> {
try {
// Query
final QueryImplementor query1 = session.createQuery( "select p from Person p" );
query1.getParameterValue( 2 );
fail( "expecting failure" );
}
catch (IllegalArgumentException expected) {
// expected condition
}
}
);
}
@Test
public void testSetParameterValueByUnknownReference() {
inTransaction(
session -> {
try {
// Query
final QueryImplementor query1 = session.createQuery( "select p from Person p where p.dob < :date1" );
final QueryImplementor query2 = session.createQuery( "select p from Person p where p.dob < :date2" );
final Parameter<?> date2 = query2.getParameter( "date2" );
query1.setParameter( date2, new Date() );
fail( "expecting failure" );
}
catch (IllegalArgumentException expected) {
// expected condition
}
}
);
}
@Test
public void testSetInvalidFirstResult() {
inTransaction(
session -> {
try {
// Query
session.createQuery( "select p from Person p" ).setFirstResult( -3 );
fail( "expecting failure" );
}
catch (IllegalArgumentException expected) {
// expected condition
}
}
);
}
@Test
public void testSetInvalidMaxResults() {
inTransaction(
session -> {
try {
// Query
session.createQuery( "select p from Person p where name = ?" ).setMaxResults( -3 );
fail( "expecting failure" );
}
catch (IllegalArgumentException expected) {
// expected condition
}
}
);
}
}

View File

@ -39,9 +39,9 @@ public class MappedSuperclassOverrideTest extends BaseNonConfigCoreFunctionalTes
}
@Override
protected void applyMetadataSources(MetadataSources metadataSources) {
super.applyMetadataSources( metadataSources );
metadataSources.addAnnotatedClass( MyMappedSuperclass.class )
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( MyMappedSuperclass.class )
.addAnnotatedClass( MyEntity.class );
}

View File

@ -32,9 +32,9 @@ import static org.junit.Assert.fail;
*/
public class BasicGetLoadAccessTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void applyMetadataSources(MetadataSources metadataSources) {
super.applyMetadataSources( metadataSources );
metadataSources.addAnnotatedClass( User.class );
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( User.class );
}
@Entity( name = "User" )

View File

@ -26,9 +26,9 @@ import org.junit.Test;
*/
public class ProxiedGetLoadAccessTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void applyMetadataSources(MetadataSources metadataSources) {
super.applyMetadataSources( metadataSources );
metadataSources.addAnnotatedClass( UserImpl.class );
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( UserImpl.class );
}
public static interface User {

View File

@ -34,9 +34,9 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate;
public class BasicStreamTest extends BaseNonConfigCoreFunctionalTestCase {
@Override
protected void applyMetadataSources(MetadataSources metadataSources) {
super.applyMetadataSources( metadataSources );
metadataSources.addAnnotatedClass( MyEntity.class );
protected void applyMetadataSources(MetadataSources sources) {
super.applyMetadataSources( sources );
sources.addAnnotatedClass( MyEntity.class );
}
@Test

View File

@ -254,21 +254,21 @@ public class BaseNonConfigCoreFunctionalTestCase extends BaseUnitTestCase {
protected void afterStandardServiceRegistryBuilt(StandardServiceRegistry ssr) {
}
protected void applyMetadataSources(MetadataSources metadataSources) {
protected void applyMetadataSources(MetadataSources sources) {
for ( String mapping : getMappings() ) {
metadataSources.addResource( getBaseForMappings() + mapping );
sources.addResource( getBaseForMappings() + mapping );
}
for ( Class annotatedClass : getAnnotatedClasses() ) {
metadataSources.addAnnotatedClass( annotatedClass );
sources.addAnnotatedClass( annotatedClass );
}
for ( String annotatedPackage : getAnnotatedPackages() ) {
metadataSources.addPackage( annotatedPackage );
sources.addPackage( annotatedPackage );
}
for ( String ormXmlFile : getXmlFiles() ) {
metadataSources.addInputStream( Thread.currentThread().getContextClassLoader().getResourceAsStream( ormXmlFile ) );
sources.addInputStream( Thread.currentThread().getContextClassLoader().getResourceAsStream( ormXmlFile ) );
}
}