DATAJPA-1575 - Consistent use of JpaParametersParameterAccessor.

We now reuse JpaParametersParameterAccessor as much as possible to avoid constant recreation. This change required several signature changes to accept JpaParametersParameterAccessor instead of raw Object[] values.
This commit is contained in:
Mark Paluch
2019-07-19 12:11:01 +02:00
parent ae594415de
commit 10d7339799
18 changed files with 264 additions and 239 deletions

View File

@@ -69,7 +69,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
private final JpaMetamodel metamodel;
private final PersistenceProvider provider;
Lazy<ParameterBinder> parameterBinder = new Lazy<>(this::createBinder);
final Lazy<ParameterBinder> parameterBinder = new Lazy<>(this::createBinder);
/**
* Creates a new {@link AbstractJpaQuery} from the given {@link JpaQueryMethod}.
@@ -133,11 +133,10 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
@Nullable
private Object doExecute(JpaQueryExecution execution, Object[] values) {
Object result = execution.execute(this, values);
JpaParametersParameterAccessor accessor = new JpaParametersParameterAccessor(method.getParameters(), values);
Object result = execution.execute(this, accessor);
ParametersParameterAccessor accessor = new ParametersParameterAccessor(method.getParameters(), values);
ResultProcessor withDynamicProjection = method.getResultProcessor().withDynamicProjection(accessor);
return withDynamicProjection.processResult(result, new TupleConverter(withDynamicProjection.getReturnedType()));
}
@@ -150,9 +149,9 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
} else if (method.isCollectionQuery()) {
return new CollectionExecution();
} else if (method.isSliceQuery()) {
return new SlicedExecution(method.getParameters());
return new SlicedExecution();
} else if (method.isPageQuery()) {
return new PagedExecution(method.getParameters());
return new PagedExecution();
} else if (method.isModifyingQuery()) {
return new ModifyingExecution(method, em);
} else {
@@ -206,8 +205,8 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
return ParameterBinderFactory.createBinder(getQueryMethod().getParameters());
}
protected Query createQuery(Object[] values) {
return applyLockMode(applyEntityGraphConfiguration(applyHints(doCreateQuery(values), method), method), method);
protected Query createQuery(JpaParametersParameterAccessor parameters) {
return applyLockMode(applyEntityGraphConfiguration(applyHints(doCreateQuery(parameters), method), method), method);
}
/**
@@ -233,14 +232,14 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
return query;
}
protected Query createCountQuery(Object[] values) {
protected Query createCountQuery(JpaParametersParameterAccessor values) {
Query countQuery = doCreateCountQuery(values);
return method.applyHintsToCountQuery() ? applyHints(countQuery, method) : countQuery;
}
/**
* Returns the type to be used when creating the JPA query.
*
*
* @return
* @since 2.0.5
*/
@@ -258,18 +257,18 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
/**
* Creates a {@link Query} instance for the given values.
*
* @param values must not be {@literal null}.
* @param accessor must not be {@literal null}.
* @return
*/
protected abstract Query doCreateQuery(Object[] values);
protected abstract Query doCreateQuery(JpaParametersParameterAccessor accessor);
/**
* Creates a {@link TypedQuery} for counting using the given values.
*
* @param values must not be {@literal null}.
* @param accessor must not be {@literal null}.
* @return
*/
protected abstract Query doCreateCountQuery(Object[] values);
protected abstract Query doCreateCountQuery(JpaParametersParameterAccessor accessor);
static class TupleConverter implements Converter<Object, Object> {

View File

@@ -20,8 +20,6 @@ import static org.springframework.data.jpa.repository.query.QueryParameterSetter
import javax.persistence.EntityManager;
import javax.persistence.Query;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.QueryMethodEvaluationContextProvider;
import org.springframework.data.repository.query.ResultProcessor;
import org.springframework.data.repository.query.ReturnedType;
@@ -36,6 +34,7 @@ import org.springframework.util.Assert;
* @author Jens Schauder
* @author Tom Hombergs
* @author David Madden
* @author Mark Paluch
*/
abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
@@ -77,12 +76,11 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateQuery(java.lang.Object[])
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateQuery(JpaParametersParameterAccessor)
*/
@Override
public Query doCreateQuery(Object[] values) {
public Query doCreateQuery(JpaParametersParameterAccessor accessor) {
ParameterAccessor accessor = new ParametersParameterAccessor(getQueryMethod().getParameters(), values);
String sortedQueryString = QueryUtils.applySorting(query.getQueryString(), accessor.getSort(), query.getAlias());
ResultProcessor processor = getQueryMethod().getResultProcessor().withDynamicProjection(accessor);
@@ -90,12 +88,12 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
// it is ok to reuse the binding contained in the ParameterBinder although we create a new query String because the
// parameters in the query do not change.
return parameterBinder.get().bindAndPrepare(query, values);
return parameterBinder.get().bindAndPrepare(query, accessor);
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#createBinder(java.lang.Object[])
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#createBinder(JpaParametersParameterAccessor)
*/
@Override
protected ParameterBinder createBinder() {
@@ -106,10 +104,10 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateCountQuery(java.lang.Object[])
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateCountQuery(JpaParametersParameterAccessor)
*/
@Override
protected Query doCreateCountQuery(Object[] values) {
protected Query doCreateCountQuery(JpaParametersParameterAccessor accessor) {
String queryString = countQuery.getQueryString();
EntityManager em = getEntityManager();
@@ -118,7 +116,7 @@ abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery {
? em.createNativeQuery(queryString) //
: em.createQuery(queryString, Long.class);
return parameterBinder.get().bind(query, values, LENIENT);
return parameterBinder.get().bind(query, accessor, LENIENT);
}
/**

View File

@@ -25,6 +25,7 @@ import org.springframework.data.repository.query.ParametersParameterAccessor;
* offers access to all the values, not just the bindable ones based on a {@link JpaParameter} instance.
*
* @author Jens Schauder
* @author Mark Paluch
*/
public class JpaParametersParameterAccessor extends ParametersParameterAccessor {
@@ -41,4 +42,9 @@ public class JpaParametersParameterAccessor extends ParametersParameterAccessor
public <T> T getValue(Parameter parameter) {
return super.getValue(parameter.getIndex());
}
@Override
public Object[] getValues() {
return super.getValues();
}
}

View File

@@ -34,9 +34,6 @@ import org.springframework.data.domain.Slice;
import org.springframework.data.domain.SliceImpl;
import org.springframework.data.jpa.provider.PersistenceProvider;
import org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.data.util.CloseableIterator;
import org.springframework.data.util.StreamUtils;
@@ -80,15 +77,15 @@ public abstract class JpaQueryExecution {
* @return
*/
@Nullable
public Object execute(AbstractJpaQuery query, Object[] values) {
public Object execute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
Assert.notNull(query, "AbstractJpaQuery must not be null!");
Assert.notNull(values, "Values must not be null!");
Assert.notNull(accessor, "JpaParametersParameterAccessor must not be null!");
Object result;
try {
result = doExecute(query, values);
result = doExecute(query, accessor);
} catch (NoResultException e) {
return null;
}
@@ -117,7 +114,7 @@ public abstract class JpaQueryExecution {
* @return
*/
@Nullable
protected abstract Object doExecute(AbstractJpaQuery query, Object[] values);
protected abstract Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor);
/**
* Executes the query to return a simple collection of entities.
@@ -125,8 +122,8 @@ public abstract class JpaQueryExecution {
static class CollectionExecution extends JpaQueryExecution {
@Override
protected Object doExecute(AbstractJpaQuery query, Object[] values) {
return query.createQuery(values).getResultList();
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
return query.createQuery(accessor).getResultList();
}
}
@@ -138,29 +135,16 @@ public abstract class JpaQueryExecution {
*/
static class SlicedExecution extends JpaQueryExecution {
private final Parameters<?, ?> parameters;
/**
* Creates a new {@link SlicedExecution} using the given {@link Parameters}.
*
* @param parameters must not be {@literal null}.
*/
public SlicedExecution(Parameters<?, ?> parameters) {
this.parameters = parameters;
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.JpaQueryExecution#doExecute(org.springframework.data.jpa.repository.query.AbstractJpaQuery, java.lang.Object[])
*/
@Override
@SuppressWarnings("unchecked")
protected Object doExecute(AbstractJpaQuery query, Object[] values) {
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
ParametersParameterAccessor accessor = new ParametersParameterAccessor(parameters, values);
Pageable pageable = accessor.getPageable();
Query createQuery = query.createQuery(values);
Query createQuery = query.createQuery(accessor);
int pageSize = 0;
if (pageable.isPaged()) {
@@ -184,28 +168,20 @@ public abstract class JpaQueryExecution {
*/
static class PagedExecution extends JpaQueryExecution {
private final Parameters<?, ?> parameters;
public PagedExecution(Parameters<?, ?> parameters) {
this.parameters = parameters;
}
@Override
@SuppressWarnings("unchecked")
protected Object doExecute(final AbstractJpaQuery repositoryQuery, final Object[] values) {
protected Object doExecute(final AbstractJpaQuery repositoryQuery, JpaParametersParameterAccessor accessor) {
ParameterAccessor accessor = new ParametersParameterAccessor(parameters, values);
Query query = repositoryQuery.createQuery(values);
Query query = repositoryQuery.createQuery(accessor);
return PageableExecutionUtils.getPage(query.getResultList(), accessor.getPageable(),
() -> count(repositoryQuery, values));
() -> count(repositoryQuery, accessor));
}
private long count(AbstractJpaQuery repositoryQuery, Object[] values) {
private long count(AbstractJpaQuery repositoryQuery, JpaParametersParameterAccessor accessor) {
List<?> totals = repositoryQuery.createCountQuery(values).getResultList();
List<?> totals = repositoryQuery.createCountQuery(accessor).getResultList();
return (totals.size() == 1 ? CONVERSION_SERVICE.convert(totals.get(0), Long.class) : totals.size());
}
}
@@ -216,9 +192,9 @@ public abstract class JpaQueryExecution {
static class SingleEntityExecution extends JpaQueryExecution {
@Override
protected Object doExecute(AbstractJpaQuery query, Object[] values) {
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
return query.createQuery(values).getSingleResult();
return query.createQuery(accessor).getSingleResult();
}
}
@@ -254,13 +230,13 @@ public abstract class JpaQueryExecution {
}
@Override
protected Object doExecute(AbstractJpaQuery query, Object[] values) {
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
if (flush) {
em.flush();
}
int result = query.createQuery(values).executeUpdate();
int result = query.createQuery(accessor).executeUpdate();
if (clear) {
em.clear();
@@ -290,9 +266,9 @@ public abstract class JpaQueryExecution {
* @see org.springframework.data.jpa.repository.query.JpaQueryExecution#doExecute(org.springframework.data.jpa.repository.query.AbstractJpaQuery, java.lang.Object[])
*/
@Override
protected Object doExecute(AbstractJpaQuery jpaQuery, Object[] values) {
protected Object doExecute(AbstractJpaQuery jpaQuery, JpaParametersParameterAccessor accessor) {
Query query = jpaQuery.createQuery(values);
Query query = jpaQuery.createQuery(accessor);
List<?> resultList = query.getResultList();
for (Object o : resultList) {
@@ -312,8 +288,8 @@ public abstract class JpaQueryExecution {
static class ExistsExecution extends JpaQueryExecution {
@Override
protected Object doExecute(AbstractJpaQuery query, Object[] values) {
return !query.createQuery(values).getResultList().isEmpty();
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
return !query.createQuery(accessor).getResultList().isEmpty();
}
}
@@ -330,12 +306,12 @@ public abstract class JpaQueryExecution {
* @see org.springframework.data.jpa.repository.query.JpaQueryExecution#doExecute(org.springframework.data.jpa.repository.query.AbstractJpaQuery, java.lang.Object[])
*/
@Override
protected Object doExecute(AbstractJpaQuery jpaQuery, Object[] values) {
protected Object doExecute(AbstractJpaQuery jpaQuery, JpaParametersParameterAccessor accessor) {
Assert.isInstanceOf(StoredProcedureJpaQuery.class, jpaQuery);
StoredProcedureJpaQuery storedProcedureJpaQuery = (StoredProcedureJpaQuery) jpaQuery;
StoredProcedureQuery storedProcedure = storedProcedureJpaQuery.createQuery(values);
StoredProcedureQuery storedProcedure = storedProcedureJpaQuery.createQuery(accessor);
storedProcedure.execute();
return storedProcedureJpaQuery.extractOutputValue(storedProcedure);
@@ -356,16 +332,16 @@ public abstract class JpaQueryExecution {
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.JpaQueryExecution#doExecute(org.springframework.data.jpa.repository.query.AbstractJpaQuery, java.lang.Object[])
* @see org.springframework.data.jpa.repository.query.JpaQueryExecution#doExecute(org.springframework.data.jpa.repository.query.AbstractJpaQuery, JpaParametersParameterAccessor)
*/
@Override
protected Object doExecute(final AbstractJpaQuery query, Object[] values) {
protected Object doExecute(final AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
if (!SurroundingTransactionDetectorMethodInterceptor.INSTANCE.isSurroundingTransactionActive()) {
throw new InvalidDataAccessApiUsageException(NO_SURROUNDING_TRANSACTION);
}
Query jpaQuery = query.createQuery(values);
Query jpaQuery = query.createQuery(accessor);
// JPA 2.2 on the classpath
if (streamMethod != null) {

View File

@@ -26,9 +26,9 @@ import javax.persistence.TypedQuery;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.jpa.provider.QueryExtractor;
import org.springframework.data.repository.query.Parameters;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.QueryCreationException;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.data.repository.query.ResultProcessor;
@@ -152,30 +152,29 @@ final class NamedQuery extends AbstractJpaQuery {
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateQuery(java.lang.Object[])
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateQuery(JpaParametersParameterAccessor)
*/
@Override
protected Query doCreateQuery(Object[] values) {
protected Query doCreateQuery(JpaParametersParameterAccessor accessor) {
EntityManager em = getEntityManager();
JpaQueryMethod queryMethod = getQueryMethod();
ResultProcessor processor = queryMethod.getResultProcessor()
.withDynamicProjection(new ParametersParameterAccessor(queryMethod.getParameters(), values));
ResultProcessor processor = queryMethod.getResultProcessor().withDynamicProjection(accessor);
Query query = getTypeToRead(processor.getReturnedType()) //
.<Query> map(it -> em.createNamedQuery(queryName, it)) //
.orElseGet(() -> em.createNamedQuery(queryName));
return parameterBinder.get().bindAndPrepare(query, values);
return parameterBinder.get().bindAndPrepare(query, accessor);
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateCountQuery(java.lang.Object[])
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateCountQuery(JpaParametersParameterAccessor)
*/
@Override
protected TypedQuery<Long> doCreateCountQuery(Object[] values) {
protected TypedQuery<Long> doCreateCountQuery(JpaParametersParameterAccessor accessor) {
EntityManager em = getEntityManager();
TypedQuery<Long> countQuery;
@@ -191,10 +190,10 @@ final class NamedQuery extends AbstractJpaQuery {
countQuery = em.createQuery(countQueryString, Long.class);
}
return parameterBinder.get().bind(countQuery, values, LENIENT);
return parameterBinder.get().bind(countQuery, accessor, LENIENT);
}
/*
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#getTypeToRead()
*/

View File

@@ -18,7 +18,6 @@ package org.springframework.data.jpa.repository.query;
import javax.persistence.Query;
import org.springframework.data.jpa.repository.query.QueryParameterSetter.ErrorHandling;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.util.Assert;
/**
@@ -70,13 +69,13 @@ public class ParameterBinder {
this.useJpaForPaging = useJpaForPaging;
}
public <T extends Query> T bind(T jpaQuery, Object[] values) {
return bind(jpaQuery, values, ErrorHandling.STRICT);
public <T extends Query> T bind(T jpaQuery, JpaParametersParameterAccessor accessor) {
return bind(jpaQuery, accessor, ErrorHandling.STRICT);
}
public <T extends Query> T bind(T jpaQuery, Object[] values, ErrorHandling errorHandling) {
public <T extends Query> T bind(T jpaQuery, JpaParametersParameterAccessor accessor, ErrorHandling errorHandling) {
parameterSetters.forEach(it -> it.setParameter(jpaQuery, values, errorHandling));
parameterSetters.forEach(it -> it.setParameter(jpaQuery, accessor, errorHandling));
return jpaQuery;
}
@@ -87,13 +86,11 @@ public class ParameterBinder {
* @param query must not be {@literal null}.
* @param values values of method parameters to be assigned to the query parameters.
*/
Query bindAndPrepare(Query query, Object[] values) {
Query bindAndPrepare(Query query, JpaParametersParameterAccessor accessor) {
Assert.notNull(query, "Query must not be null!");
ParametersParameterAccessor accessor = new ParametersParameterAccessor(parameters, values);
Query result = bind(query, values);
Query result = bind(query, accessor);
if (!useJpaForPaging || !parameters.hasPageableParameter() || accessor.getPageable().isUnpaged()) {
return result;

View File

@@ -64,7 +64,7 @@ class ParameterMetadataProvider {
* Creates a new {@link ParameterMetadataProvider} from the given {@link CriteriaBuilder} and
* {@link ParametersParameterAccessor} with support for parameter value customizations via {@link PersistenceProvider}
* .
*
*
* @param builder must not be {@literal null}.
* @param accessor must not be {@literal null}.
* @param provider must not be {@literal null}.
@@ -78,7 +78,7 @@ class ParameterMetadataProvider {
/**
* Creates a new {@link ParameterMetadataProvider} from the given {@link CriteriaBuilder} and {@link Parameters} with
* support for parameter value customizations via {@link PersistenceProvider}.
*
*
* @param builder must not be {@literal null}.
* @param parameters must not be {@literal null}.
* @param provider must not be {@literal null}.
@@ -121,7 +121,7 @@ class ParameterMetadataProvider {
* @return the expressions
*/
public List<ParameterMetadata<?>> getExpressions() {
return Collections.unmodifiableList(expressions);
return expressions;
}
/**

View File

@@ -17,7 +17,6 @@ package org.springframework.data.jpa.repository.query;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import javax.persistence.EntityManager;
import javax.persistence.Query;
@@ -106,21 +105,21 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateQuery(java.lang.Object[])
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateQuery(JpaParametersParameterAccessor)
*/
@Override
public Query doCreateQuery(Object[] values) {
return query.createQuery(values);
public Query doCreateQuery(JpaParametersParameterAccessor accessor) {
return query.createQuery(accessor);
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateCountQuery(java.lang.Object[])
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateCountQuery(JpaParametersParameterAccessor)
*/
@Override
@SuppressWarnings("unchecked")
public TypedQuery<Long> doCreateCountQuery(Object[] values) {
return (TypedQuery<Long>) countQuery.createQuery(values);
public TypedQuery<Long> doCreateCountQuery(JpaParametersParameterAccessor accessor) {
return (TypedQuery<Long>) countQuery.createQuery(accessor);
}
/*
@@ -218,7 +217,7 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
this.persistenceProvider = persistenceProvider;
JpaQueryCreator creator = createCreator(persistenceProvider, Optional.empty());
JpaQueryCreator creator = createCreator(persistenceProvider, null);
if (recreateQueries) {
this.cachedCriteriaQuery = null;
@@ -234,15 +233,14 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
/**
* Creates a new {@link Query} for the given parameter values.
*/
public Query createQuery(Object[] values) {
public Query createQuery(JpaParametersParameterAccessor accessor) {
CriteriaQuery<?> criteriaQuery = cachedCriteriaQuery;
ParameterBinder parameterBinder = cachedParameterBinder;
ParametersParameterAccessor accessor = new ParametersParameterAccessor(parameters, values);
if (cachedCriteriaQuery == null || accessor.hasBindableNullValue()) {
JpaQueryCreator creator = createCreator(persistenceProvider, Optional.of(accessor));
criteriaQuery = creator.createQuery(getDynamicSort(values));
JpaQueryCreator creator = createCreator(persistenceProvider, accessor);
criteriaQuery = creator.createQuery(getDynamicSort(accessor));
List<ParameterMetadata<?>> expressions = creator.getParameterExpressions();
parameterBinder = getBinder(expressions);
}
@@ -251,7 +249,7 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
throw new IllegalStateException("ParameterBinder is null!");
}
return restrictMaxResultsIfNecessary(invokeBinding(parameterBinder, createQuery(criteriaQuery), values));
return restrictMaxResultsIfNecessary(invokeBinding(parameterBinder, createQuery(criteriaQuery), accessor));
}
/**
@@ -303,18 +301,22 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
}
protected JpaQueryCreator createCreator(PersistenceProvider persistenceProvider,
Optional<ParametersParameterAccessor> accessor) {
@Nullable JpaParametersParameterAccessor accessor) {
EntityManager entityManager = getEntityManager();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
ParameterMetadataProvider provider = accessor
.map(it -> new ParameterMetadataProvider(builder, it, persistenceProvider, escape))//
.orElseGet(() -> new ParameterMetadataProvider(builder, parameters, persistenceProvider, escape));
ResultProcessor processor = getQueryMethod().getResultProcessor();
ReturnedType returnedType = accessor.map(processor::withDynamicProjection)//
.orElse(processor).getReturnedType();
ParameterMetadataProvider provider;
ReturnedType returnedType;
if (accessor != null) {
provider = new ParameterMetadataProvider(builder, accessor, persistenceProvider, escape);
returnedType = processor.withDynamicProjection(accessor).getReturnedType();
} else {
provider = new ParameterMetadataProvider(builder, parameters, persistenceProvider, escape);
returnedType = processor.getReturnedType();
}
return new JpaQueryCreator(tree, returnedType, builder, provider);
}
@@ -322,19 +324,20 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
/**
* Invokes parameter binding on the given {@link TypedQuery}.
*/
protected Query invokeBinding(ParameterBinder binder, TypedQuery<?> query, Object[] values) {
protected Query invokeBinding(ParameterBinder binder, TypedQuery<?> query,
JpaParametersParameterAccessor accessor) {
return binder.bindAndPrepare(query, values);
return binder.bindAndPrepare(query, accessor);
}
private ParameterBinder getBinder(List<ParameterMetadata<?>> expressions) {
return ParameterBinderFactory.createCriteriaBinder(parameters, expressions);
}
private Sort getDynamicSort(Object[] values) {
private Sort getDynamicSort(JpaParametersParameterAccessor accessor) {
return parameters.potentiallySortsDynamically() //
? new ParametersParameterAccessor(parameters, values).getSort() //
? accessor.getSort() //
: Sort.unsorted();
}
}
@@ -351,20 +354,20 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
super(persistenceProvider, recreateQueries);
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.PartTreeJpaQuery.QueryPreparer#createCreator(org.springframework.data.repository.query.ParametersParameterAccessor, org.springframework.data.jpa.provider.PersistenceProvider)
*/
@Override
protected JpaQueryCreator createCreator(PersistenceProvider persistenceProvider,
Optional<ParametersParameterAccessor> accessor) {
JpaParametersParameterAccessor accessor) {
EntityManager entityManager = getEntityManager();
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
ParameterMetadataProvider provider = accessor
.map(it -> new ParameterMetadataProvider(builder, it, persistenceProvider, escape))//
.orElseGet(() -> new ParameterMetadataProvider(builder, parameters, persistenceProvider, escape));
ParameterMetadataProvider provider;
if (accessor != null) {
provider = new ParameterMetadataProvider(builder, accessor, persistenceProvider, escape);
} else {
provider = new ParameterMetadataProvider(builder, parameters, persistenceProvider, escape);
}
return new JpaCountQueryCreator(tree, getQueryMethod().getResultProcessor().getReturnedType(), builder, provider);
}
@@ -372,11 +375,12 @@ public class PartTreeJpaQuery extends AbstractJpaQuery {
/**
* Customizes binding by skipping the pagination.
*
* @see QueryPreparer#invokeBinding(ParameterBinder, TypedQuery, Object[])
* @see QueryPreparer#invokeBinding(ParameterBinder, TypedQuery, JpaParametersParameterAccessor)
*/
@Override
protected Query invokeBinding(ParameterBinder binder, TypedQuery<?> query, Object[] values) {
return binder.bind(query, values);
protected Query invokeBinding(ParameterBinder binder, TypedQuery<?> query,
JpaParametersParameterAccessor accessor) {
return binder.bind(query, accessor);
}
}
}

View File

@@ -28,6 +28,7 @@ import javax.persistence.criteria.ParameterExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -41,7 +42,7 @@ import org.springframework.util.Assert;
*/
interface QueryParameterSetter {
void setParameter(Query query, Object[] values, ErrorHandling errorHandling);
void setParameter(Query query, JpaParametersParameterAccessor accessor, ErrorHandling errorHandling);
/** Noop implementation */
QueryParameterSetter NOOP = (query, values, errorHandling) -> {};
@@ -53,7 +54,7 @@ interface QueryParameterSetter {
private static final Logger LOGGER = LoggerFactory.getLogger(NamedOrIndexedQueryParameterSetter.class);
private final Function<Object[], Object> valueExtractor;
private final Function<JpaParametersParameterAccessor, Object> valueExtractor;
private final Parameter<?> parameter;
private final @Nullable TemporalType temporalType;
@@ -62,8 +63,8 @@ interface QueryParameterSetter {
* @param parameter must not be {@literal null}.
* @param temporalType may be {@literal null}.
*/
NamedOrIndexedQueryParameterSetter(Function<Object[], Object> valueExtractor, Parameter<?> parameter,
@Nullable TemporalType temporalType) {
NamedOrIndexedQueryParameterSetter(Function<JpaParametersParameterAccessor, Object> valueExtractor,
Parameter<?> parameter, @Nullable TemporalType temporalType) {
Assert.notNull(valueExtractor, "ValueExtractor must not be null!");
@@ -78,9 +79,9 @@ interface QueryParameterSetter {
*/
@SuppressWarnings("unchecked")
@Override
public void setParameter(Query query, Object[] values, ErrorHandling errorHandling) {
public void setParameter(Query query, JpaParametersParameterAccessor accessor, ErrorHandling errorHandling) {
Object value = valueExtractor.apply(values);
Object value = valueExtractor.apply(accessor);
if (temporalType != null) {
@@ -143,7 +144,7 @@ interface QueryParameterSetter {
/**
* Returns the actual target {@link Query} instance, even if the provided query is a {@link Proxy} based on
* {@link org.springframework.orm.jpa.SharedEntityManagerCreator.DeferredQueryInvocationHandler}.
*
*
* @param query a {@link Query} instance, possibly a Proxy.
* @return the class of the actual underlying class if it can be determined, the class of the passed in instance
* otherwise.

View File

@@ -106,7 +106,8 @@ abstract class QueryParameterSetterFactory {
* @param binding the binding of the query parameter to be set.
* @param parameter the method parameter to bind.
*/
private static QueryParameterSetter createSetter(Function<Object[], Object> valueExtractor, ParameterBinding binding,
private static QueryParameterSetter createSetter(Function<JpaParametersParameterAccessor, Object> valueExtractor,
ParameterBinding binding,
@Nullable JpaParameter parameter) {
TemporalType temporalType = parameter != null && parameter.isTemporalParameter() //
@@ -172,9 +173,9 @@ abstract class QueryParameterSetterFactory {
* @return the result of the evaluation.
*/
@Nullable
private Object evaluateExpression(Expression expression, Object[] values) {
private Object evaluateExpression(Expression expression, JpaParametersParameterAccessor accessor) {
EvaluationContext context = evaluationContextProvider.getEvaluationContext(parameters, values);
EvaluationContext context = evaluationContextProvider.getEvaluationContext(parameters, accessor.getValues());
return expression.getValue(context, Object.class);
}
@@ -244,8 +245,8 @@ abstract class QueryParameterSetterFactory {
.findFirst().orElse(null);
}
private Object getValue(Object[] values, Parameter parameter) {
return new JpaParametersParameterAccessor(parameters, values).getValue(parameter);
private Object getValue(JpaParametersParameterAccessor accessor, Parameter parameter) {
return accessor.getValue(parameter);
}
private static String getName(JpaParameter p) {
@@ -306,15 +307,15 @@ abstract class QueryParameterSetterFactory {
JpaParameter parameter = parameters.getBindableParameter(parameterIndex);
TemporalType temporalType = parameter.isTemporalParameter() ? parameter.getRequiredTemporalType() : null;
return new NamedOrIndexedQueryParameterSetter(values -> getAndPrepare(parameter, metadata, values),
return new NamedOrIndexedQueryParameterSetter(values -> {
return getAndPrepare(parameter, metadata, values);
},
metadata.getExpression(), temporalType);
}
@Nullable
private Object getAndPrepare(JpaParameter parameter, ParameterMetadata<?> metadata, Object[] values) {
JpaParametersParameterAccessor accessor = new JpaParametersParameterAccessor(parameters, values);
private Object getAndPrepare(JpaParameter parameter, ParameterMetadata<?> metadata,
JpaParametersParameterAccessor accessor) {
return metadata.prepare(accessor.getValue(parameter));
}
}

View File

@@ -28,6 +28,7 @@ import javax.persistence.TypedQuery;
import org.springframework.data.jpa.repository.query.JpaParameters.JpaParameter;
import org.springframework.data.repository.query.Parameter;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
@@ -83,28 +84,28 @@ class StoredProcedureJpaQuery extends AbstractJpaQuery {
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#createQuery(java.lang.Object[])
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#createQuery(JpaParametersParameterAccessor)
*/
@Override
protected StoredProcedureQuery createQuery(Object[] values) {
return applyHints(doCreateQuery(values), getQueryMethod());
protected StoredProcedureQuery createQuery(JpaParametersParameterAccessor accessor) {
return applyHints(doCreateQuery(accessor), getQueryMethod());
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateQuery(java.lang.Object[])
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateQuery(JpaParametersParameterAccessor)
*/
@Override
protected StoredProcedureQuery doCreateQuery(Object[] values) {
return parameterBinder.get().bind(createStoredProcedure(), values);
protected StoredProcedureQuery doCreateQuery(JpaParametersParameterAccessor accessor) {
return parameterBinder.get().bind(createStoredProcedure(), accessor);
}
/*
* (non-Javadoc)
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateCountQuery(java.lang.Object[])
* @see org.springframework.data.jpa.repository.query.AbstractJpaQuery#doCreateCountQuery(JpaParametersParameterAccessor)
*/
@Override
protected TypedQuery<Long> doCreateCountQuery(Object[] values) {
protected TypedQuery<Long> doCreateCountQuery(JpaParametersParameterAccessor accessor) {
throw new UnsupportedOperationException("StoredProcedureQuery does not support count queries!");
}

View File

@@ -51,6 +51,7 @@ import org.springframework.transaction.annotation.Transactional;
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:infrastructure.xml")
@@ -75,10 +76,12 @@ public class AbstractJpaQueryTests {
AbstractJpaQuery jpaQuery = new DummyJpaQuery(queryMethod, em);
Query result = jpaQuery.createQuery(new Object[] { "Matthews" });
Query result = jpaQuery
.createQuery(new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { "Matthews" }));
verify(result).setHint("foo", "bar");
result = jpaQuery.createCountQuery(new Object[] { "Matthews" });
result = jpaQuery
.createCountQuery(new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { "Matthews" }));
verify(result).setHint("foo", "bar");
}
@@ -88,10 +91,12 @@ public class AbstractJpaQueryTests {
JpaQueryMethod queryMethod = getMethod("findByFirstname", String.class);
AbstractJpaQuery jpaQuery = new DummyJpaQuery(queryMethod, em);
Query result = jpaQuery.createQuery(new Object[] { "Dave" });
Query result = jpaQuery
.createQuery(new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { "Dave" }));
verify(result).setHint("bar", "foo");
result = jpaQuery.createCountQuery(new Object[] { "Dave" });
result = jpaQuery
.createCountQuery(new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { "Dave" }));
verify(result, never()).setHint("bar", "foo");
}
@@ -103,7 +108,8 @@ public class AbstractJpaQueryTests {
JpaQueryMethod queryMethod = getMethod("findOneLocked", Integer.class);
AbstractJpaQuery jpaQuery = new DummyJpaQuery(queryMethod, em);
Query result = jpaQuery.createQuery(new Object[] { Integer.valueOf(1) });
Query result = jpaQuery.createQuery(
new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { Integer.valueOf(1) }));
verify(result).setLockMode(LockModeType.PESSIMISTIC_WRITE);
}
@@ -118,7 +124,7 @@ public class AbstractJpaQueryTests {
javax.persistence.EntityGraph<?> entityGraph = em.getEntityGraph("User.overview");
AbstractJpaQuery jpaQuery = new DummyJpaQuery(queryMethod, em);
Query result = jpaQuery.createQuery(new Object[0]);
Query result = jpaQuery.createQuery(new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[0]));
verify(result).setHint("javax.persistence.fetchgraph", entityGraph);
}
@@ -134,7 +140,8 @@ public class AbstractJpaQueryTests {
javax.persistence.EntityGraph<?> entityGraph = em.getEntityGraph("User.detail");
AbstractJpaQuery jpaQuery = new DummyJpaQuery(queryMethod, em);
Query result = jpaQuery.createQuery(new Object[] { 1 });
Query result = jpaQuery
.createQuery(new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { 1 }));
verify(result).setHint("javax.persistence.loadgraph", entityGraph);
}
@@ -176,12 +183,12 @@ public class AbstractJpaQueryTests {
}
@Override
protected Query doCreateQuery(Object[] values) {
protected Query doCreateQuery(JpaParametersParameterAccessor accessor) {
return query;
}
@Override
protected TypedQuery<Long> doCreateCountQuery(Object[] values) {
protected TypedQuery<Long> doCreateCountQuery(JpaParametersParameterAccessor accessor) {
return (TypedQuery<Long>) countQuery;
}
}

View File

@@ -33,12 +33,11 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.query.JpaQueryExecution.ModifyingExecution;
import org.springframework.data.jpa.repository.query.JpaQueryExecution.PagedExecution;
import org.springframework.data.repository.query.DefaultParameters;
import org.springframework.data.repository.query.Parameters;
/**
* Unit test for {@link JpaQueryExecution}.
@@ -56,6 +55,7 @@ public class JpaQueryExecutionUnitTests {
@Mock AbstractStringBasedJpaQuery jpaQuery;
@Mock Query query;
@Mock JpaQueryMethod method;
@Mock JpaParametersParameterAccessor accessor;
@Mock TypedQuery<Long> countQuery;
@@ -65,14 +65,14 @@ public class JpaQueryExecutionUnitTests {
public void setUp() {
when(query.executeUpdate()).thenReturn(0);
when(jpaQuery.createQuery(Mockito.any(Object[].class))).thenReturn(query);
when(jpaQuery.createQuery(Mockito.any(JpaParametersParameterAccessor.class))).thenReturn(query);
when(jpaQuery.getQueryMethod()).thenReturn(method);
}
@Test(expected = IllegalArgumentException.class)
public void rejectsNullQuery() {
new StubQueryExecution().execute(null, new Object[] {});
new StubQueryExecution().execute(null, accessor);
}
@Test(expected = IllegalArgumentException.class)
@@ -87,11 +87,11 @@ public class JpaQueryExecutionUnitTests {
assertThat(new JpaQueryExecution() {
@Override
protected Object doExecute(AbstractJpaQuery query, Object[] values) {
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
return null;
}
}.execute(jpaQuery, new Object[] {})).isNull();
}.execute(jpaQuery, accessor)).isNull();
}
@Test // DATAJPA-806
@@ -102,7 +102,7 @@ public class JpaQueryExecutionUnitTests {
when(method.getFlushAutomatically()).thenReturn(true);
ModifyingExecution execution = new ModifyingExecution(method, em);
execution.execute(jpaQuery, new Object[] {});
execution.execute(jpaQuery, accessor);
verify(em, times(1)).flush();
verify(em, times(0)).clear();
@@ -116,7 +116,7 @@ public class JpaQueryExecutionUnitTests {
when(method.getClearAutomatically()).thenReturn(true);
ModifyingExecution execution = new ModifyingExecution(method, em);
execution.execute(jpaQuery, new Object[] {});
execution.execute(jpaQuery, accessor);
verify(em, times(0)).flush();
verify(em, times(1)).clear();
@@ -144,13 +144,14 @@ public class JpaQueryExecutionUnitTests {
@Test // DATAJPA-124, DATAJPA-912
public void pagedExecutionRetrievesObjectsForPageableOutOfRange() throws Exception {
Parameters<?, ?> parameters = new DefaultParameters(getClass().getMethod("sampleMethod", Pageable.class));
when(jpaQuery.createCountQuery(Mockito.any(Object[].class))).thenReturn(countQuery);
when(jpaQuery.createQuery(Mockito.any(Object[].class))).thenReturn(query);
JpaParameters parameters = new JpaParameters(getClass().getMethod("sampleMethod", Pageable.class));
when(jpaQuery.createCountQuery(Mockito.any())).thenReturn(countQuery);
when(jpaQuery.createQuery(Mockito.any())).thenReturn(query);
when(countQuery.getResultList()).thenReturn(Arrays.asList(20L));
PagedExecution execution = new PagedExecution(parameters);
execution.doExecute(jpaQuery, new Object[] { PageRequest.of(2, 10) });
PagedExecution execution = new PagedExecution();
execution.doExecute(jpaQuery,
new JpaParametersParameterAccessor(parameters, new Object[] { PageRequest.of(2, 10) }));
verify(query).getResultList();
verify(countQuery).getResultList();
@@ -159,73 +160,78 @@ public class JpaQueryExecutionUnitTests {
@Test // DATAJPA-477, DATAJPA-912
public void pagedExecutionShouldNotGenerateCountQueryIfQueryReportedNoResults() throws Exception {
Parameters<?, ?> parameters = new DefaultParameters(getClass().getMethod("sampleMethod", Pageable.class));
when(jpaQuery.createQuery(Mockito.any(Object[].class))).thenReturn(query);
JpaParameters parameters = new JpaParameters(getClass().getMethod("sampleMethod", Pageable.class));
when(jpaQuery.createQuery(Mockito.any())).thenReturn(query);
when(query.getResultList()).thenReturn(Arrays.asList(0L));
PagedExecution execution = new PagedExecution(parameters);
execution.doExecute(jpaQuery, new Object[] { PageRequest.of(0, 10) });
PagedExecution execution = new PagedExecution();
execution.doExecute(jpaQuery,
new JpaParametersParameterAccessor(parameters, new Object[] { PageRequest.of(0, 10) }));
verify(countQuery, times(0)).getResultList();
verify(jpaQuery, times(0)).createCountQuery((Object[]) any());
verify(jpaQuery, times(0)).createCountQuery(any());
}
@Test // DATAJPA-912
public void pagedExecutionShouldUseCountFromResultIfOffsetIsZeroAndResultsWithinPageSize() throws Exception {
Parameters<?, ?> parameters = new DefaultParameters(getClass().getMethod("sampleMethod", Pageable.class));
when(jpaQuery.createQuery(Mockito.any(Object[].class))).thenReturn(query);
JpaParameters parameters = new JpaParameters(getClass().getMethod("sampleMethod", Pageable.class));
when(jpaQuery.createQuery(Mockito.any())).thenReturn(query);
when(query.getResultList()).thenReturn(Arrays.asList(new Object(), new Object(), new Object(), new Object()));
PagedExecution execution = new PagedExecution(parameters);
execution.doExecute(jpaQuery, new Object[] { PageRequest.of(0, 10) });
PagedExecution execution = new PagedExecution();
execution.doExecute(jpaQuery,
new JpaParametersParameterAccessor(parameters, new Object[] { PageRequest.of(0, 10) }));
verify(jpaQuery, times(0)).createCountQuery((Object[]) any());
verify(jpaQuery, times(0)).createCountQuery(any());
}
@Test // DATAJPA-912
public void pagedExecutionShouldUseCountFromResultWithOffsetAndResultsWithinPageSize() throws Exception {
Parameters<?, ?> parameters = new DefaultParameters(getClass().getMethod("sampleMethod", Pageable.class));
when(jpaQuery.createQuery(Mockito.any(Object[].class))).thenReturn(query);
JpaParameters parameters = new JpaParameters(getClass().getMethod("sampleMethod", Pageable.class));
when(jpaQuery.createQuery(Mockito.any())).thenReturn(query);
when(query.getResultList()).thenReturn(Arrays.asList(new Object(), new Object(), new Object(), new Object()));
PagedExecution execution = new PagedExecution(parameters);
execution.doExecute(jpaQuery, new Object[] { PageRequest.of(5, 10) });
PagedExecution execution = new PagedExecution();
execution.doExecute(jpaQuery,
new JpaParametersParameterAccessor(parameters, new Object[] { PageRequest.of(5, 10) }));
verify(jpaQuery, times(0)).createCountQuery((Object[]) any());
verify(jpaQuery, times(0)).createCountQuery(any());
}
@Test // DATAJPA-912
public void pagedExecutionShouldUseRequestCountFromResultWithOffsetAndResultsHitLowerPageSizeBounds()
throws Exception {
Parameters<?, ?> parameters = new DefaultParameters(getClass().getMethod("sampleMethod", Pageable.class));
when(jpaQuery.createQuery(Mockito.any(Object[].class))).thenReturn(query);
JpaParameters parameters = new JpaParameters(getClass().getMethod("sampleMethod", Pageable.class));
when(jpaQuery.createQuery(Mockito.any())).thenReturn(query);
when(query.getResultList()).thenReturn(Collections.emptyList());
when(jpaQuery.createCountQuery(Mockito.any(Object[].class))).thenReturn(query);
when(jpaQuery.createCountQuery(Mockito.any())).thenReturn(query);
when(countQuery.getResultList()).thenReturn(Arrays.asList(20L));
PagedExecution execution = new PagedExecution(parameters);
execution.doExecute(jpaQuery, new Object[] { PageRequest.of(4, 4) });
PagedExecution execution = new PagedExecution();
execution.doExecute(jpaQuery,
new JpaParametersParameterAccessor(parameters, new Object[] { PageRequest.of(4, 4) }));
verify(jpaQuery).createCountQuery((Object[]) any());
verify(jpaQuery).createCountQuery(any());
}
@Test // DATAJPA-912
public void pagedExecutionShouldUseRequestCountFromResultWithOffsetAndResultsHitUpperPageSizeBounds()
throws Exception {
Parameters<?, ?> parameters = new DefaultParameters(getClass().getMethod("sampleMethod", Pageable.class));
when(jpaQuery.createQuery(Mockito.any(Object[].class))).thenReturn(query);
JpaParameters parameters = new JpaParameters(getClass().getMethod("sampleMethod", Pageable.class));
when(jpaQuery.createQuery(Mockito.any())).thenReturn(query);
when(query.getResultList()).thenReturn(Arrays.asList(new Object(), new Object(), new Object(), new Object()));
when(jpaQuery.createCountQuery(Mockito.any(Object[].class))).thenReturn(query);
when(jpaQuery.createCountQuery(Mockito.any())).thenReturn(query);
when(countQuery.getResultList()).thenReturn(Arrays.asList(20L));
PagedExecution execution = new PagedExecution(parameters);
execution.doExecute(jpaQuery, new Object[] { PageRequest.of(4, 4) });
PagedExecution execution = new PagedExecution();
execution.doExecute(jpaQuery,
new JpaParametersParameterAccessor(parameters, new Object[] { PageRequest.of(4, 4) }));
verify(jpaQuery).createCountQuery((Object[]) any());
verify(jpaQuery).createCountQuery(any());
}
@Test // DATAJPA-951
@@ -233,15 +239,16 @@ public class JpaQueryExecutionUnitTests {
doReturn(method).when(jpaQuery).getQueryMethod();
doReturn(Optional.class).when(method).getReturnType();
JpaParametersParameterAccessor accessor = mock(JpaParametersParameterAccessor.class);
StubQueryExecution execution = new StubQueryExecution() {
@Override
protected Object doExecute(AbstractJpaQuery query, Object[] values) {
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
return "result";
}
};
Object result = execution.execute(jpaQuery, new Object[0]);
Object result = execution.execute(jpaQuery, accessor);
assertThat(result).isInstanceOf(String.class);
}
@@ -249,7 +256,7 @@ public class JpaQueryExecutionUnitTests {
static class StubQueryExecution extends JpaQueryExecution {
@Override
protected Object doExecute(AbstractJpaQuery query, Object[] values) {
protected Object doExecute(AbstractJpaQuery query, JpaParametersParameterAccessor accessor) {
return null;
}
}

View File

@@ -35,20 +35,22 @@ import javax.persistence.TemporalType;
import javax.persistence.criteria.ParameterExpression;
import org.assertj.core.api.SoftAssertions;
import org.junit.Before;
import org.junit.Test;
import org.springframework.data.jpa.repository.query.QueryParameterSetter.NamedOrIndexedQueryParameterSetter;
/**
* Unit tests fir {@link NamedOrIndexedQueryParameterSetter}.
*
*
* @author Jens Schauder
* @author Oliver Gierke
* @author Mark Paluch
*/
public class NamedOrIndexedQueryParameterSetterUnitTests {
static final String EXCEPTION_MESSAGE = "mock exception";
Function<Object[], Object> firstValueExtractor = args -> args[0];
Object[] methodArguments = { new Date() };
Function<JpaParametersParameterAccessor, Object> firstValueExtractor = args -> args.getValues()[0];
JpaParametersParameterAccessor methodArguments;
List<TemporalType> temporalTypes = asList(null, TIME);
List<Parameter<?>> parameters = Arrays.<Parameter<?>> asList( //
@@ -59,6 +61,15 @@ public class NamedOrIndexedQueryParameterSetterUnitTests {
SoftAssertions softly = new SoftAssertions();
@Before
public void before() {
JpaParametersParameterAccessor accessor = mock(JpaParametersParameterAccessor.class);
when(accessor.getValues()).thenReturn(new Object[] { new Date() });
this.methodArguments = accessor;
}
@Test // DATAJPA-1233
public void strictErrorHandlingThrowsExceptionForAllVariationsOfParameters() {

View File

@@ -43,6 +43,7 @@ import org.springframework.data.repository.query.QueryCreationException;
*
* @author Oliver Gierke
* @author Thomas Darimont
* @author Mark Paluch
*/
@RunWith(MockitoJUnitRunner.class)
public class NamedQueryUnitTests {
@@ -92,7 +93,7 @@ public class NamedQueryUnitTests {
when(em.createNamedQuery(eq(queryMethod.getNamedCountQueryName()), eq(Long.class))).thenReturn(countQuery);
NamedQuery query = (NamedQuery) NamedQuery.lookupFrom(queryMethod, em);
query.doCreateCountQuery(new Object[1]);
query.doCreateCountQuery(new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[1]));
verify(em, times(1)).createNamedQuery(queryMethod.getNamedCountQueryName(), Long.class);
verify(em, never()).createQuery(any(String.class), eq(Long.class));
}

View File

@@ -47,6 +47,7 @@ import org.springframework.data.repository.query.Param;
* @author Oliver Gierke
* @author Thomas Darimont
* @author Jens Schauder
* @author Mark Paluch
*/
@RunWith(MockitoJUnitRunner.class)
public class ParameterBinderUnitTests {
@@ -101,7 +102,8 @@ public class ParameterBinderUnitTests {
Method validWithSort = SampleRepository.class.getMethod("validWithSort", String.class, Sort.class);
Object[] values = { "foo", null };
ParameterBinderFactory.createBinder(new JpaParameters(validWithSort)).bind(query, values);
ParameterBinderFactory.createBinder(new JpaParameters(validWithSort)).bind(query,
new JpaParametersParameterAccessor(new JpaParameters(validWithSort), values));
verify(query).setParameter(eq(1), eq("foo"));
}
@@ -111,7 +113,8 @@ public class ParameterBinderUnitTests {
Method validWithPageable = SampleRepository.class.getMethod("validWithPageable", String.class, Pageable.class);
Object[] values = { "foo", null };
ParameterBinderFactory.createBinder(new JpaParameters(validWithPageable)).bind(query, values);
ParameterBinderFactory.createBinder(new JpaParameters(validWithPageable)).bind(query,
new JpaParametersParameterAccessor(new JpaParameters(validWithPageable), values));
verify(query).setParameter(eq(1), eq("foo"));
}
@@ -119,7 +122,8 @@ public class ParameterBinderUnitTests {
public void usesIndexedParametersIfNoParamAnnotationPresent() throws Exception {
Object[] values = { "foo" };
ParameterBinderFactory.createBinder(new JpaParameters(useIndexedParameters)).bind(query, values);
ParameterBinderFactory.createBinder(new JpaParameters(useIndexedParameters)).bind(query,
new JpaParametersParameterAccessor(new JpaParameters(useIndexedParameters), values));
verify(query).setParameter(eq(1), any());
}
@@ -134,7 +138,8 @@ public class ParameterBinderUnitTests {
when(query.getParameters()).thenReturn(singleton(parameter));
Object[] values = { "foo" };
ParameterBinderFactory.createBinder(new JpaParameters(valid)).bind(query, values);
ParameterBinderFactory.createBinder(new JpaParameters(valid)).bind(query,
new JpaParametersParameterAccessor(new JpaParameters(valid), values));
verify(query).setParameter(eq("username"), any());
}
@@ -147,7 +152,7 @@ public class ParameterBinderUnitTests {
SampleEmbeddable embeddable = new SampleEmbeddable();
Object[] values = { embeddable };
ParameterBinderFactory.createBinder(parameters).bind(query, values);
ParameterBinderFactory.createBinder(parameters).bind(query, getAccessor(method, values));
verify(query).setParameter(1, embeddable);
}
@@ -160,7 +165,7 @@ public class ParameterBinderUnitTests {
Date date = new Date();
Object[] values = { date };
ParameterBinderFactory.createBinder(parameters).bind(query, values);
ParameterBinderFactory.createBinder(parameters).bind(query, getAccessor(method, values));
verify(query).setParameter(eq(1), eq(date), eq(TemporalType.DATE));
}
@@ -173,7 +178,7 @@ public class ParameterBinderUnitTests {
Date date = new Date();
Object[] values = { date };
ParameterBinderFactory.createBinder(parameters).bind(query, values);
ParameterBinderFactory.createBinder(parameters).bind(query, getAccessor(method, values));
verify(query).setParameter(eq(1), eq(date), eq(TemporalType.TIMESTAMP));
}
@@ -194,7 +199,7 @@ public class ParameterBinderUnitTests {
JpaParameters parameters = new JpaParameters(method);
Integer[] ids = new Integer[] { 1, 2, 3 };
Object[] values = { ids };
ParameterBinderFactory.createBinder(parameters).bind(query, values);
ParameterBinderFactory.createBinder(parameters).bind(query, getAccessor(method, values));
verify(query).setParameter(eq(1), eq(ids));
}
@@ -206,7 +211,7 @@ public class ParameterBinderUnitTests {
JpaParameters parameters = new JpaParameters(method);
Object[] values = { Optional.of("Foo") };
ParameterBinderFactory.createBinder(parameters).bind(query, values);
ParameterBinderFactory.createBinder(parameters).bind(query, getAccessor(method, values));
verify(query).setParameter(eq(1), eq("Foo"));
}
@@ -217,12 +222,16 @@ public class ParameterBinderUnitTests {
Method method = SampleRepository.class.getMethod("withQuery", String.class, String.class);
Object[] values = { "foo", "superfluous" };
ParameterBinderFactory.createBinder(new JpaParameters(method)).bind(query, values);
ParameterBinderFactory.createBinder(new JpaParameters(method)).bind(query, getAccessor(method, values));
verify(query).setParameter(eq(1), any());
verify(query, never()).setParameter(eq(2), any());
}
private JpaParametersParameterAccessor getAccessor(Method method, Object... values) {
return new JpaParametersParameterAccessor(new JpaParameters(method), values);
}
public SampleEntity findByEmbeddable(SampleEmbeddable embeddable) {
return null;

View File

@@ -85,8 +85,8 @@ public class PartTreeJpaQueryIntegrationTests {
JpaQueryMethod queryMethod = getQueryMethod("findByFirstname", String.class, Pageable.class);
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider);
jpaQuery.createQuery(new Object[] { "Matthews", PageRequest.of(0, 1) });
jpaQuery.createQuery(new Object[] { "Matthews", PageRequest.of(0, 1) });
jpaQuery.createQuery(getAccessor(queryMethod, new Object[] { "Matthews", PageRequest.of(0, 1) }));
jpaQuery.createQuery((getAccessor(queryMethod, new Object[] { "Matthews", PageRequest.of(0, 1) })));
}
@Test
@@ -109,11 +109,11 @@ public class PartTreeJpaQueryIntegrationTests {
JpaQueryMethod queryMethod = getQueryMethod("findByFirstname", String.class, Pageable.class);
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider);
Query query = jpaQuery.createQuery(new Object[] { "Matthews", PageRequest.of(0, 1) });
Query query = jpaQuery.createQuery((getAccessor(queryMethod, new Object[] { "Matthews", PageRequest.of(0, 1) })));
assertThat(HibernateUtils.getHibernateQuery(getValue(query, PROPERTY))).endsWith("firstname=:param0");
query = jpaQuery.createQuery(new Object[] { null, PageRequest.of(0, 1) });
query = jpaQuery.createQuery((getAccessor(queryMethod, new Object[] { null, PageRequest.of(0, 1) })));
assertThat(HibernateUtils.getHibernateQuery(getValue(query, PROPERTY))).endsWith("firstname is null");
}
@@ -124,7 +124,7 @@ public class PartTreeJpaQueryIntegrationTests {
JpaQueryMethod queryMethod = getQueryMethod("existsByFirstname", String.class);
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider);
Query query = jpaQuery.createQuery(new Object[] { "Matthews" });
Query query = jpaQuery.createQuery((getAccessor(queryMethod, new Object[] { "Matthews" })));
assertThat(query.getMaxResults()).isEqualTo(1);
}
@@ -135,7 +135,7 @@ public class PartTreeJpaQueryIntegrationTests {
JpaQueryMethod queryMethod = getQueryMethod("existsByFirstname", String.class);
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider);
Query query = jpaQuery.createQuery(new Object[] { "Matthews" });
Query query = jpaQuery.createQuery((getAccessor(queryMethod, new Object[] { "Matthews" })));
assertThat(HibernateUtils.getHibernateQuery(getValue(query, PROPERTY))).contains(".id from User as");
}
@@ -146,7 +146,7 @@ public class PartTreeJpaQueryIntegrationTests {
JpaQueryMethod queryMethod = getQueryMethod("findByRolesIsEmpty");
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider);
Query query = jpaQuery.createQuery(new Object[] {});
Query query = jpaQuery.createQuery((getAccessor(queryMethod, new Object[] {})));
assertThat(HibernateUtils.getHibernateQuery(getValue(query, PROPERTY))).endsWith("roles is empty");
}
@@ -157,7 +157,7 @@ public class PartTreeJpaQueryIntegrationTests {
JpaQueryMethod queryMethod = getQueryMethod("findByRolesIsNotEmpty");
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider);
Query query = jpaQuery.createQuery(new Object[] {});
Query query = jpaQuery.createQuery((getAccessor(queryMethod, new Object[] {})));
assertThat(HibernateUtils.getHibernateQuery(getValue(query, PROPERTY))).endsWith("roles is not empty");
}
@@ -168,7 +168,7 @@ public class PartTreeJpaQueryIntegrationTests {
JpaQueryMethod method = getQueryMethod("findByFirstnameIsEmpty");
AbstractJpaQuery jpaQuery = new PartTreeJpaQuery(method, entityManager, provider);
jpaQuery.createQuery(new Object[] { "Oliver" });
jpaQuery.createQuery((getAccessor(method, new Object[] { "Oliver" })));
}
@Test // DATAJPA-1182
@@ -232,7 +232,7 @@ public class PartTreeJpaQueryIntegrationTests {
JpaQueryMethod queryMethod = getQueryMethod(methodName, parameterTypes);
PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager,
PersistenceProvider.fromEntityManager(entityManager));
jpaQuery.createQuery(values);
jpaQuery.createQuery((getAccessor(queryMethod, values)));
}
private JpaQueryMethod getQueryMethod(String methodName, Class<?>... parameterTypes) throws Exception {
@@ -258,6 +258,10 @@ public class PartTreeJpaQueryIntegrationTests {
return (T) result;
}
private JpaParametersParameterAccessor getAccessor(JpaQueryMethod queryMethod, Object[] values) {
return new JpaParametersParameterAccessor(queryMethod.getParameters(), values);
}
private static String getQueryProperty() {
return isHibernate43() || isHibernate5() ? "jpqlQuery" : "val$jpaqlQuery";
}

View File

@@ -111,7 +111,8 @@ public class SimpleJpaQueryUnitTests {
SimpleJpaQuery jpaQuery = new SimpleJpaQuery(method, em, "select u from User u", EVALUATION_CONTEXT_PROVIDER,
PARSER);
assertThat(jpaQuery.createCountQuery(new Object[] {})).isEqualTo((javax.persistence.Query) typedQuery);
assertThat(jpaQuery.createCountQuery(new JpaParametersParameterAccessor(method.getParameters(), new Object[] {})))
.isEqualTo(typedQuery);
}
@Test // DATAJPA-77
@@ -124,7 +125,8 @@ public class SimpleJpaQueryUnitTests {
AbstractJpaQuery jpaQuery = new SimpleJpaQuery(queryMethod, em, "select u from User u", EVALUATION_CONTEXT_PROVIDER,
PARSER);
jpaQuery.createCountQuery(new Object[] { PageRequest.of(1, 10) });
jpaQuery.createCountQuery(
new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { PageRequest.of(1, 10) }));
verify(query, times(0)).setFirstResult(anyInt());
verify(query, times(0)).setMaxResults(anyInt());
@@ -144,7 +146,7 @@ public class SimpleJpaQueryUnitTests {
when(em.createNativeQuery(anyString(), eq(User.class))).thenReturn(query);
when(metadata.getReturnedDomainClass(method)).thenReturn((Class) User.class);
jpaQuery.createQuery(new Object[] { "Matthews" });
jpaQuery.createQuery(new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { "Matthews" }));
verify(em).createNativeQuery("SELECT u FROM User u WHERE u.lastname = ?1", User.class);
}
@@ -202,7 +204,8 @@ public class SimpleJpaQueryUnitTests {
AbstractJpaQuery jpaQuery = createJpaQuery(
UserRepository.class.getMethod("findUsersInNativeQueryWithPagination", Pageable.class));
jpaQuery.doCreateCountQuery(new Object[] { PageRequest.of(0, 10) });
jpaQuery.doCreateCountQuery(new JpaParametersParameterAccessor(jpaQuery.getQueryMethod().getParameters(),
new Object[] { PageRequest.of(0, 10) }));
verify(em).createNativeQuery(anyString());
}
@@ -212,7 +215,7 @@ public class SimpleJpaQueryUnitTests {
AbstractJpaQuery jpaQuery = createJpaQuery(SampleRepository.class.getMethod("projectWithExplicitQuery"));
jpaQuery.createQuery(new Object[0]);
jpaQuery.createQuery(new JpaParametersParameterAccessor(jpaQuery.getQueryMethod().getParameters(), new Object[0]));
verify(em, times(0)).createQuery(anyString(), eq(Tuple.class));
@@ -242,7 +245,8 @@ public class SimpleJpaQueryUnitTests {
AbstractJpaQuery jpaQuery = new SimpleJpaQuery(queryMethod, em, "select u from User u", EVALUATION_CONTEXT_PROVIDER,
PARSER);
jpaQuery.createCountQuery(new Object[] { PageRequest.of(1, 10) });
jpaQuery.createCountQuery(
new JpaParametersParameterAccessor(queryMethod.getParameters(), new Object[] { PageRequest.of(1, 10) }));
verify(em).createQuery(eq("select u from User u"));
verify(em).createQuery(eq("select count(u.id) from User u"), eq(Long.class));