From 4c1a1450b9561397bc7e986dcd936e4d4caec705 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Mon, 4 Jun 2012 16:33:58 +0200 Subject: [PATCH] DATAJPA-176 - Introduce Querydsl abstraction. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduced Querydsl helper class to allow using more functionality from QuerydslJpaRepository as well as QuerydslRepositorySupport. Moved applyPagination(…) and applySorting(…) methods into that helper class. Removed QuerydslUtils and moved functionality into Querydsl helper. This change breaks exposed API in Querydsl repo and repo support classes. --- .../support/QueryDslJpaRepository.java | 71 +-------- .../support/QueryDslRepositorySupport.java | 38 +++-- .../data/jpa/repository/support/Querydsl.java | 144 ++++++++++++++++++ .../jpa/repository/support/QuerydslUtils.java | 56 ------- ...yDslRepositorySupportIntegrationTests.java | 5 + .../QueryDslRepositorySupportTests.java | 4 + 6 files changed, 187 insertions(+), 131 deletions(-) create mode 100644 src/main/java/org/springframework/data/jpa/repository/support/Querydsl.java delete mode 100644 src/main/java/org/springframework/data/jpa/repository/support/QuerydslUtils.java diff --git a/src/main/java/org/springframework/data/jpa/repository/support/QueryDslJpaRepository.java b/src/main/java/org/springframework/data/jpa/repository/support/QueryDslJpaRepository.java index b25d0c5b2..0c36f096a 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/QueryDslJpaRepository.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/QueryDslJpaRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2011 the original author or authors. + * Copyright 2008-2012 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. @@ -23,15 +23,12 @@ import javax.persistence.EntityManager; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.domain.Sort.Order; import org.springframework.data.querydsl.EntityPathResolver; import org.springframework.data.querydsl.QueryDslPredicateExecutor; import org.springframework.data.querydsl.SimpleEntityPathResolver; import com.mysema.query.jpa.JPQLQuery; import com.mysema.query.types.EntityPath; -import com.mysema.query.types.Expression; import com.mysema.query.types.OrderSpecifier; import com.mysema.query.types.Predicate; import com.mysema.query.types.path.PathBuilder; @@ -47,10 +44,9 @@ public class QueryDslJpaRepository extends SimpleJpa private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE; - private final EntityManager em; private final EntityPath path; private final PathBuilder builder; - private final PersistenceProvider provider; + private final Querydsl querydsl; /** * Creates a new {@link QueryDslJpaRepository} from the given domain class and {@link EntityManager}. This will use @@ -60,7 +56,6 @@ public class QueryDslJpaRepository extends SimpleJpa * @param entityManager must not be {@literal null}. */ public QueryDslJpaRepository(JpaEntityInformation entityInformation, EntityManager entityManager) { - this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER); } @@ -76,10 +71,10 @@ public class QueryDslJpaRepository extends SimpleJpa EntityPathResolver resolver) { super(entityInformation, entityManager); - this.em = entityManager; + this.path = resolver.createPath(entityInformation.getJavaType()); this.builder = new PathBuilder(path.getType(), path.getMetadata()); - this.provider = PersistenceProvider.fromEntityManager(entityManager); + this.querydsl = new Querydsl(entityManager, builder); } /* @@ -113,7 +108,7 @@ public class QueryDslJpaRepository extends SimpleJpa public Page findAll(Predicate predicate, Pageable pageable) { JPQLQuery countQuery = createQuery(predicate); - JPQLQuery query = applyPagination(createQuery(predicate), pageable); + JPQLQuery query = querydsl.applyPagination(pageable, createQuery(predicate)); return new PageImpl(query.list(path), pageable, countQuery.count()); } @@ -133,60 +128,6 @@ public class QueryDslJpaRepository extends SimpleJpa * @return the Querydsl {@link JPQLQuery}. */ protected JPQLQuery createQuery(Predicate... predicate) { - return QuerydslUtils.createQueryInstance(em, provider).from(path).where(predicate); - } - - /** - * Applies the given {@link Pageable} to the given {@link JPQLQuery}. - * - * @param query must not be {@literal null}. - * @param pageable - * @return the Querydsl {@link JPQLQuery}. - */ - protected JPQLQuery applyPagination(JPQLQuery query, Pageable pageable) { - - if (pageable == null) { - return query; - } - - query.offset(pageable.getOffset()); - query.limit(pageable.getPageSize()); - - return applySorting(query, pageable.getSort()); - } - - /** - * Applies sorting to the given {@link JPQLQuery}. - * - * @param query must not be {@literal null}. - * @param sort - * @return the Querydsl {@link JPQLQuery} - */ - protected JPQLQuery applySorting(JPQLQuery query, Sort sort) { - - if (sort == null) { - return query; - } - - for (Order order : sort) { - query.orderBy(toOrder(order)); - } - - return query; - } - - /** - * Transforms a plain {@link Order} into a QueryDsl specific {@link OrderSpecifier}. - * - * @param order - * @return - */ - @SuppressWarnings({ "rawtypes", "unchecked" }) - protected OrderSpecifier toOrder(Order order) { - - Expression property = builder.get(order.getProperty()); - - return new OrderSpecifier(order.isAscending() ? com.mysema.query.types.Order.ASC - : com.mysema.query.types.Order.DESC, property); + return querydsl.createQuery(path).where(predicate); } } diff --git a/src/main/java/org/springframework/data/jpa/repository/support/QueryDslRepositorySupport.java b/src/main/java/org/springframework/data/jpa/repository/support/QueryDslRepositorySupport.java index 782e5139a..878bac417 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/QueryDslRepositorySupport.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/QueryDslRepositorySupport.java @@ -39,9 +39,20 @@ import com.mysema.query.types.path.PathBuilderFactory; @Repository public abstract class QueryDslRepositorySupport { - private PathBuilderFactory builderFactory = new PathBuilderFactory(); + private final PathBuilder builder; + private EntityManager entityManager; - private PersistenceProvider provider; + private Querydsl querydsl; + + /** + * Creates a new {@link QueryDslRepositorySupport} instance for the given domain type. + * + * @param domainClass must not be {@literal null}. + */ + public QueryDslRepositorySupport(Class domainClass) { + Assert.notNull(domainClass); + this.builder = new PathBuilderFactory().create(domainClass); + } /** * Setter to inject {@link EntityManager}. @@ -52,8 +63,8 @@ public abstract class QueryDslRepositorySupport { public void setEntityManager(EntityManager entityManager) { Assert.notNull(entityManager); + this.querydsl = new Querydsl(entityManager, builder); this.entityManager = entityManager; - this.provider = PersistenceProvider.fromEntityManager(entityManager); } /** @@ -62,6 +73,7 @@ public abstract class QueryDslRepositorySupport { @PostConstruct public void validate() { Assert.notNull(entityManager, "EntityManager must not be null!"); + Assert.notNull(querydsl, "Querydsl must not be null!"); } /** @@ -79,7 +91,7 @@ public abstract class QueryDslRepositorySupport { * @return the Querydsl {@link JPQLQuery}. */ protected JPQLQuery from(EntityPath... paths) { - return QuerydslUtils.createQueryInstance(entityManager, provider).from(paths); + return querydsl.createQuery(paths); } /** @@ -89,7 +101,6 @@ public abstract class QueryDslRepositorySupport { * @return the Querydsl {@link DeleteClause}. */ protected DeleteClause delete(EntityPath path) { - return new JPADeleteClause(entityManager, path); } @@ -100,19 +111,26 @@ public abstract class QueryDslRepositorySupport { * @return the Querydsl {@link UpdateClause}. */ protected UpdateClause update(EntityPath path) { - return new JPAUpdateClause(entityManager, path); } /** - * Returns a {@link PathBuilder} for the given type. + * Returns a {@link PathBuilder} for the configured domain type. * * @param - * @param type * @return the Querdsl {@link PathBuilder}. */ - protected PathBuilder getBuilder(Class type) { + @SuppressWarnings("unchecked") + protected PathBuilder getBuilder() { + return (PathBuilder) builder; + } - return builderFactory.create(type); + /** + * Returns the underlying Querydsl helper instance. + * + * @return + */ + protected Querydsl getQuerydsl() { + return this.querydsl; } } diff --git a/src/main/java/org/springframework/data/jpa/repository/support/Querydsl.java b/src/main/java/org/springframework/data/jpa/repository/support/Querydsl.java new file mode 100644 index 000000000..dea0f96b9 --- /dev/null +++ b/src/main/java/org/springframework/data/jpa/repository/support/Querydsl.java @@ -0,0 +1,144 @@ +/* + * Copyright 2012 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.support; + +import javax.persistence.EntityManager; + +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.domain.Sort.Order; +import org.springframework.util.Assert; + +import com.mysema.query.jpa.EclipseLinkTemplates; +import com.mysema.query.jpa.HQLTemplates; +import com.mysema.query.jpa.JPQLQuery; +import com.mysema.query.jpa.OpenJPATemplates; +import com.mysema.query.jpa.impl.JPAQuery; +import com.mysema.query.types.EntityPath; +import com.mysema.query.types.Expression; +import com.mysema.query.types.OrderSpecifier; +import com.mysema.query.types.path.PathBuilder; + +/** + * Helper instance to ease access to Querydsl JPA query API. + * + * @author Oliver Gierke + */ +public class Querydsl { + + private final EntityManager em; + private final PersistenceProvider provider; + private final PathBuilder builder; + + /** + * Creates a new {@link Querydsl} for the given {@link EntityManager} and {@link PathBuilder}. + * + * @param em must not be {@literal null}. + * @param builder must not be {@literal null}. + */ + public Querydsl(EntityManager em, PathBuilder builder) { + + Assert.notNull(em); + Assert.notNull(builder); + + this.em = em; + this.provider = PersistenceProvider.fromEntityManager(em); + this.builder = builder; + } + + /** + * Creates the {@link JPQLQuery} instance based on the configured {@link EntityManager}. + * + * @return + */ + public JPQLQuery createQuery() { + + switch (provider) { + case ECLIPSELINK: + return new JPAQuery(em, EclipseLinkTemplates.DEFAULT); + case HIBERNATE: + return new JPAQuery(em, HQLTemplates.DEFAULT); + case OPEN_JPA: + return new JPAQuery(em, OpenJPATemplates.DEFAULT); + case GENERIC_JPA: + default: + return new JPAQuery(em); + } + } + + /** + * Creates the {@link JPQLQuery} instance based on the configured {@link EntityManager}. + * + * @return + */ + public JPQLQuery createQuery(EntityPath... paths) { + return createQuery().from(paths); + } + + /** + * Applies the given {@link Pageable} to the given {@link JPQLQuery}. + * + * @param pageable + * @param query must not be {@literal null}. + * @return the Querydsl {@link JPQLQuery}. + */ + public JPQLQuery applyPagination(Pageable pageable, JPQLQuery query) { + + if (pageable == null) { + return query; + } + + query.offset(pageable.getOffset()); + query.limit(pageable.getPageSize()); + + return query; + } + + /** + * Applies sorting to the given {@link JPQLQuery}. + * + * @param sort + * @param query must not be {@literal null}. + * @return the Querydsl {@link JPQLQuery} + */ + public JPQLQuery applySorting(Sort sort, JPQLQuery query) { + + if (sort == null) { + return query; + } + + for (Order order : sort) { + query.orderBy(toOrder(order)); + } + + return query; + } + + /** + * Transforms a plain {@link Order} into a QueryDsl specific {@link OrderSpecifier}. + * + * @param order + * @return + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + private OrderSpecifier toOrder(Order order) { + + Expression property = builder.get(order.getProperty()); + + return new OrderSpecifier(order.isAscending() ? com.mysema.query.types.Order.ASC + : com.mysema.query.types.Order.DESC, property); + } +} diff --git a/src/main/java/org/springframework/data/jpa/repository/support/QuerydslUtils.java b/src/main/java/org/springframework/data/jpa/repository/support/QuerydslUtils.java deleted file mode 100644 index c3efe73f3..000000000 --- a/src/main/java/org/springframework/data/jpa/repository/support/QuerydslUtils.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2012 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.support; - -import javax.persistence.EntityManager; - -import com.mysema.query.jpa.EclipseLinkTemplates; -import com.mysema.query.jpa.HQLTemplates; -import com.mysema.query.jpa.JPQLQuery; -import com.mysema.query.jpa.OpenJPATemplates; -import com.mysema.query.jpa.impl.JPAQuery; - -/** - * Utility methods for Querydsl. - * - * @author Oliver Gierke - */ -class QuerydslUtils { - - private QuerydslUtils() { - - } - - /** - * Creates the {@link JPQLQuery} instance based on the given {@link EntityManager} and {@link PersistenceProvider}. - * - * @return - */ - public static JPQLQuery createQueryInstance(EntityManager em, PersistenceProvider provider) { - - switch (provider) { - case ECLIPSELINK: - return new JPAQuery(em, EclipseLinkTemplates.DEFAULT); - case HIBERNATE: - return new JPAQuery(em, HQLTemplates.DEFAULT); - case OPEN_JPA: - return new JPAQuery(em, OpenJPATemplates.DEFAULT); - case GENERIC_JPA: - default: - return new JPAQuery(em); - } - } -} diff --git a/src/test/java/org/springframework/data/jpa/repository/support/QueryDslRepositorySupportIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/support/QueryDslRepositorySupportIntegrationTests.java index 7d5db1b45..a34fc000b 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/QueryDslRepositorySupportIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/QueryDslRepositorySupportIntegrationTests.java @@ -24,6 +24,7 @@ import javax.persistence.PersistenceContext; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.jpa.domain.sample.User; import org.springframework.data.jpa.repository.support.QueryDslRepositorySupportTests.UserRepository; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; @@ -63,6 +64,10 @@ public class QueryDslRepositorySupportIntegrationTests { static class ReconfiguringUserRepositoryImpl extends QueryDslRepositorySupport { + public ReconfiguringUserRepositoryImpl() { + super(User.class); + } + @Override @PersistenceContext(unitName = "querydsl") public void setEntityManager(EntityManager entityManager) { diff --git a/src/test/java/org/springframework/data/jpa/repository/support/QueryDslRepositorySupportTests.java b/src/test/java/org/springframework/data/jpa/repository/support/QueryDslRepositorySupportTests.java index 48b5ba255..4aef7df47 100644 --- a/src/test/java/org/springframework/data/jpa/repository/support/QueryDslRepositorySupportTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/support/QueryDslRepositorySupportTests.java @@ -127,6 +127,10 @@ public class QueryDslRepositorySupportTests { private static final QUser user = QUser.user; + public UserRepositoryImpl() { + super(User.class); + } + @Override @PersistenceContext(unitName = "default") public void setEntityManager(EntityManager entityManager) {