DATAJPA-176 - Introduce Querydsl abstraction.
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.
This commit is contained in:
@@ -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<T, ID extends Serializable> extends SimpleJpa
|
||||
|
||||
private static final EntityPathResolver DEFAULT_ENTITY_PATH_RESOLVER = SimpleEntityPathResolver.INSTANCE;
|
||||
|
||||
private final EntityManager em;
|
||||
private final EntityPath<T> path;
|
||||
private final PathBuilder<T> 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<T, ID extends Serializable> extends SimpleJpa
|
||||
* @param entityManager must not be {@literal null}.
|
||||
*/
|
||||
public QueryDslJpaRepository(JpaEntityInformation<T, ID> entityInformation, EntityManager entityManager) {
|
||||
|
||||
this(entityInformation, entityManager, DEFAULT_ENTITY_PATH_RESOLVER);
|
||||
}
|
||||
|
||||
@@ -76,10 +71,10 @@ public class QueryDslJpaRepository<T, ID extends Serializable> extends SimpleJpa
|
||||
EntityPathResolver resolver) {
|
||||
|
||||
super(entityInformation, entityManager);
|
||||
this.em = entityManager;
|
||||
|
||||
this.path = resolver.createPath(entityInformation.getJavaType());
|
||||
this.builder = new PathBuilder<T>(path.getType(), path.getMetadata());
|
||||
this.provider = PersistenceProvider.fromEntityManager(entityManager);
|
||||
this.querydsl = new Querydsl(entityManager, builder);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -113,7 +108,7 @@ public class QueryDslJpaRepository<T, ID extends Serializable> extends SimpleJpa
|
||||
public Page<T> 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<T>(query.list(path), pageable, countQuery.count());
|
||||
}
|
||||
@@ -133,60 +128,6 @@ public class QueryDslJpaRepository<T, ID extends Serializable> 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<Object> 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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<JPADeleteClause> delete(EntityPath<?> path) {
|
||||
|
||||
return new JPADeleteClause(entityManager, path);
|
||||
}
|
||||
|
||||
@@ -100,19 +111,26 @@ public abstract class QueryDslRepositorySupport {
|
||||
* @return the Querydsl {@link UpdateClause}.
|
||||
*/
|
||||
protected UpdateClause<JPAUpdateClause> 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 <T>
|
||||
* @param type
|
||||
* @return the Querdsl {@link PathBuilder}.
|
||||
*/
|
||||
protected <T> PathBuilder<T> getBuilder(Class<T> type) {
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> PathBuilder<T> getBuilder() {
|
||||
return (PathBuilder<T>) builder;
|
||||
}
|
||||
|
||||
return builderFactory.create(type);
|
||||
/**
|
||||
* Returns the underlying Querydsl helper instance.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
protected Querydsl getQuerydsl() {
|
||||
return this.querydsl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Object> property = builder.get(order.getProperty());
|
||||
|
||||
return new OrderSpecifier(order.isAscending() ? com.mysema.query.types.Order.ASC
|
||||
: com.mysema.query.types.Order.DESC, property);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user