From 4d1188b751b7a0bda76d8eb831a294898043a6ad Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 7 Dec 2010 20:43:54 +0100 Subject: [PATCH] Migrated query-from-methodname algorithm to PartTree infrastructure. Query creation is not String based anymore but rather leverages the PartTree infrastructure and builds a JPA criteria API query instead. Changed query lookup and execution accordingly. --- .../repository/query/AbstractJpaQuery.java | 57 +-- .../query/AbstractStringBasedJpaQuery.java | 59 ++++ .../query/JpaCountQueryCreator.java | 56 +++ .../jpa/repository/query/JpaQueryCreator.java | 209 +++++++++++ .../repository/query/JpaQueryExecution.java | 105 +++++- .../query/JpaQueryLookupStrategy.java | 2 +- .../jpa/repository/query/JpaQueryMethod.java | 2 +- .../data/jpa/repository/query/NamedQuery.java | 13 +- .../jpa/repository/query/ParameterBinder.java | 2 +- .../repository/query/PartTreeJpaQuery.java | 85 +++++ .../jpa/repository/query/QueryCreator.java | 166 --------- .../data/jpa/repository/query/QueryUtils.java | 51 ++- .../jpa/repository/query/SimpleJpaQuery.java | 57 +-- .../support/SimpleJpaRepository.java | 26 -- .../OpenJpaNamespaceUserDaoTests.java | 3 +- .../jpa/repository/UserRepositoryTests.java | 11 +- .../config/RepositoryAutoConfigTests.java | 3 +- .../config/TypeFilterConfigTest.java | 3 +- .../CustomGenericJpaRepositoryFactory.java | 7 +- .../custom/CustomGenericRepository.java | 8 +- .../custom/UserCustomExtendedRepository.java | 4 +- .../query/JpaQueryExecutionUnitTests.java | 30 +- .../query/JpaQueryMethodUnitTests.java | 48 ++- .../query/ParameterBinderUnitTests.java | 26 +- .../query/QueryCreatorUnitTests.java | 327 ------------------ .../query/SimpleJpaQueryUnitTests.java | 4 +- .../JpaRepositoryFactoryBeanUnitTests.java | 11 +- .../JpaRepositoryFactoryUnitTests.java | 3 +- 28 files changed, 691 insertions(+), 687 deletions(-) create mode 100644 src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java create mode 100644 src/main/java/org/springframework/data/jpa/repository/query/JpaCountQueryCreator.java create mode 100644 src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java create mode 100644 src/main/java/org/springframework/data/jpa/repository/query/PartTreeJpaQuery.java delete mode 100644 src/main/java/org/springframework/data/jpa/repository/query/QueryCreator.java delete mode 100644 src/test/java/org/springframework/data/jpa/repository/query/QueryCreatorUnitTests.java diff --git a/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java index ad71ee6a9..3098ce8f0 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java @@ -19,7 +19,6 @@ import javax.persistence.EntityManager; import javax.persistence.Query; import org.springframework.data.repository.query.Parameters; -import org.springframework.data.repository.query.QueryMethod; import org.springframework.data.repository.query.RepositoryQuery; import org.springframework.util.Assert; @@ -57,65 +56,37 @@ public abstract class AbstractJpaQuery implements RepositoryQuery { /** - * Creates a JPA {@link Query} with the given {@link ParameterBinder}. - * - * @param binder - * @return + * @return the parameters */ - public Query createQuery(ParameterBinder binder) { + public Parameters getParameters() { - return createQuery(em, binder); + return parameters; } /** - * Creates a JPA {@link Query} to count the instances of the - * {@link HadesQuery} to be returned. - * - * @param binder - * @return + * @return the em */ - public Query createCountQuery() { + public EntityManager getEntityManager() { - return createCountQuery(em); + return em; } - /** - * Executes the {@link javax.persistence.Query} backing the - * {@link QueryMethod} with the given parameters. + /* + * (non-Javadoc) * - * @param em - * @param parameters - * @return + * @see + * org.springframework.data.repository.query.RepositoryQuery#execute(java + * .lang.Object[]) */ public Object execute(Object[] parameters) { - ParameterBinder binder = - new ParameterBinder(this.parameters, parameters); - - return execution.execute(this, binder); + return doExecute(execution, parameters); } - /** - * Returns the actual {@link Query} to be executed. Has to return a fresh - * instance on each call. - * - * @param em - * @param binder - * @return - */ - protected abstract Query createQuery(EntityManager em, - ParameterBinder binder); + protected abstract Object doExecute(JpaQueryExecution execution, + Object[] parameters); - - /** - * Returns the projecting count {@link Query} to be executed. Has to return - * a fresh instance on each call. - * - * @param em - * @return - */ - protected abstract Query createCountQuery(EntityManager em); } \ No newline at end of file diff --git a/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java new file mode 100644 index 000000000..7c9ac96ac --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/repository/query/AbstractStringBasedJpaQuery.java @@ -0,0 +1,59 @@ +package org.springframework.data.jpa.repository.query; + +import javax.persistence.EntityManager; +import javax.persistence.Query; + + +/** + * Base class for {@link String} based JPA queries. + * + * @author Oliver Gierke + */ +public abstract class AbstractStringBasedJpaQuery extends AbstractJpaQuery { + + /** + * Creates a new {@link AbstractStringBasedJpaQuery}. + * + * @param method + * @param em + */ + public AbstractStringBasedJpaQuery(JpaQueryMethod method, EntityManager em) { + + super(method, em); + } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.jpa.repository.query.AbstractJpaQuery#doExecute + * (org.springframework.data.jpa.repository.query.JpaQueryExecution, + * java.lang.Object[]) + */ + @Override + protected Object doExecute(JpaQueryExecution execution, Object[] parameters) { + + ParameterBinder binder = + new ParameterBinder(getParameters(), parameters); + return execution.execute(this, binder); + } + + + /** + * Create a {@link Query} with the given {@link ParameterBinder}. + * + * @param binder + * @return + */ + protected abstract Query createQuery(ParameterBinder binder); + + + /** + * Create a count {@link Query} with the given {@link ParameterBinder}. + * + * @param binder + * @return + */ + protected abstract Query createCountQuery(ParameterBinder binder); +} diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaCountQueryCreator.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaCountQueryCreator.java new file mode 100644 index 000000000..14fbf3b68 --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaCountQueryCreator.java @@ -0,0 +1,56 @@ +package org.springframework.data.jpa.repository.query; + +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Predicate; + +import org.springframework.data.domain.Sort; +import org.springframework.data.repository.query.SimpleParameterAccessor; +import org.springframework.data.repository.query.parser.PartTree; + + +/** + * Special {@link JpaQueryCreator} that creates a count projecting query. + * + * @author Oliver Gierke + */ +public class JpaCountQueryCreator extends JpaQueryCreator { + + private final Class domainClass; + + + /** + * Creates a new {@link JpaCountQueryCreator}. + * + * @param tree + * @param parameters + * @param domainClass + * @param em + */ + public JpaCountQueryCreator(PartTree tree, + SimpleParameterAccessor parameters, Class domainClass, + EntityManager em) { + + super(tree, parameters, domainClass, em); + this.domainClass = domainClass; + } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.jpa.repository.query.JpaQueryCreator#finalize + * (javax.persistence.criteria.Predicate, + * org.springframework.data.domain.Sort, + * javax.persistence.criteria.CriteriaQuery, + * javax.persistence.criteria.CriteriaBuilder) + */ + @Override + protected CriteriaQuery finalize(Predicate predicate, Sort sort, + CriteriaQuery query, CriteriaBuilder builder) { + + return query.select(builder.count(query.from(domainClass))); + } +} diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java new file mode 100644 index 000000000..eaeeefc4c --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryCreator.java @@ -0,0 +1,209 @@ +package org.springframework.data.jpa.repository.query; + +import javax.persistence.EntityManager; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +import org.springframework.data.domain.Sort; +import org.springframework.data.repository.query.SimpleParameterAccessor; +import org.springframework.data.repository.query.SimpleParameterAccessor.BindableParameterIterator; +import org.springframework.data.repository.query.parser.AbstractQueryCreator; +import org.springframework.data.repository.query.parser.Part; +import org.springframework.data.repository.query.parser.PartTree; +import org.springframework.util.Assert; + + +/** + * Query creator to create a {@link CriteriaQuery} from a {@link PartTree}. + * + * @author Oliver Gierke + */ +public class JpaQueryCreator extends + AbstractQueryCreator, Predicate> { + + private final CriteriaBuilder builder; + private final Root root; + private final CriteriaQuery query; + + + /** + * Create a new {@link JpaQueryCreator}. + * + * @param tree + * @param parameters + * @param domainClass + * @param em + */ + public JpaQueryCreator(PartTree tree, SimpleParameterAccessor parameters, + Class domainClass, EntityManager em) { + + super(tree, parameters); + + this.builder = em.getCriteriaBuilder(); + this.query = builder.createQuery(); + this.root = query.from(domainClass); + } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.repository.query.parser.AbstractQueryCreator + * #create(org.springframework.data.repository.query.parser.Part, + * org.springframework + * .data.repository.query.SimpleParameterAccessor.BindableParameterIterator) + */ + @Override + protected Predicate create(Part part, BindableParameterIterator iterator) { + + return toPredicate(part, root, iterator); + } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.repository.query.parser.AbstractQueryCreator + * #and(org.springframework.data.repository.query.parser.Part, + * java.lang.Object, + * org.springframework.data.repository.query.SimpleParameterAccessor + * .BindableParameterIterator) + */ + @Override + protected Predicate and(Part part, Predicate base, + BindableParameterIterator iterator) { + + return builder.and(base, toPredicate(part, root, iterator)); + } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.repository.query.parser.AbstractQueryCreator + * #or(java.lang.Object, java.lang.Object) + */ + @Override + protected Predicate or(Predicate base, Predicate predicate) { + + return builder.or(base, predicate); + } + + + /** + * Finalizes the given {@link Predicate} and applies the given sort. + * Delegates to + * {@link #finalize(Predicate, Sort, CriteriaQuery, CriteriaBuilder)} and + * hands it the current {@link CriteriaQuery} and {@link CriteriaBuilder}. + */ + @Override + protected final CriteriaQuery finalize(Predicate predicate, + Sort sort) { + + return finalize(predicate, sort, query, builder); + } + + + /** + * Template method to finalize the given {@link Predicate} using the given + * {@link CriteriaQuery} and {@link CriteriaBuilder}. + * + * @param predicate + * @param sort + * @param query + * @param builder + * @return + */ + protected CriteriaQuery finalize(Predicate predicate, Sort sort, + CriteriaQuery query, CriteriaBuilder builder) { + + return this.query.select(root).where(predicate) + .orderBy(QueryUtils.toOrders(sort, root, builder)); + } + + + /** + * Creates a {@link Predicate} from the given {@link Part}. + * + * @param part + * @param root + * @param iterator + * @return + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + private Predicate toPredicate(Part part, Root root, + BindableParameterIterator iterator) { + + Expression path = root.get(part.getProperty()); + + switch (part.getType()) { + + case BETWEEN: + return builder.between(root. get(part.getProperty()), + nextAsComparable(iterator), nextAsComparable(iterator)); + case GREATER_THAN: + return builder.greaterThan(getComparablePath(root, part), + nextAsComparable(iterator)); + case LESS_THAN: + return builder.lessThan(getComparablePath(root, part), + nextAsComparable(iterator)); + case IS_NULL: + return root.isNull(); + case IS_NOT_NULL: + return root.isNotNull(); + case LIKE: + return builder.like(root. get(part.getProperty()), iterator + .next().toString()); + case NOT_LIKE: + return builder.not(builder.like(root. get(part + .getProperty()), iterator.next().toString())); + case SIMPLE_PROPERTY: + return builder.equal(path, iterator.next()); + case NEGATING_SIMPLE_PROPERTY: + return builder.notEqual(path, iterator.next()); + default: + throw new IllegalArgumentException("Unsupported keyword + " + + part.getType()); + } + } + + + /** + * Returns a path to a {@link Comparable}. + * + * @param root + * @param part + * @return + */ + @SuppressWarnings("rawtypes") + private Expression getComparablePath(Root root, + Part part) { + + return root.get(part.getProperty()); + } + + + /** + * Returns the next parameter from the given + * {@link BindableParameterIterator} and expects it to be a + * {@link Comparable}. + * + * @param iterator + * @return + */ + @SuppressWarnings("rawtypes") + private Comparable nextAsComparable(BindableParameterIterator iterator) { + + Object next = iterator.next(); + Assert.isInstanceOf(Comparable.class, next, + "Parameter has to implement Comparable to be bound correctly!"); + + return (Comparable) next; + } +} diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java index edc88aea2..336ed8c2e 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java @@ -24,6 +24,7 @@ import javax.persistence.Query; import org.springframework.data.domain.PageImpl; import org.springframework.data.repository.query.Parameters; import org.springframework.data.repository.query.QueryMethod; +import org.springframework.data.repository.query.SimpleParameterAccessor; import org.springframework.util.Assert; @@ -44,7 +45,8 @@ public abstract class JpaQueryExecution { * @return */ - public Object execute(AbstractJpaQuery query, ParameterBinder binder) { + public Object execute(AbstractStringBasedJpaQuery query, + ParameterBinder binder) { Assert.notNull(query); Assert.notNull(binder); @@ -57,6 +59,19 @@ public abstract class JpaQueryExecution { } + public Object execute(PartTreeJpaQuery query, Object[] parameters) { + + Assert.notNull(query); + Assert.notNull(parameters); + + try { + return doExecute(query, parameters); + } catch (NoResultException e) { + return null; + } + } + + /** * Method to implement {@link AbstractHadesQuery} executions by single enum * values. @@ -65,8 +80,12 @@ public abstract class JpaQueryExecution { * @param binder * @return */ - protected abstract Object doExecute(AbstractJpaQuery query, - ParameterBinder binder); + protected abstract Object doExecute(AbstractStringBasedJpaQuery query, + ParameterBinder parameters); + + + protected abstract Object doExecute(PartTreeJpaQuery query, + Object[] parameters); /** * Executes the {@link HadesQuery} to return a simple collection of @@ -75,12 +94,26 @@ public abstract class JpaQueryExecution { static class CollectionExecution extends JpaQueryExecution { @Override - protected Object doExecute(AbstractJpaQuery query, + protected Object doExecute(AbstractStringBasedJpaQuery query, ParameterBinder binder) { return binder.bindAndPrepare(query.createQuery(binder)) .getResultList(); } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.jpa.repository.query.JpaQueryExecution#doExecute + * (org.springframework.data.jpa.repository.query.DerivedJpaQuery) + */ + @Override + protected Object doExecute(PartTreeJpaQuery query, Object[] parameters) { + + return query.createQuery(parameters).getResultList(); + } } /** @@ -89,13 +122,23 @@ 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(AbstractJpaQuery repositoryQuery, + protected Object doExecute(AbstractStringBasedJpaQuery repositoryQuery, ParameterBinder binder) { // Execute query to compute total - Query projection = binder.bind(repositoryQuery.createCountQuery()); + Query projection = + binder.bind(repositoryQuery.createCountQuery(binder)); Long total = (Long) projection.getSingleResult(); Query query = @@ -104,6 +147,30 @@ public abstract class JpaQueryExecution { return new PageImpl(query.getResultList(), binder.getPageable(), total); } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.jpa.repository.query.JpaQueryExecution#doExecute + * (org.springframework.data.jpa.repository.query.DerivedJpaQuery, + * java.lang.Object[]) + */ + @Override + @SuppressWarnings("unchecked") + protected Object doExecute(PartTreeJpaQuery query, Object[] parameters) { + + SimpleParameterAccessor accessor = + new SimpleParameterAccessor(this.parameters, parameters); + + Query countQuery = query.createCountQuery(parameters); + Long total = (Long) countQuery.getSingleResult(); + + Query jpaQuery = query.createQuery(parameters); + return new PageImpl(jpaQuery.getResultList(), + accessor.getPageable(), total); + } } /** @@ -112,11 +179,26 @@ public abstract class JpaQueryExecution { static class SingleEntityExecution extends JpaQueryExecution { @Override - protected Object doExecute(AbstractJpaQuery query, + protected Object doExecute(AbstractStringBasedJpaQuery query, ParameterBinder binder) { return binder.bind(query.createQuery(binder)).getSingleResult(); } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.jpa.repository.query.JpaQueryExecution#doExecute + * (org.springframework.data.jpa.repository.query.DerivedJpaQuery, + * java.lang.Object[]) + */ + @Override + protected Object doExecute(PartTreeJpaQuery query, Object[] parameters) { + + return query.createQuery(parameters).getSingleResult(); + } } /** @@ -158,7 +240,7 @@ public abstract class JpaQueryExecution { * org.springframework.data.repository.query.ParameterBinder) */ @Override - protected Object doExecute(AbstractJpaQuery query, + protected Object doExecute(AbstractStringBasedJpaQuery query, ParameterBinder binder) { int result = binder.bind(query.createQuery(binder)).executeUpdate(); @@ -169,5 +251,12 @@ public abstract class JpaQueryExecution { return result; } + + + @Override + protected Object doExecute(PartTreeJpaQuery query, Object[] parameters) { + + throw new UnsupportedOperationException(); + } } } \ No newline at end of file diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java index 8757a7617..b32e5804b 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategy.java @@ -90,7 +90,7 @@ public class JpaQueryLookupStrategy { protected RepositoryQuery resolveQuery(JpaQueryMethod method, EntityManager em) { - return SimpleJpaQuery.construct(method, em); + return new PartTreeJpaQuery(method, em); } } diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java index 4d83bcf26..2d9f221a4 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java @@ -81,7 +81,7 @@ public class JpaQueryMethod extends QueryMethod { } if (isPageQuery()) { - return new PagedExecution(); + return new PagedExecution(getParameters()); } if (isModifyingQuery()) { diff --git a/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java index e4508cb1b..1c64e467f 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/NamedQuery.java @@ -32,7 +32,7 @@ import org.springframework.data.repository.query.RepositoryQuery; * * @author Oliver Gierke */ -final class NamedQuery extends AbstractJpaQuery { +final class NamedQuery extends AbstractStringBasedJpaQuery { private static final Logger LOG = LoggerFactory.getLogger(NamedQuery.class); @@ -121,9 +121,9 @@ final class NamedQuery extends AbstractJpaQuery { * .EntityManager, org.synyx.hades.dao.query.ParameterBinder) */ @Override - protected Query createQuery(EntityManager em, ParameterBinder binder) { + protected Query createQuery(ParameterBinder binder) { - return em.createNamedQuery(queryName); + return getEntityManager().createNamedQuery(queryName); } @@ -134,11 +134,12 @@ final class NamedQuery extends AbstractJpaQuery { * persistence.EntityManager) */ @Override - protected Query createCountQuery(EntityManager em) { + protected Query createCountQuery(ParameterBinder binder) { - Query query = createQuery(em, null); + Query query = createQuery(binder); String queryString = extractor.extractQueryString(query); - return em.createQuery(QueryUtils.createCountQueryFor(queryString)); + return getEntityManager().createQuery( + QueryUtils.createCountQueryFor(queryString)); } } \ No newline at end of file diff --git a/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java b/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java index b5c553ab6..eddf243ac 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/ParameterBinder.java @@ -118,7 +118,7 @@ public class ParameterBinder { if (hasNamedParameter(query) && parameter.isNamedParameter()) { query.setParameter(parameter.getName(), value); } else { - query.setParameter(parameter.getParameterPosition(), value); + query.setParameter(parameter.getIndex() + 1, value); } } diff --git a/src/main/java/org/springframework/data/jpa/repository/query/PartTreeJpaQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/PartTreeJpaQuery.java new file mode 100644 index 000000000..301eeef67 --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/repository/query/PartTreeJpaQuery.java @@ -0,0 +1,85 @@ +package org.springframework.data.jpa.repository.query; + +import javax.persistence.EntityManager; +import javax.persistence.Query; +import javax.persistence.criteria.CriteriaQuery; + +import org.springframework.data.repository.query.SimpleParameterAccessor; +import org.springframework.data.repository.query.parser.PartTree; + + +/** + * A {@link AbstractJpaQuery} implementation based on a {@link PartTree}. + * + * @author Oliver Gierke + */ +public class PartTreeJpaQuery extends AbstractJpaQuery { + + private final PartTree tree; + private final Class domainClass; + + + /** + * Creates a new {@link PartTreeJpaQuery}. + * + * @param method + * @param em + */ + public PartTreeJpaQuery(JpaQueryMethod method, EntityManager em) { + + super(method, em); + + this.tree = new PartTree(method.getName(), method.getDomainClass()); + this.domainClass = method.getDomainClass(); + } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.jpa.repository.query.AbstractJpaQuery#createQuery + * (javax.persistence.EntityManager, + * org.springframework.data.jpa.repository.query.ParameterBinder) + */ + public Query createQuery(Object[] parameters) { + + JpaQueryCreator jpaQueryCreator = + new JpaQueryCreator(tree, new SimpleParameterAccessor( + getParameters(), parameters), domainClass, + getEntityManager()); + + return getEntityManager().createQuery(jpaQueryCreator.createQuery()); + } + + + /* + * (non-Javadoc) + * + * @see org.springframework.data.jpa.repository.query.AbstractJpaQuery# + * createCountQuery(javax.persistence.EntityManager) + */ + public Query createCountQuery(Object[] parameters) { + + CriteriaQuery createQuery = + new JpaCountQueryCreator(tree, new SimpleParameterAccessor( + getParameters(), parameters), domainClass, + getEntityManager()).createQuery(); + return getEntityManager().createQuery(createQuery); + } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.jpa.repository.query.AbstractJpaQuery#doExecute + * (org.springframework.data.jpa.repository.query.JpaQueryExecution, + * java.lang.Object[]) + */ + @Override + protected Object doExecute(JpaQueryExecution execution, Object[] parameters) { + + return execution.execute(this, parameters); + } +} diff --git a/src/main/java/org/springframework/data/jpa/repository/query/QueryCreator.java b/src/main/java/org/springframework/data/jpa/repository/query/QueryCreator.java deleted file mode 100644 index ec2e139a5..000000000 --- a/src/main/java/org/springframework/data/jpa/repository/query/QueryCreator.java +++ /dev/null @@ -1,166 +0,0 @@ -/* - * Copyright 2008-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.jpa.repository.query; - -import static org.springframework.data.jpa.repository.query.QueryUtils.*; - -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.data.domain.Sort.Order; -import org.springframework.data.jpa.repository.utils.JpaClassUtils; -import org.springframework.data.repository.query.Parameter; -import org.springframework.data.repository.query.ParameterOutOfBoundsException; -import org.springframework.data.repository.query.Parameters; -import org.springframework.data.repository.query.QueryCreationException; -import org.springframework.data.repository.query.QueryMethod; -import org.springframework.data.repository.query.parser.OrderBySource; -import org.springframework.data.repository.query.parser.PartSource; -import org.springframework.util.Assert; -import org.springframework.util.StringUtils; - - -/** - * Class to encapsulate query creation logic for {@link QueryMethod}s. - * - * @author Oliver Gierke - */ -class QueryCreator { - - private static final Logger LOG = LoggerFactory - .getLogger(QueryCreator.class); - private static final String INVALID_PARAMETER_SIZE = - "You have to provide method arguments for each query " - + "criteria to construct the query correctly!"; - private static final String AND = "And"; - private static final String OR = "Or"; - - private JpaQueryMethod method; - - - /** - * Creates a new {@link QueryCreator} for the given {@link QueryMethod}. - * - * @param queryMethod - */ - public QueryCreator(JpaQueryMethod queryMethod) { - - Assert.isTrue(!queryMethod.isModifyingQuery()); - this.method = queryMethod; - } - - - /** - * Constructs a query from the underlying {@link QueryMethod}. - * - * @return the query string - * @throws QueryCreationException in case the query can't be created - */ - public String constructQuery() { - - StringBuilder queryBuilder = new StringBuilder(); - - Parameters parameters = method.getParameters().getBindableParameters(); - String methodName = method.getName(); - Class domainClass = method.getDomainClass(); - - try { - int parametersBound = - doCreateQuery(new PartSource(methodName), domainClass, - queryBuilder, parameters); - - if (!method.isCorrectNumberOfParameters(parametersBound)) { - throw QueryCreationException.create(method, - INVALID_PARAMETER_SIZE); - } - } catch (ParameterOutOfBoundsException e) { - throw QueryCreationException.create(method, e); - } - - String query = queryBuilder.toString(); - - LOG.debug("Created query '%s' from method %s", query, method.getName()); - - return query; - } - - - private int doCreateQuery(PartSource source, Class domainClass, - StringBuilder builder, Parameters parameters) { - - builder.append(getQueryString(READ_ALL_QUERY, - JpaClassUtils.getEntityName(domainClass))); - builder.append(" where "); - - Iterator orParts = source.getParts(OR); - int parametersBound = 0; - - while (orParts.hasNext()) { - - Iterator andParts = orParts.next().getParts(AND); - - while (andParts.hasNext()) { - PartSource andPart = andParts.next(); - - JpaQueryPart part = - new JpaQueryPart(andPart.cleanedUp(), domainClass); - Parameter parameter = - part.getParameterRequired() ? parameters - .getParameter(parametersBound) : null; - - builder.append(part.getQueryPart(parameter)); - - if (andParts.hasNext()) { - builder.append(" and "); - } - parametersBound += part.getNumberOfArguments(); - } - - if (orParts.hasNext()) { - builder.append(" or "); - } - } - - if (source.hasOrderByClause()) { - builder.append(" ").append(getClause(source.getOrderBySource())); - } - - return parametersBound; - } - - - /** - * Returns the final JPA order by clause. - * - * @return - */ - public String getClause(OrderBySource source) { - - List parts = new ArrayList(); - - for (Order order : source.toSort()) { - parts.add(String.format("x.%s %s", order.getProperty(), - QueryUtils.toJpaDirection(order))); - - } - - return "order by " - + StringUtils.collectionToDelimitedString(parts, ", "); - } -} diff --git a/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java b/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java index b9adc32df..e53c95073 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/QueryUtils.java @@ -18,7 +18,9 @@ package org.springframework.data.jpa.repository.query; import static java.util.regex.Pattern.*; import static org.springframework.data.jpa.repository.utils.JpaClassUtils.*; +import java.util.ArrayList; import java.util.Iterator; +import java.util.List; import java.util.Locale; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -26,6 +28,9 @@ import java.util.regex.Pattern; import javax.persistence.EntityManager; import javax.persistence.Parameter; import javax.persistence.Query; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Root; import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort.Order; @@ -107,7 +112,7 @@ public abstract class QueryUtils { * @param clazzName * @return */ - public static String getQueryString(String template, String clazzName) { + private static String getQueryString(String template, String clazzName) { Assert.hasText(clazzName, "Classname must not be null or empty!"); @@ -265,4 +270,48 @@ public abstract class QueryUtils { return false; } + + + /** + * Turns the given {@link Sort} into + * {@link javax.persistence.criteria.Order}s. + * + * @param sort + * @param root + * @param cb + * @return + */ + public static List toOrders(Sort sort, + Root root, CriteriaBuilder cb) { + + List orders = + new ArrayList(); + + if (sort == null) { + return orders; + } + + for (org.springframework.data.domain.Sort.Order order : sort) { + orders.add(toJpaOrder(order, root, cb)); + } + + return orders; + } + + + /** + * Creates a criteria API {@link javax.persistence.criteria.Order} from the + * given {@link Order}. + * + * @param order + * @param root + * @param cb + * @return + */ + private static javax.persistence.criteria.Order toJpaOrder(Order order, + Root root, CriteriaBuilder cb) { + + Expression expression = root.get(order.getProperty()); + return order.isAscending() ? cb.asc(expression) : cb.desc(expression); + } } diff --git a/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java index f7e1eddc5..e1295f445 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/SimpleJpaQuery.java @@ -23,7 +23,6 @@ import javax.persistence.QueryHint; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.data.repository.query.QueryCreationException; import org.springframework.data.repository.query.QueryMethod; import org.springframework.data.repository.query.RepositoryQuery; @@ -35,7 +34,7 @@ import org.springframework.data.repository.query.RepositoryQuery; * * @author Oliver Gierke */ -final class SimpleJpaQuery extends AbstractJpaQuery { +final class SimpleJpaQuery extends AbstractStringBasedJpaQuery { private static final Logger LOG = LoggerFactory .getLogger(SimpleJpaQuery.class); @@ -63,19 +62,6 @@ final class SimpleJpaQuery extends AbstractJpaQuery { } - /** - * Creates a new {@link SimpleJpaQuery} that constructs the query from the - * given {@link QueryMethod}. - * - * @param method - * @param em - */ - SimpleJpaQuery(JpaQueryMethod method, EntityManager em) { - - this(method, em, new QueryCreator(method).constructQuery()); - } - - /* * (non-Javadoc) * @@ -84,25 +70,27 @@ final class SimpleJpaQuery extends AbstractJpaQuery { * .EntityManager, org.synyx.hades.dao.query.ParameterBinder) */ @Override - protected Query createQuery(EntityManager em, ParameterBinder binder) { + public Query createQuery(ParameterBinder binder) { String query = QueryUtils.applySorting(queryString, binder.getSort(), alias); - return applyHints(em.createQuery(query)); + return applyHints(getEntityManager().createQuery(query)); } /* * (non-Javadoc) * - * @see org.synyx.hades.dao.query.AbstractHadesQuery#createCountQuery(javax. - * persistence.EntityManager) + * @see + * org.springframework.data.jpa.repository.query.AbstractStringBasedJpaQuery + * #createCountQuery(org.springframework.data.jpa.repository.query. + * ParameterBinder) */ @Override - protected Query createCountQuery(EntityManager em) { + protected Query createCountQuery(ParameterBinder binder) { - return applyHints(em.createQuery(countQuery)); + return applyHints(getEntityManager().createQuery(countQuery)); } @@ -138,30 +126,7 @@ final class SimpleJpaQuery extends AbstractJpaQuery { String query = queryMethod.getAnnotatedQuery(); - return query == null ? null : new SimpleJpaQuery(queryMethod, em, - query); - } - - - /** - * Constructs a {@link HadesQuery} from the given {@link QueryMethod}. - * - * @param queryMethod - * @param em - * @return - */ - public static RepositoryQuery construct(JpaQueryMethod queryMethod, - EntityManager em) { - - if (queryMethod.isModifyingQuery()) { - throw QueryCreationException - .create(queryMethod, - "Cannot create query from method name " - + "for modifying query. Use @Query or @NamedQuery to " - + "declare the query to execute. Do not use CREATE as " - + "strategy to lookup queries!"); - } - - return new SimpleJpaQuery(queryMethod, em); + return query == null ? null + : new SimpleJpaQuery(queryMethod, em, query); } } \ No newline at end of file diff --git a/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java b/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java index 59ffc2e44..a513eb44b 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/SimpleJpaRepository.java @@ -26,8 +26,6 @@ import javax.persistence.EntityManager; import javax.persistence.TypedQuery; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaQuery; -import javax.persistence.criteria.Expression; -import javax.persistence.criteria.Order; import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Root; @@ -464,28 +462,4 @@ public class SimpleJpaRepository extends return root; } - - - private List toOrders(Sort sort, Root root, CriteriaBuilder cb) { - - List orders = new ArrayList(); - - if (sort == null) { - return orders; - } - - for (org.springframework.data.domain.Sort.Order order : sort) { - orders.add(toJpaOrder(order, root, cb)); - } - - return orders; - } - - - private Order toJpaOrder(org.springframework.data.domain.Sort.Order order, - Root root, CriteriaBuilder cb) { - - Expression expression = root.get(order.getProperty()); - return order.isAscending() ? cb.asc(expression) : cb.desc(expression); - } } diff --git a/src/test/java/org/springframework/data/jpa/repository/OpenJpaNamespaceUserDaoTests.java b/src/test/java/org/springframework/data/jpa/repository/OpenJpaNamespaceUserDaoTests.java index 46cb33c6b..67509b35f 100644 --- a/src/test/java/org/springframework/data/jpa/repository/OpenJpaNamespaceUserDaoTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/OpenJpaNamespaceUserDaoTests.java @@ -25,7 +25,6 @@ import org.springframework.test.context.ContextConfiguration; * @author Oliver Gierke */ @ContextConfiguration(value = "classpath:openjpa.xml", inheritLocations = true) -public class OpenJpaNamespaceUserDaoTests extends - NamespaceUserRepositoryTests { +public class OpenJpaNamespaceUserDaoTests extends NamespaceUserRepositoryTests { } \ No newline at end of file diff --git a/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java b/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java index 04ed08504..a90869189 100644 --- a/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java @@ -255,8 +255,9 @@ public class UserRepositoryTests { flushTestUsers(); repository.renameAllUsersTo("newLastname"); - assertEquals(repository.count().intValue(), - repository.findByLastname("newLastname").size()); + Integer expected = repository.count().intValue(); + assertThat(repository.findByLastname("newLastname").size(), + is(expected)); } @@ -546,8 +547,10 @@ public class UserRepositoryTests { firstUser = repository.save(firstUser); secondUser = repository.save(secondUser); - assertTrue(repository.findByFirstnameOrLastname("Oliver", "Arrasz") - .containsAll(Arrays.asList(firstUser, secondUser))); + List result = + repository.findByFirstnameOrLastname("Oliver", "Arrasz"); + assertThat(result.size(), is(2)); + assertThat(result, hasItems(firstUser, secondUser)); } diff --git a/src/test/java/org/springframework/data/jpa/repository/config/RepositoryAutoConfigTests.java b/src/test/java/org/springframework/data/jpa/repository/config/RepositoryAutoConfigTests.java index 412fdf8a6..3733e3ba5 100644 --- a/src/test/java/org/springframework/data/jpa/repository/config/RepositoryAutoConfigTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/config/RepositoryAutoConfigTests.java @@ -25,6 +25,5 @@ import org.springframework.test.context.ContextConfiguration; * @author Oliver Gierke */ @ContextConfiguration(locations = "classpath:config/namespace-autoconfig-context.xml") -public class RepositoryAutoConfigTests extends - AbstractRepositoryConfigTests { +public class RepositoryAutoConfigTests extends AbstractRepositoryConfigTests { } diff --git a/src/test/java/org/springframework/data/jpa/repository/config/TypeFilterConfigTest.java b/src/test/java/org/springframework/data/jpa/repository/config/TypeFilterConfigTest.java index 23d7d1c69..3b5f1cd3c 100644 --- a/src/test/java/org/springframework/data/jpa/repository/config/TypeFilterConfigTest.java +++ b/src/test/java/org/springframework/data/jpa/repository/config/TypeFilterConfigTest.java @@ -28,8 +28,7 @@ import org.springframework.test.context.ContextConfiguration; * @author Oliver Gierke */ @ContextConfiguration(locations = "classpath:config/namespace-autoconfig-typefilter-context.xml") -public class TypeFilterConfigTest extends - AbstractRepositoryConfigTests { +public class TypeFilterConfigTest extends AbstractRepositoryConfigTests { /* * (non-Javadoc) diff --git a/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactory.java b/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactory.java index b08c55e1c..a81fa4349 100644 --- a/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactory.java +++ b/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericJpaRepositoryFactory.java @@ -25,13 +25,12 @@ import org.springframework.data.repository.support.RepositorySupport; /** - * Sample implementation of a custom {@link JpaRepositoryFactory} to use - * a custom repository base class. + * Sample implementation of a custom {@link JpaRepositoryFactory} to use a + * custom repository base class. * * @author Oliver Gierke */ -public class CustomGenericJpaRepositoryFactory extends - JpaRepositoryFactory { +public class CustomGenericJpaRepositoryFactory extends JpaRepositoryFactory { /** * @param entityManager diff --git a/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericRepository.java b/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericRepository.java index 7f523b7d1..c92ef39d5 100644 --- a/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericRepository.java +++ b/src/test/java/org/springframework/data/jpa/repository/custom/CustomGenericRepository.java @@ -24,10 +24,10 @@ import org.springframework.data.repository.NoRepositoryBean; /** - * Extension of {@link Repository} to be added on a custom repository - * base class. This tests the facility to implement custom base class - * functionality for all repository instances derived from this interface and - * implementation base class. + * Extension of {@link Repository} to be added on a custom repository base + * class. This tests the facility to implement custom base class functionality + * for all repository instances derived from this interface and implementation + * base class. * * @author Oliver Gierke */ diff --git a/src/test/java/org/springframework/data/jpa/repository/custom/UserCustomExtendedRepository.java b/src/test/java/org/springframework/data/jpa/repository/custom/UserCustomExtendedRepository.java index 8bd4fa0b4..8042e2de8 100644 --- a/src/test/java/org/springframework/data/jpa/repository/custom/UserCustomExtendedRepository.java +++ b/src/test/java/org/springframework/data/jpa/repository/custom/UserCustomExtendedRepository.java @@ -19,13 +19,13 @@ package org.springframework.data.jpa.repository.custom; import org.springframework.data.jpa.domain.sample.User; - /** * Custom Extended DAO interface for a {@code User}. This relies on the custom * intermediate DAO interface {@link CustomGenericRepository}. * * @author Oliver Gierke */ -public interface UserCustomExtendedRepository extends CustomGenericRepository { +public interface UserCustomExtendedRepository extends + CustomGenericRepository { } \ No newline at end of file diff --git a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java index 2cc586491..0589103ca 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java @@ -45,7 +45,7 @@ public class JpaQueryExecutionUnitTests { @Mock EntityManager em; @Mock - AbstractJpaQuery jpaQuery; + AbstractStringBasedJpaQuery jpaQuery; @Mock ParameterBinder binder; @Mock @@ -81,11 +81,28 @@ public class JpaQueryExecutionUnitTests { assertThat(new JpaQueryExecution() { @Override - protected Object doExecute(AbstractJpaQuery query, + protected Object doExecute(AbstractStringBasedJpaQuery query, ParameterBinder binder) { throw new NoResultException(); } + + + /* + * (non-Javadoc) + * + * @see + * org.springframework.data.jpa.repository.query.JpaQueryExecution + * #doExecute + * (org.springframework.data.jpa.repository.query.PartTreeJpaQuery, + * java.lang.Object[]) + */ + @Override + protected Object doExecute(PartTreeJpaQuery query, + Object[] parameters) { + + return null; + } }.execute(jpaQuery, binder), is(nullValue())); } @@ -123,11 +140,18 @@ public class JpaQueryExecutionUnitTests { static class StubQueryExecution extends JpaQueryExecution { @Override - protected Object doExecute(AbstractJpaQuery query, + protected Object doExecute(AbstractStringBasedJpaQuery query, ParameterBinder binder) { return null; } + + + @Override + protected Object doExecute(PartTreeJpaQuery query, Object[] parameters) { + + return null; + } } static interface Dummy { diff --git a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java index 2942ac3bb..bdb67e22e 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryMethodUnitTests.java @@ -57,7 +57,7 @@ public class JpaQueryMethodUnitTests { EntityManager em; Method daoMethod, invalidReturnType, pageableAndSort, pageableTwice, - sortableTwice, modifyingMethod; + sortableTwice, modifyingMethod; /** @@ -67,24 +67,24 @@ public class JpaQueryMethodUnitTests { public void setUp() throws Exception { daoMethod = - UserRepository.class.getMethod("findByLastname", String.class); + UserRepository.class.getMethod("findByLastname", String.class); invalidReturnType = - InvalidDao.class.getMethod(METHOD_NAME, String.class, - Pageable.class); + InvalidDao.class.getMethod(METHOD_NAME, String.class, + Pageable.class); pageableAndSort = - InvalidDao.class.getMethod(METHOD_NAME, String.class, - Pageable.class, Sort.class); + InvalidDao.class.getMethod(METHOD_NAME, String.class, + Pageable.class, Sort.class); pageableTwice = - InvalidDao.class.getMethod(METHOD_NAME, String.class, - Pageable.class, Pageable.class); + InvalidDao.class.getMethod(METHOD_NAME, String.class, + Pageable.class, Pageable.class); sortableTwice = - InvalidDao.class.getMethod(METHOD_NAME, String.class, - Sort.class, Sort.class); + InvalidDao.class.getMethod(METHOD_NAME, String.class, + Sort.class, Sort.class); modifyingMethod = - UserRepository.class - .getMethod("renameAllUsersTo", String.class); + UserRepository.class + .getMethod("renameAllUsersTo", String.class); } @@ -95,8 +95,6 @@ public class JpaQueryMethodUnitTests { assertEquals("User.findByLastname", method.getNamedQueryName()); assertThat(method.getExecution(), is(CollectionExecution.class)); - assertEquals("select x from User x where x.lastname = ?1", - new QueryCreator(method).constructQuery()); } @@ -137,11 +135,11 @@ public class JpaQueryMethodUnitTests { assertNull(method.getAnnotatedQuery()); Method daoMethod = - UserRepository.class - .getMethod("findByHadesQuery", String.class); + UserRepository.class + .getMethod("findByHadesQuery", String.class); assertNotNull(new JpaQueryMethod(daoMethod, extractor, em) - .getAnnotatedQuery()); + .getAnnotatedQuery()); } @@ -192,11 +190,11 @@ public class JpaQueryMethodUnitTests { @Test(expected = IllegalArgumentException.class) public void rejectsPageablesOnPersistenceProvidersNotExtractingQueries() - throws Exception { + throws Exception { Method method = - UserRepository.class.getMethod("findByFirstname", - Pageable.class, String.class); + UserRepository.class.getMethod("findByFirstname", + Pageable.class, String.class); when(extractor.canExtractQuery()).thenReturn(false); @@ -208,7 +206,7 @@ public class JpaQueryMethodUnitTests { public void recognizesModifyingMethod() { JpaQueryMethod method = - new JpaQueryMethod(modifyingMethod, extractor, em); + new JpaQueryMethod(modifyingMethod, extractor, em); assertTrue(method.isModifyingQuery()); } @@ -217,8 +215,8 @@ public class JpaQueryMethodUnitTests { public void rejectsModifyingMethodWithPageable() throws Exception { Method method = - InvalidDao.class.getMethod("updateMethod", String.class, - Pageable.class); + InvalidDao.class.getMethod("updateMethod", String.class, + Pageable.class); new JpaQueryMethod(method, extractor, em); } @@ -228,8 +226,8 @@ public class JpaQueryMethodUnitTests { public void rejectsModifyingMethodWithSort() throws Exception { Method method = - InvalidDao.class.getMethod("updateMethod", String.class, - Sort.class); + InvalidDao.class.getMethod("updateMethod", String.class, + Sort.class); new JpaQueryMethod(method, extractor, em); } diff --git a/src/test/java/org/springframework/data/jpa/repository/query/ParameterBinderUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/ParameterBinderUnitTests.java index 7c973380f..9510f52f4 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/ParameterBinderUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/ParameterBinderUnitTests.java @@ -22,6 +22,7 @@ import static org.mockito.Mockito.*; import java.lang.reflect.Method; +import javax.persistence.Embeddable; import javax.persistence.Query; import org.junit.Before; @@ -31,7 +32,6 @@ import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; -import org.springframework.data.jpa.repository.query.QueryCreatorUnitTests.SampleEmbeddable; import org.springframework.data.repository.query.Param; import org.springframework.data.repository.query.Parameters; @@ -183,8 +183,8 @@ public class ParameterBinderUnitTests { public void bindsEmbeddableCorrectly() throws Exception { Method method = - QueryCreatorUnitTests.class.getMethod("findByEmbeddable", - SampleEmbeddable.class); + getClass() + .getMethod("findByEmbeddable", SampleEmbeddable.class); Parameters parameters = new Parameters(method); SampleEmbeddable embeddable = new SampleEmbeddable(); @@ -204,4 +204,24 @@ public class ParameterBinderUnitTests { new Object[] { "name", sort }); assertThat(binder.getSort(), is(sort)); } + + + public SampleEntity findByEmbeddable(SampleEmbeddable embeddable) { + + return null; + } + + @SuppressWarnings("unused") + static class SampleEntity { + + private SampleEmbeddable embeddable; + } + + @Embeddable + @SuppressWarnings("unused") + static class SampleEmbeddable { + + private String foo; + private String bar; + } } diff --git a/src/test/java/org/springframework/data/jpa/repository/query/QueryCreatorUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/QueryCreatorUnitTests.java deleted file mode 100644 index 883c0e3ab..000000000 --- a/src/test/java/org/springframework/data/jpa/repository/query/QueryCreatorUnitTests.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright 2008-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.jpa.repository.query; - -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.*; - -import java.lang.reflect.Method; -import java.util.Date; - -import javax.persistence.Embeddable; -import javax.persistence.EntityManager; - -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; -import org.springframework.data.jpa.domain.sample.User; -import org.springframework.data.jpa.repository.query.JpaQueryMethodUnitTests.InvalidDao; -import org.springframework.data.repository.query.QueryCreationException; - - -/** - * Unit test for {@link QueryCreator}. - * - * @author Oliver Gierke - */ -@RunWith(MockitoJUnitRunner.class) -public class QueryCreatorUnitTests { - - private Method method; - - @Mock - QueryExtractor extractor; - @Mock - EntityManager em; - - - @Before - public void setup() throws SecurityException, NoSuchMethodException { - - method = - QueryCreatorUnitTests.class.getMethod( - "findByFirstnameAndMethod", String.class); - } - - - @Test(expected = QueryCreationException.class) - public void rejectsInvalidProperty() throws Exception { - - JpaQueryMethod finderMethod = new JpaQueryMethod(method, extractor, em); - new QueryCreator(finderMethod).constructQuery(); - } - - - @Test - public void splitsKeywordsCorrectly() throws SecurityException, - NoSuchMethodException { - - method = - QueryCreatorUnitTests.class.getMethod( - "findByNameOrOrganization", String.class, String.class); - - assertCreatesQueryForMethod( - "where x.name = :name or x.organization = :organization", - method); - } - - - /** - * @throws NoSuchMethodException - * @throws SecurityException - * @see #265 - * @throws Exception - */ - @Test - public void createsQueryWithEmbeddableCorrectly() throws SecurityException, - NoSuchMethodException { - - method = - getClass() - .getMethod("findByEmbeddable", SampleEmbeddable.class); - - assertCreatesQueryForMethod("where x.embeddable = :embeddable", method); - } - - - @Test - public void createsQueryWithBetweenKeywordCorrectly() throws Exception { - - method = - getClass().getMethod("findByStartDateBetweenAndName", - Date.class, Date.class, String.class); - - assertCreatesQueryForMethod( - "where x.startDate between :first and :second and x.name = :name", - method); - } - - - @Test - public void createsQueryWithLessThanKeywordCorrectly() throws Exception { - - method = getClass().getMethod("findByAgeLessThan", int.class); - - assertCreatesQueryForMethod("where x.age < :age", method); - } - - - @Test - public void createsQueryWithGreaterThanKeywordCorrectly() throws Exception { - - method = getClass().getMethod("findByAgeGreaterThan", int.class); - - assertCreatesQueryForMethod("where x.age > :age", method); - } - - - @Test(expected = IllegalArgumentException.class) - public void rejectsModifyingMethodWithoutBacking() - throws SecurityException, NoSuchMethodException { - - Method invalidModifyingMethod = - InvalidDao.class.getMethod("updateMethod", String.class); - - JpaQueryMethod method = - new JpaQueryMethod(invalidModifyingMethod, extractor, em); - - new QueryCreator(method); - } - - - @Test - public void parsesLikeOperatorCorrectly() throws Exception { - - method = getClass().getMethod("findByNameLike", String.class); - assertCreatesQueryForMethod("where x.name like :name", method); - } - - - @Test - public void parsesNotOperatorCorrectly() throws Exception { - - method = getClass().getMethod("findByNameNot", String.class); - assertCreatesQueryForMethod("where x.name <> :name", method); - } - - - @Test - public void parsesNotNullOperatorCorrectly() throws Exception { - - method = getClass().getMethod("findByNameNotNull"); - assertCreatesQueryForMethod("where x.name is not null", method); - } - - - @Test - public void parsesLikeCorrectly() throws Exception { - - method = getClass().getMethod("findByNameLike", String.class); - assertCreatesQueryForMethod("where x.name like :name", method); - } - - - @Test - public void parsesNotLikeCorrectly() throws Exception { - - method = getClass().getMethod("findByNameNotLike", String.class); - assertCreatesQueryForMethod("where x.name not like :name", method); - } - - - @Test - public void parsesOrderByClauseCorrectly() throws Exception { - - method = - getClass().getMethod("findByNameOrderByOrganizationDesc", - String.class); - assertCreatesQueryForMethod( - "where x.name = :name order by x.organization desc", method); - } - - - /** - * Asserts that the query created for the given {@link Method} results in a - * query ending with the given {@link String}. - * - * @param queryEnd - * @param method - */ - private void assertCreatesQueryForMethod(String queryEnd, Method method) { - - JpaQueryMethod queryMethod = new JpaQueryMethod(method, extractor, em); - String result = new QueryCreator(queryMethod).constructQuery(); - assertThat(result, endsWith(queryEnd)); - } - - - /** - * Sample method to test failing query creation. - * - * @param firstname - * @return - */ - public User findByFirstnameAndMethod(String firstname) { - - return null; - } - - - /** - * A method to check that query keyowrds are considered correctly. The - * {@link QueryCreator} must not detect the {@code Or} in - * {@code Organization} as keyword. - * - * @param name - * @param organization - * @return - */ - public SampleEntity findByNameOrOrganization(String name, - String organization) { - - return null; - } - - - /** - * Sample method to create a finder query for that references an - * {@link Embeddable}. - * - * @see #265 - * @param embeddable - * @return - */ - public SampleEntity findByEmbeddable(SampleEmbeddable embeddable) { - - return null; - } - - - public SampleEntity findByStartDateBetweenAndName(Date first, Date second, - String name) { - - return null; - } - - - public SampleEntity findByAgeLessThan(int age) { - - return null; - } - - - public SampleEntity findByAgeGreaterThan(int age) { - - return null; - } - - - public SampleEntity findByNameLike(String name) { - - return null; - } - - - public SampleEntity findByNameNotLike(String name) { - - return null; - } - - - public SampleEntity findByNameNot(String name) { - - return null; - } - - - public SampleEntity findByNameNotNull() { - - return null; - } - - - public SampleEntity findByNameOrderByOrganizationDesc(String name) { - - return null; - } - - /** - * Sample class for keyword split check. - * - * @author Oliver Gierke - */ - @SuppressWarnings("unused") - static class SampleEntity { - - private String organization; - private String name; - - private Date startDate; - private int age; - - private SampleEmbeddable embeddable; - } - - @Embeddable - @SuppressWarnings("unused") - static class SampleEmbeddable { - - private String foo; - private String bar; - } -} diff --git a/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java index b10e77a39..d51c4f8e6 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/SimpleJpaQueryUnitTests.java @@ -69,7 +69,7 @@ public class SimpleJpaQueryUnitTests { public void appliesHintsCorrectly() throws Exception { SimpleJpaQuery hadesQuery = new SimpleJpaQuery(method, em, "foobar"); - hadesQuery.createQuery(em, new ParameterBinder(method.getParameters(), + hadesQuery.createQuery(new ParameterBinder(method.getParameters(), new Object[] { "gierke" })); verify(query).setHint("foo", "bar"); @@ -86,6 +86,6 @@ public class SimpleJpaQueryUnitTests { SimpleJpaQuery hadesQuery = new SimpleJpaQuery(method, em, "select u from User u"); - assertThat(hadesQuery.createCountQuery(em), is(query)); + assertThat(hadesQuery.createCountQuery(null), is(query)); } } diff --git a/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanUnitTests.java index 1e82d532b..bb1c28a6e 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBeanUnitTests.java @@ -72,8 +72,8 @@ public class JpaRepositoryFactoryBeanUnitTests { // Setup standard factory configuration factory = - JpaRepositoryFactoryBean.create( - SimpleSampleRepository.class, entityManager); + JpaRepositoryFactoryBean.create(SimpleSampleRepository.class, + entityManager); factory.setEntityManager(entityManager); } @@ -139,8 +139,7 @@ public class JpaRepositoryFactoryBeanUnitTests { JpaRepositoryFactoryBean factory = - JpaRepositoryFactoryBean.create(SampleRepository.class, - entityManager); + JpaRepositoryFactoryBean.create(SampleRepository.class, entityManager); try { factory.afterPropertiesSet(); @@ -166,8 +165,8 @@ public class JpaRepositoryFactoryBeanUnitTests { void someSampleMethod(); } - private interface SampleRepository extends - JpaRepository, SampleCustomDao { + private interface SampleRepository extends JpaRepository, + SampleCustomDao { } } diff --git a/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryUnitTests.java index 6352c04ac..579a833a0 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryUnitTests.java @@ -131,8 +131,7 @@ public class JpaRepositoryFactoryUnitTests { dao.customMethod(1); } - private interface SimpleSampleDao extends - JpaRepository { + private interface SimpleSampleDao extends JpaRepository { @Transactional User readByPrimaryKey(Integer primaryKey);