DATAJPA-218 - Further work on Query by Example.
Add reference documentation. Adapted to API changes in Spring Data Commons. Related tickets: DATACMNS-810. Original pull request: #164.
This commit is contained in:
committed by
Oliver Gierke
parent
88abb0dbc3
commit
75f2719c61
2
.gitignore
vendored
2
.gitignore
vendored
@@ -1,5 +1,7 @@
|
||||
target/
|
||||
.idea/
|
||||
.settings/
|
||||
*.iml
|
||||
.project
|
||||
.classpath
|
||||
.springBeans
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
= Spring Data JPA - Reference Documentation
|
||||
Oliver Gierke; Thomas Darimont; Christoph Strobl
|
||||
Oliver Gierke; Thomas Darimont; Christoph Strobl; Mark Paluch
|
||||
:revnumber: {version}
|
||||
:revdate: {localdate}
|
||||
:toc:
|
||||
@@ -7,7 +7,7 @@ Oliver Gierke; Thomas Darimont; Christoph Strobl
|
||||
:spring-data-commons-docs: ../../../../spring-data-commons/src/main/asciidoc
|
||||
:spring-framework-docs: http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/html
|
||||
|
||||
(C) 2008-2015 The original authors.
|
||||
(C) 2008-2016 The original authors.
|
||||
|
||||
NOTE: Copies of this document may be made for your own use and for distribution to others, provided that you do not charge any fee for such copies and further provided that each copy contains this Copyright Notice, whether distributed in print or electronically.
|
||||
|
||||
|
||||
@@ -604,6 +604,9 @@ List<Customer> customers = customerRepository.findAll(
|
||||
As you can see, `Specifications` offers some glue-code methods to chain and combine `Specification` instances. Thus extending your data access layer is just a matter of creating new `Specification` implementations and combining them with ones already existing.
|
||||
====
|
||||
|
||||
include::{spring-data-commons-docs}/query-by-example.adoc[]
|
||||
include::query-by-example.adoc[]
|
||||
|
||||
[[transactions]]
|
||||
== Transactionality
|
||||
CRUD methods on repository instances are transactional by default. For reading operations the transaction configuration `readOnly` flag is set to true, all others are configured with a plain `@Transactional` so that default transaction configuration applies. For details see JavaDoc of `CrudRepository`. If you need to tweak transaction configuration for one of the methods declared in a repository simply redeclare the method in your repository interface as follows:
|
||||
|
||||
68
src/main/asciidoc/query-by-example.adoc
Normal file
68
src/main/asciidoc/query-by-example.adoc
Normal file
@@ -0,0 +1,68 @@
|
||||
[[query.by.example.execution]]
|
||||
== Executing Example
|
||||
|
||||
In Spring Data JPA you can use Query by Example with Repositories.
|
||||
|
||||
.Query by Example using a Repository
|
||||
====
|
||||
[source, java]
|
||||
----
|
||||
public interface PersonRepository extends JpaRepository<Person, String> {
|
||||
|
||||
}
|
||||
|
||||
public class PersonService {
|
||||
|
||||
@Autowired PersonRepository personRepository;
|
||||
|
||||
public List<Person> findPeople(Person probe) {
|
||||
return personRepository.findAll(Example.of(probe));
|
||||
}
|
||||
}
|
||||
----
|
||||
====
|
||||
|
||||
An `Example` containing an untyped `ExampleSpec` uses the Repository type. Typed `ExampleSpec` use their type for creating JPA queries.
|
||||
|
||||
NOTE: Only SingularAttribute properties can be used for property matching.
|
||||
|
||||
|
||||
Property specifier accepts property names (e.g. "firstname" and "lastname"). You can navigate by chaining properties together with dots ("address.city"). You can tune it with matching options and case sensitivity.
|
||||
|
||||
[cols="1,2", options="header"]
|
||||
.`StringMatcher` options
|
||||
|===
|
||||
| Matching
|
||||
| Logical result
|
||||
|
||||
| `DEFAULT` (case-sensitive)
|
||||
| `firstname = ?0`
|
||||
|
||||
| `DEFAULT` (case-insensitive)
|
||||
| `LOWER(firstname) = LOWER(?0)`
|
||||
|
||||
| `EXACT` (case-sensitive)
|
||||
| `firstname = ?0`
|
||||
|
||||
| `EXACT` (case-insensitive)
|
||||
| `LOWER(firstname) = LOWER(?0)`
|
||||
|
||||
| `STARTING` (case-sensitive)
|
||||
| `firstname like ?0 + '%'`
|
||||
|
||||
| `STARTING` (case-insensitive)
|
||||
| `LOWER(firstname) like LOWER(?0) + '%'`
|
||||
|
||||
| `ENDING` (case-sensitive)
|
||||
| `firstname like '%' + ?0`
|
||||
|
||||
| `ENDING` (case-insensitive)
|
||||
| `LOWER(firstname) like '%' + LOWER(?0)`
|
||||
|
||||
| `CONTAINING` (case-sensitive)
|
||||
| `firstname like '%' + ?0 + '%'`
|
||||
|
||||
| `CONTAINING` (case-insensitive)
|
||||
| `LOWER(firstname) like '%' + LOWER(?0) + '%'`
|
||||
|
||||
|===
|
||||
@@ -34,7 +34,8 @@ import javax.persistence.metamodel.SingularAttribute;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.domain.Example.NullHandler;
|
||||
import org.springframework.data.domain.ExampleSpec;
|
||||
import org.springframework.data.repository.core.support.ExampleSpecAccessor;
|
||||
import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper;
|
||||
import org.springframework.orm.jpa.JpaSystemException;
|
||||
import org.springframework.util.Assert;
|
||||
@@ -48,8 +49,9 @@ import org.springframework.util.StringUtils;
|
||||
* The builder includes any {@link SingularAttribute} of the {@link Example#getProbe()} applying {@link String} and
|
||||
* {@literal null} matching strategies configured on the {@link Example}. Ignored paths are no matter of their actual
|
||||
* value not considered. <br />
|
||||
*
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
* @since 1.10
|
||||
*/
|
||||
public class QueryByExamplePredicateBuilder {
|
||||
@@ -63,7 +65,7 @@ public class QueryByExamplePredicateBuilder {
|
||||
|
||||
/**
|
||||
* Extract the {@link Predicate} representing the {@link Example}.
|
||||
*
|
||||
*
|
||||
* @param root must not be {@literal null}.
|
||||
* @param cb must not be {@literal null}.
|
||||
* @param example must not be {@literal null}.
|
||||
@@ -73,13 +75,14 @@ public class QueryByExamplePredicateBuilder {
|
||||
|
||||
Assert.notNull(root, "Root must not be null!");
|
||||
Assert.notNull(cb, "CriteriaBuilder must not be null!");
|
||||
Assert.notNull(example, "Root must not be null!");
|
||||
Assert.notNull(example, "Example must not be null!");
|
||||
|
||||
List<Predicate> predicates = getPredicates("", cb, root, root.getModel(), example.getSampleObject(), example,
|
||||
new PathNode("root", null, example.getSampleObject()));
|
||||
List<Predicate> predicates = getPredicates("", cb, root, root.getModel(), example.getProbe(),
|
||||
example.getProbeType(), new ExampleSpecAccessor(example.getExampleSpec()),
|
||||
new PathNode("root", null, example.getProbe()));
|
||||
|
||||
if (predicates.isEmpty()) {
|
||||
return cb.isTrue(cb.literal(false));
|
||||
return cb.isTrue(cb.literal(true));
|
||||
}
|
||||
|
||||
if (predicates.size() == 1) {
|
||||
@@ -90,8 +93,8 @@ public class QueryByExamplePredicateBuilder {
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
static List<Predicate> getPredicates(String path, CriteriaBuilder cb, Path<?> from, ManagedType<?> type,
|
||||
Object value, Example<?> example, PathNode currentNode) {
|
||||
static List<Predicate> getPredicates(String path, CriteriaBuilder cb, Path<?> from, ManagedType<?> type, Object value,
|
||||
Class<?> probeType, ExampleSpecAccessor exampleAccessor, PathNode currentNode) {
|
||||
|
||||
List<Predicate> predicates = new ArrayList<Predicate>();
|
||||
DirectFieldAccessFallbackBeanWrapper beanWrapper = new DirectFieldAccessFallbackBeanWrapper(value);
|
||||
@@ -100,16 +103,16 @@ public class QueryByExamplePredicateBuilder {
|
||||
|
||||
String currentPath = !StringUtils.hasText(path) ? attribute.getName() : path + "." + attribute.getName();
|
||||
|
||||
if (example.isIgnoredPath(currentPath)) {
|
||||
if (exampleAccessor.isIgnoredPath(currentPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Object attributeValue = example.getValueTransformerForPath(currentPath).convert(
|
||||
beanWrapper.getPropertyValue(attribute.getName()));
|
||||
Object attributeValue = exampleAccessor.getValueTransformerForPath(currentPath)
|
||||
.convert(beanWrapper.getPropertyValue(attribute.getName()));
|
||||
|
||||
if (attributeValue == null) {
|
||||
|
||||
if (example.getNullHandler().equals(NullHandler.INCLUDE)) {
|
||||
if (exampleAccessor.getNullHandler().equals(ExampleSpec.NullHandler.INCLUDE)) {
|
||||
predicates.add(cb.isNull(from.get(attribute)));
|
||||
}
|
||||
continue;
|
||||
@@ -118,26 +121,26 @@ public class QueryByExamplePredicateBuilder {
|
||||
if (attribute.getPersistentAttributeType().equals(PersistentAttributeType.EMBEDDED)) {
|
||||
|
||||
predicates.addAll(getPredicates(currentPath, cb, from.get(attribute.getName()),
|
||||
(ManagedType<?>) attribute.getType(), attributeValue, example, currentNode));
|
||||
(ManagedType<?>) attribute.getType(), attributeValue, probeType, exampleAccessor, currentNode));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isAssociation(attribute)) {
|
||||
|
||||
if (!(from instanceof From)) {
|
||||
throw new JpaSystemException(new IllegalArgumentException(String.format(
|
||||
"Unexpected path type for %s. Found % where From.class was expected.", currentPath, from)));
|
||||
throw new JpaSystemException(new IllegalArgumentException(
|
||||
String.format("Unexpected path type for %s. Found % where From.class was expected.", currentPath, from)));
|
||||
}
|
||||
|
||||
PathNode node = currentNode.add(attribute.getName(), attributeValue);
|
||||
if (node.spansCycle()) {
|
||||
throw new InvalidDataAccessApiUsageException(String.format(
|
||||
"Path '%s' from root %s must not span a cyclic property reference!\r\n%s", currentPath,
|
||||
ClassUtils.getShortName(example.getSampleType()), node));
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
String.format("Path '%s' from root %s must not span a cyclic property reference!\r\n%s", currentPath,
|
||||
ClassUtils.getShortName(probeType), node));
|
||||
}
|
||||
|
||||
predicates.addAll(getPredicates(currentPath, cb, ((From<?, ?>) from).join(attribute.getName()),
|
||||
(ManagedType<?>) attribute.getType(), attributeValue, example, node));
|
||||
(ManagedType<?>) attribute.getType(), attributeValue, probeType, exampleAccessor, node));
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -145,12 +148,12 @@ public class QueryByExamplePredicateBuilder {
|
||||
if (attribute.getJavaType().equals(String.class)) {
|
||||
|
||||
Expression<String> expression = from.get(attribute);
|
||||
if (example.isIgnoreCaseForPath(currentPath)) {
|
||||
if (exampleAccessor.isIgnoreCaseForPath(currentPath)) {
|
||||
expression = cb.lower(expression);
|
||||
attributeValue = attributeValue.toString().toLowerCase();
|
||||
}
|
||||
|
||||
switch (example.getStringMatcherForPath(currentPath)) {
|
||||
switch (exampleAccessor.getStringMatcherForPath(currentPath)) {
|
||||
|
||||
case DEFAULT:
|
||||
case EXACT:
|
||||
@@ -166,8 +169,8 @@ public class QueryByExamplePredicateBuilder {
|
||||
predicates.add(cb.like(expression, "%" + attributeValue));
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported StringMatcher "
|
||||
+ example.getStringMatcherForPath(currentPath));
|
||||
throw new IllegalArgumentException(
|
||||
"Unsupported StringMatcher " + exampleAccessor.getStringMatcherForPath(currentPath));
|
||||
}
|
||||
} else {
|
||||
predicates.add(cb.equal(from.get(attribute), attributeValue));
|
||||
@@ -184,7 +187,7 @@ public class QueryByExamplePredicateBuilder {
|
||||
/**
|
||||
* {@link PathNode} is used to dynamically grow a directed graph structure that allows to detect cycles within its
|
||||
* direct predecessor nodes by comparing parent node values using {@link System#identityHashCode(Object)}.
|
||||
*
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
*/
|
||||
private static class PathNode {
|
||||
|
||||
@@ -52,7 +52,7 @@ import org.springframework.util.ConcurrentReferenceHashMap;
|
||||
* @author Oliver Gierke
|
||||
* @author Thomas Darimont
|
||||
*/
|
||||
public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
|
||||
public enum PersistenceProvider implements QueryExtractor,ProxyIdAccessor {
|
||||
|
||||
/**
|
||||
* Hibernate persistence provider.
|
||||
@@ -117,14 +117,13 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
|
||||
public CloseableIterator<Object> executeQueryWithResultStream(Query jpaQuery) {
|
||||
return new HibernateScrollableResultsIterator<Object>(jpaQuery);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
* EclipseLink persistence provider.
|
||||
*/
|
||||
ECLIPSELINK(Collections.singleton(ECLIPSELINK_ENTITY_MANAGER_INTERFACE), Collections
|
||||
.singleton(ECLIPSELINK_JPA_METAMODEL_TYPE)) {
|
||||
ECLIPSELINK(Collections.singleton(ECLIPSELINK_ENTITY_MANAGER_INTERFACE),
|
||||
Collections.singleton(ECLIPSELINK_JPA_METAMODEL_TYPE)) {
|
||||
|
||||
public String extractQueryString(Query query) {
|
||||
return ((JpaQuery<?>) query).getDatabaseQuery().getJPQLString();
|
||||
@@ -164,7 +163,6 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
|
||||
public CloseableIterator<Object> executeQueryWithResultStream(Query jpaQuery) {
|
||||
return new EclipseLinkScrollableResultsIterator<Object>(jpaQuery);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -203,7 +201,6 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
|
||||
public CloseableIterator<Object> executeQueryWithResultStream(Query jpaQuery) {
|
||||
return new OpenJpaResultStreamingIterator<Object>(jpaQuery);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
/**
|
||||
@@ -246,7 +243,6 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
|
||||
public Object getIdentifierFrom(Object entity) {
|
||||
return null;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -388,8 +384,8 @@ public enum PersistenceProvider implements QueryExtractor, ProxyIdAccessor {
|
||||
}
|
||||
|
||||
public CloseableIterator<Object> executeQueryWithResultStream(Query jpaQuery) {
|
||||
throw new UnsupportedOperationException("Streaming results is not implement for this PersistenceProvider: "
|
||||
+ name());
|
||||
throw new UnsupportedOperationException(
|
||||
"Streaming results is not implement for this PersistenceProvider: " + name());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -21,20 +21,21 @@ import java.util.List;
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.repository.NoRepositoryBean;
|
||||
import org.springframework.data.repository.PagingAndSortingRepository;
|
||||
import org.springframework.data.repository.query.QueryByExampleExecutor;
|
||||
|
||||
/**
|
||||
* JPA specific extension of {@link org.springframework.data.repository.Repository}.
|
||||
*
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@NoRepositoryBean
|
||||
public interface JpaRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
|
||||
public interface JpaRepository<T, ID extends Serializable>
|
||||
extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
@@ -95,33 +96,16 @@ public interface JpaRepository<T, ID extends Serializable> extends PagingAndSort
|
||||
*/
|
||||
T getOne(ID id);
|
||||
|
||||
/**
|
||||
* Returns all instances of the type specified by the given {@link Example}.
|
||||
*
|
||||
* @param example must not be {@literal null}.
|
||||
* @return
|
||||
* @since 1.10
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example)
|
||||
*/
|
||||
List<T> findAllByExample(Example<T> example);
|
||||
@Override
|
||||
<S extends T> List<S> findAll(Example<S> example);
|
||||
|
||||
/**
|
||||
* Returns all instances of the type specified by the given {@link Example}.
|
||||
*
|
||||
* @param example must not be {@literal null}.
|
||||
* @param sort can be {@literal null}.
|
||||
* @return all entities sorted by the given options
|
||||
* @since 1.10
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example, org.springframework.data.domain.Sort)
|
||||
*/
|
||||
List<T> findAllByExample(Example<T> example, Sort sort);
|
||||
@Override
|
||||
<S extends T> List<S> findAll(Example<S> example, Sort sort);
|
||||
|
||||
/**
|
||||
* Returns a {@link Page} of entities meeting the paging restriction specified by the given {@link Example} limited to
|
||||
* criteria provided in the {@code Pageable} object.
|
||||
*
|
||||
* @param example must not be {@literal null}.
|
||||
* @param pageable can be {@literal null}.
|
||||
* @return a {@link Page} of entities
|
||||
* @since 1.10
|
||||
*/
|
||||
Page<T> findAllByExample(Example<T> example, Pageable pageable);
|
||||
}
|
||||
|
||||
@@ -189,8 +189,8 @@ public abstract class AbstractJpaQuery implements RepositoryQuery {
|
||||
Assert.notNull(query, "Query must not be null!");
|
||||
Assert.notNull(method, "JpaQueryMethod must not be null!");
|
||||
|
||||
Map<String, Object> hints = Jpa21Utils.tryGetFetchGraphHints(em, method.getEntityGraph(), getQueryMethod()
|
||||
.getEntityInformation().getJavaType());
|
||||
Map<String, Object> hints = Jpa21Utils.tryGetFetchGraphHints(em, method.getEntityGraph(),
|
||||
getQueryMethod().getEntityInformation().getJavaType());
|
||||
|
||||
for (Map.Entry<String, Object> hint : hints.entrySet()) {
|
||||
query.setHint(hint.getKey(), hint.getValue());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2015 the original author or authors.
|
||||
* Copyright 2008-2016 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.
|
||||
@@ -44,6 +44,7 @@ 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.TypedExampleSpec;
|
||||
import org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder;
|
||||
import org.springframework.data.jpa.domain.Specification;
|
||||
import org.springframework.data.jpa.provider.PersistenceProvider;
|
||||
@@ -64,13 +65,14 @@ import org.springframework.util.Assert;
|
||||
* @author Oliver Gierke
|
||||
* @author Eberhard Wolff
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
* @param <T> the type of the entity to handle
|
||||
* @param <ID> the type of the entity's identifier
|
||||
*/
|
||||
@Repository
|
||||
@Transactional(readOnly = true)
|
||||
public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepository<T, ID>,
|
||||
JpaSpecificationExecutor<T> {
|
||||
public class SimpleJpaRepository<T, ID extends Serializable>
|
||||
implements JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
|
||||
|
||||
private static final String ID_MUST_NOT_BE_NULL = "The given id must not be null!";
|
||||
|
||||
@@ -370,7 +372,7 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
|
||||
return new PageImpl<T>(findAll());
|
||||
}
|
||||
|
||||
return findAll(null, pageable);
|
||||
return findAll((Specification<T>) null, pageable);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -414,29 +416,65 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.JpaRepository#findWithExample(org.springframework.data.jpa.domain.Example)
|
||||
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findOne(org.springframework.data.domain.Example)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <S extends T> S findOne(Example<S> example) {
|
||||
try {
|
||||
return getQuery(new ExampleSpecification<S>(example), getResultType(example), (Sort) null).getSingleResult();
|
||||
} catch (NoResultException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.QueryByExampleExecutor#count(org.springframework.data.domain.Example)
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <S extends T> long count(Example<S> example) {
|
||||
return executeCountQuery(getCountQuery(new ExampleSpecification<S>(example), getResultType(example)));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.QueryByExampleExecutor#exists(org.springframework.data.domain.Example)
|
||||
*/
|
||||
@Override
|
||||
public List<T> findAllByExample(Example<T> example) {
|
||||
return findAll(new ExampleSpecification<T>(example));
|
||||
public <S extends T> boolean exists(Example<S> example) {
|
||||
return !getQuery(new ExampleSpecification<S>(example), getResultType(example), (Sort) null).getResultList()
|
||||
.isEmpty();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.JpaRepository#findAllByExample(org.springframework.data.domain.Example, org.springframework.data.domain.Sort)
|
||||
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example)
|
||||
*/
|
||||
@Override
|
||||
public List<T> findAllByExample(Example<T> example, Sort sort) {
|
||||
return findAll(new ExampleSpecification<T>(example), sort);
|
||||
public <S extends T> List<S> findAll(Example<S> example) {
|
||||
return getQuery(new ExampleSpecification<S>(example), getResultType(example), (Sort) null).getResultList();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.jpa.repository.JpaRepository#findAllByExample(org.springframework.data.domain.Example, org.springframework.data.domain.Pageable)
|
||||
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example, org.springframework.data.domain.Sort)
|
||||
*/
|
||||
@Override
|
||||
public Page<T> findAllByExample(Example<T> example, Pageable pageable) {
|
||||
return findAll(new ExampleSpecification<T>(example), pageable);
|
||||
public <S extends T> List<S> findAll(Example<S> example, Sort sort) {
|
||||
return getQuery(new ExampleSpecification<S>(example), getResultType(example), sort).getResultList();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.repository.query.QueryByExampleExecutor#findAll(org.springframework.data.domain.Example, org.springframework.data.domain.Pageable)
|
||||
*/
|
||||
@Override
|
||||
public <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {
|
||||
|
||||
ExampleSpecification<S> spec = new ExampleSpecification<S>(example);
|
||||
TypedQuery<S> query = getQuery(new ExampleSpecification<S>(example), getResultType(example), pageable);
|
||||
return pageable == null ? new PageImpl<S>(query.getResultList())
|
||||
: readPage(query, getResultType(example), pageable, spec);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -517,26 +555,41 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
|
||||
/**
|
||||
* Reads the given {@link TypedQuery} into a {@link Page} applying the given {@link Pageable} and
|
||||
* {@link Specification}.
|
||||
*
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @param spec can be {@literal null}.
|
||||
* @param pageable can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected Page<T> readPage(TypedQuery<T> query, Pageable pageable, Specification<T> spec) {
|
||||
return readPage(query, getDomainClass(), pageable, spec);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the given {@link TypedQuery} into a {@link Page} applying the given {@link Pageable} and
|
||||
* {@link Specification}.
|
||||
*
|
||||
* @param query must not be {@literal null}.
|
||||
* @param domainClass must not be {@literal null}.
|
||||
* @param spec can be {@literal null}.
|
||||
* @param pageable can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected <S extends T> Page<S> readPage(TypedQuery<S> query, Class<S> domainClass, Pageable pageable,
|
||||
Specification<S> spec) {
|
||||
|
||||
query.setFirstResult(pageable.getOffset());
|
||||
query.setMaxResults(pageable.getPageSize());
|
||||
|
||||
Long total = executeCountQuery(getCountQuery(spec));
|
||||
List<T> content = total > pageable.getOffset() ? query.getResultList() : Collections.<T> emptyList();
|
||||
Long total = executeCountQuery(getCountQuery(spec, domainClass));
|
||||
List<S> content = total > pageable.getOffset() ? query.getResultList() : Collections.<S> emptyList();
|
||||
|
||||
return new PageImpl<T>(content, pageable, total);
|
||||
return new PageImpl<S>(content, pageable, total);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TypedQuery} from the given {@link Specification}.
|
||||
*
|
||||
*
|
||||
* @param spec can be {@literal null}.
|
||||
* @param pageable can be {@literal null}.
|
||||
* @return
|
||||
@@ -544,7 +597,21 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
|
||||
protected TypedQuery<T> getQuery(Specification<T> spec, Pageable pageable) {
|
||||
|
||||
Sort sort = pageable == null ? null : pageable.getSort();
|
||||
return getQuery(spec, sort);
|
||||
return getQuery(spec, getDomainClass(), sort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link TypedQuery} from the given {@link Specification}.
|
||||
*
|
||||
* @param spec can be {@literal null}.
|
||||
* @param domainClass must not be {@literal null}.
|
||||
* @param pageable can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, Class<S> domainClass, Pageable pageable) {
|
||||
|
||||
Sort sort = pageable == null ? null : pageable.getSort();
|
||||
return getQuery(spec, domainClass, sort);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -555,11 +622,23 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
|
||||
* @return
|
||||
*/
|
||||
protected TypedQuery<T> getQuery(Specification<T> spec, Sort sort) {
|
||||
return getQuery(spec, getDomainClass(), sort);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a {@link TypedQuery} for the given {@link Specification} and {@link Sort}.
|
||||
*
|
||||
* @param spec can be {@literal null}.
|
||||
* @param domainClass must not be {@literal null}.
|
||||
* @param sort can be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, Class<S> domainClass, Sort sort) {
|
||||
|
||||
CriteriaBuilder builder = em.getCriteriaBuilder();
|
||||
CriteriaQuery<T> query = builder.createQuery(getDomainClass());
|
||||
CriteriaQuery<S> query = builder.createQuery(domainClass);
|
||||
|
||||
Root<T> root = applySpecificationToCriteria(spec, query);
|
||||
Root<S> root = applySpecificationToCriteria(spec, domainClass, query);
|
||||
query.select(root);
|
||||
|
||||
if (sort != null) {
|
||||
@@ -576,11 +655,22 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
|
||||
* @return
|
||||
*/
|
||||
protected TypedQuery<Long> getCountQuery(Specification<T> spec) {
|
||||
return getCountQuery(spec, getDomainClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new count query for the given {@link Specification}.
|
||||
*
|
||||
* @param spec can be {@literal null}.
|
||||
* @param domainClass must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
protected <S extends T> TypedQuery<Long> getCountQuery(Specification<S> spec, Class<S> domainClass) {
|
||||
|
||||
CriteriaBuilder builder = em.getCriteriaBuilder();
|
||||
CriteriaQuery<Long> query = builder.createQuery(Long.class);
|
||||
|
||||
Root<T> root = applySpecificationToCriteria(spec, query);
|
||||
Root<S> root = applySpecificationToCriteria(spec, domainClass, query);
|
||||
|
||||
if (query.isDistinct()) {
|
||||
query.select(builder.countDistinct(root));
|
||||
@@ -599,9 +689,24 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
|
||||
* @return
|
||||
*/
|
||||
private <S> Root<T> applySpecificationToCriteria(Specification<T> spec, CriteriaQuery<S> query) {
|
||||
return applySpecificationToCriteria(spec, getDomainClass(), query);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the given {@link Specification} to the given {@link CriteriaQuery}.
|
||||
*
|
||||
* @param spec can be {@literal null}.
|
||||
* @param domainClass must not be {@literal null}.
|
||||
* @param query must not be {@literal null}.
|
||||
* @return
|
||||
*/
|
||||
private <S, U extends T> Root<U> applySpecificationToCriteria(Specification<U> spec, Class<U> domainClass,
|
||||
CriteriaQuery<S> query) {
|
||||
|
||||
Assert.notNull(query);
|
||||
Root<T> root = query.from(getDomainClass());
|
||||
Assert.notNull(domainClass);
|
||||
Root<U> root = query.from(domainClass);
|
||||
|
||||
if (spec == null) {
|
||||
return root;
|
||||
@@ -617,14 +722,14 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
|
||||
return root;
|
||||
}
|
||||
|
||||
private TypedQuery<T> applyRepositoryMethodMetadata(TypedQuery<T> query) {
|
||||
private <S> TypedQuery<S> applyRepositoryMethodMetadata(TypedQuery<S> query) {
|
||||
|
||||
if (metadata == null) {
|
||||
return query;
|
||||
}
|
||||
|
||||
LockModeType type = metadata.getLockModeType();
|
||||
TypedQuery<T> toReturn = type == null ? query : query.setLockMode(type);
|
||||
TypedQuery<S> toReturn = type == null ? query : query.setLockMode(type);
|
||||
|
||||
applyQueryHints(toReturn);
|
||||
|
||||
@@ -638,6 +743,15 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private <S extends T> Class<S> getResultType(Example<S> example) {
|
||||
|
||||
if(example.getExampleSpec() instanceof TypedExampleSpec<?>){
|
||||
return example.getResultType();
|
||||
}
|
||||
return (Class<S>) getDomainClass();
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a count query and transparently sums up all values returned.
|
||||
*
|
||||
@@ -692,7 +806,7 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
|
||||
/**
|
||||
* {@link Specification} that gives access to the {@link Predicate} instance representing the values contained in the
|
||||
* {@link Example}.
|
||||
*
|
||||
*
|
||||
* @author Christoph Strobl
|
||||
* @since 1.10
|
||||
* @param <T>
|
||||
@@ -703,7 +817,7 @@ public class SimpleJpaRepository<T, ID extends Serializable> implements JpaRepos
|
||||
|
||||
/**
|
||||
* Creates new {@link ExampleSpecification}.
|
||||
*
|
||||
*
|
||||
* @param example
|
||||
*/
|
||||
public ExampleSpecification(Example<T> example) {
|
||||
|
||||
@@ -47,6 +47,7 @@ import org.springframework.util.ObjectUtils;
|
||||
|
||||
/**
|
||||
* @author Christoph Strobl
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class QueryByExamplePredicateBuilderUnitTests {
|
||||
@@ -55,7 +56,7 @@ public class QueryByExamplePredicateBuilderUnitTests {
|
||||
@Mock Root root;
|
||||
@Mock EntityType<Person> personEntityType;
|
||||
@Mock Expression expressionMock;
|
||||
@Mock Predicate falsePredicate;
|
||||
@Mock Predicate truePredicate;
|
||||
@Mock Predicate dummyPredicate;
|
||||
@Mock Predicate listPredicate;
|
||||
@Mock Path dummyPath;
|
||||
@@ -100,7 +101,7 @@ public class QueryByExamplePredicateBuilderUnitTests {
|
||||
when(cb.like(any(Expression.class), any(String.class))).thenReturn(dummyPredicate);
|
||||
|
||||
when(cb.literal(any(Boolean.class))).thenReturn(expressionMock);
|
||||
when(cb.isTrue(eq(expressionMock))).thenReturn(falsePredicate);
|
||||
when(cb.isTrue(eq(expressionMock))).thenReturn(truePredicate);
|
||||
when(cb.and(Matchers.<Predicate> anyVararg())).thenReturn(listPredicate);
|
||||
}
|
||||
|
||||
@@ -109,7 +110,7 @@ public class QueryByExamplePredicateBuilderUnitTests {
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void getPredicateShouldThrowExceptionOnNullRoot() {
|
||||
QueryByExamplePredicateBuilder.getPredicate(null, cb, exampleOf(new Person()));
|
||||
QueryByExamplePredicateBuilder.getPredicate(null, cb, of(new Person()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -117,7 +118,7 @@ public class QueryByExamplePredicateBuilderUnitTests {
|
||||
*/
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void getPredicateShouldThrowExceptionOnNullCriteriaBuilder() {
|
||||
QueryByExamplePredicateBuilder.getPredicate(root, null, exampleOf(new Person()));
|
||||
QueryByExamplePredicateBuilder.getPredicate(root, null, of(new Person()));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -132,8 +133,8 @@ public class QueryByExamplePredicateBuilderUnitTests {
|
||||
* @see DATAJPA-218
|
||||
*/
|
||||
@Test
|
||||
public void emptyCriteriaListShouldResultFalsePredicate() {
|
||||
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, exampleOf(new Person())), equalTo(falsePredicate));
|
||||
public void emptyCriteriaListShouldResultTruePredicate() {
|
||||
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, of(new Person())), equalTo(truePredicate));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -145,7 +146,7 @@ public class QueryByExamplePredicateBuilderUnitTests {
|
||||
Person p = new Person();
|
||||
p.firstname = "foo";
|
||||
|
||||
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, exampleOf(p)), equalTo(dummyPredicate));
|
||||
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, of(p)), equalTo(dummyPredicate));
|
||||
verify(cb, times(1)).equal(any(Expression.class), eq("foo"));
|
||||
}
|
||||
|
||||
@@ -159,7 +160,7 @@ public class QueryByExamplePredicateBuilderUnitTests {
|
||||
p.firstname = "foo";
|
||||
p.age = 2L;
|
||||
|
||||
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, exampleOf(p)), equalTo(listPredicate));
|
||||
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, of(p)), equalTo(listPredicate));
|
||||
|
||||
verify(cb, times(1)).equal(any(Expression.class), eq("foo"));
|
||||
verify(cb, times(1)).equal(any(Expression.class), eq(2L));
|
||||
|
||||
@@ -30,6 +30,8 @@ import org.springframework.context.annotation.FilterType;
|
||||
import org.springframework.context.annotation.ImportResource;
|
||||
import org.springframework.data.jpa.domain.sample.Category;
|
||||
import org.springframework.data.jpa.domain.sample.Product;
|
||||
import org.springframework.data.jpa.provider.PersistenceProvider;
|
||||
import org.springframework.data.jpa.provider.ProxyIdAccessor;
|
||||
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.data.jpa.repository.sample.CategoryRepository;
|
||||
import org.springframework.data.jpa.repository.sample.ProductRepository;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2014 the original author or authors.
|
||||
* Copyright 2008-2016 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.
|
||||
@@ -16,10 +16,12 @@
|
||||
package org.springframework.data.jpa.repository;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.data.domain.Example.*;
|
||||
import static org.springframework.data.domain.Sort.Direction.*;
|
||||
import static org.springframework.data.jpa.domain.Specifications.*;
|
||||
import static org.springframework.data.jpa.domain.Specifications.not;
|
||||
import static org.springframework.data.jpa.domain.sample.UserSpecifications.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -51,12 +53,13 @@ import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.domain.Example;
|
||||
import org.springframework.data.domain.Example.StringMatcher;
|
||||
import org.springframework.data.domain.ExampleSpec;
|
||||
import org.springframework.data.domain.ExampleSpec.GenericPropertyMatcher;
|
||||
import org.springframework.data.domain.ExampleSpec.StringMatcher;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.PageRequest;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.PropertySpecifier;
|
||||
import org.springframework.data.domain.Slice;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.data.domain.Sort.Direction;
|
||||
@@ -84,6 +87,7 @@ import com.google.common.base.Optional;
|
||||
* @author Oliver Gierke
|
||||
* @author Kevin Raymond
|
||||
* @author Thomas Darimont
|
||||
* @author Mark Paluch
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:application-context.xml")
|
||||
@@ -593,7 +597,7 @@ public class UserRepositoryTests {
|
||||
Pageable pageable = new PageRequest(0, 1);
|
||||
|
||||
flushTestUsers();
|
||||
assertThat(repository.findAll(null, pageable), is(repository.findAll(pageable)));
|
||||
assertThat(repository.findAll((Specification<User>) null, pageable), is(repository.findAll(pageable)));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1278,6 +1282,68 @@ public class UserRepositoryTests {
|
||||
assertThat(user.getEmailAddress(), is(savedUser.getEmailAddress()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-218
|
||||
*/
|
||||
@Test
|
||||
public void findAllByUntypedExampleShouldReturnSubTypesOfRepositoryEntity() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
SpecialUser user = new SpecialUser();
|
||||
user.setFirstname("Thomas");
|
||||
user.setEmailAddress("thomas@example.org");
|
||||
|
||||
repository.saveAndFlush(user);
|
||||
|
||||
List<User> result = repository
|
||||
.findAll(Example.of(new User(), ExampleSpec.untyped().withIgnorePaths("age", "createdAt", "dateOfBirth")));
|
||||
|
||||
assertThat(result, hasSize(5));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-218
|
||||
*/
|
||||
@Test
|
||||
public void findAllByTypedUserExampleShouldReturnSubTypesOfRepositoryEntity() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
SpecialUser user = new SpecialUser();
|
||||
user.setFirstname("Thomas");
|
||||
user.setEmailAddress("thomas@example.org");
|
||||
|
||||
repository.saveAndFlush(user);
|
||||
|
||||
Example<User> example = Example.of(new User(),
|
||||
ExampleSpec.typed(User.class).withIgnorePaths("age", "createdAt", "dateOfBirth"));
|
||||
List<User> result = repository.findAll(example);
|
||||
|
||||
assertThat(result, hasSize(5));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-218
|
||||
*/
|
||||
@Test
|
||||
public void findAllByTypedSpecialUserExampleShouldReturnSubTypesOfRepositoryEntity() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
SpecialUser user = new SpecialUser();
|
||||
user.setFirstname("Thomas");
|
||||
user.setEmailAddress("thomas@example.org");
|
||||
|
||||
repository.saveAndFlush(user);
|
||||
|
||||
Example<User> example = Example.of(new User(),
|
||||
ExampleSpec.typed(SpecialUser.class).withIgnorePaths("age", "createdAt", "dateOfBirth"));
|
||||
List<User> result = repository.findAll(example);
|
||||
|
||||
assertThat(result, hasSize(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-491
|
||||
*/
|
||||
@@ -1924,18 +1990,35 @@ public class UserRepositoryTests {
|
||||
prototype.setAge(28);
|
||||
prototype.setCreatedAt(null);
|
||||
|
||||
List<User> users = repository.findAllByExample(exampleOf(prototype));
|
||||
List<User> users = repository.findAll(of(prototype));
|
||||
|
||||
assertThat(users, hasSize(1));
|
||||
assertThat(users.get(0), is(firstUser));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-218
|
||||
*/
|
||||
@Test
|
||||
public void findAllByExampleWithEmptyProbe() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
User prototype = new User();
|
||||
prototype.setCreatedAt(null);
|
||||
|
||||
List<User> users = repository
|
||||
.findAll(of(prototype, ExampleSpec.untyped().withIgnorePaths("age", "createdAt", "active")));
|
||||
|
||||
assertThat(users, hasSize(4));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-218
|
||||
*/
|
||||
@Test(expected = InvalidDataAccessApiUsageException.class)
|
||||
public void findAllByNullExample() {
|
||||
repository.findAllByExample(null);
|
||||
repository.findAll((Example) null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1949,7 +2032,8 @@ public class UserRepositoryTests {
|
||||
User prototype = new User();
|
||||
prototype.setAge(28);
|
||||
|
||||
List<User> users = repository.findAllByExample(newExampleOf(prototype).ignore("createdAt").get());
|
||||
Example<User> example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnorePaths("createdAt"));
|
||||
List<User> users = repository.findAll(example);
|
||||
|
||||
assertThat(users, hasSize(1));
|
||||
assertThat(users.get(0), is(firstUser));
|
||||
@@ -1976,7 +2060,8 @@ public class UserRepositoryTests {
|
||||
prototype.setCreatedAt(null);
|
||||
prototype.setManager(manager);
|
||||
|
||||
List<User> users = repository.findAllByExample(newExampleOf(prototype).ignore("age").get());
|
||||
Example<User> example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnorePaths("age"));
|
||||
List<User> users = repository.findAll(example);
|
||||
|
||||
assertThat(users, hasSize(1));
|
||||
assertThat(users.get(0), is(firstUser));
|
||||
@@ -1997,7 +2082,8 @@ public class UserRepositoryTests {
|
||||
prototype.setCreatedAt(null);
|
||||
prototype.setAddress(new Address("germany", null, null, null));
|
||||
|
||||
List<User> users = repository.findAllByExample(newExampleOf(prototype).ignore("age").get());
|
||||
Example<User> example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnorePaths("age"));
|
||||
List<User> users = repository.findAll(example);
|
||||
|
||||
assertThat(users, hasSize(1));
|
||||
assertThat(users.get(0), is(firstUser));
|
||||
@@ -2014,9 +2100,9 @@ public class UserRepositoryTests {
|
||||
User prototype = new User();
|
||||
prototype.setFirstname("Ol");
|
||||
|
||||
Example<User> example = newExampleOf(prototype).matchStringsStartingWith().ignore("age", "createdAt").get();
|
||||
|
||||
List<User> users = repository.findAllByExample(example);
|
||||
Example<User> example = Example.of(prototype,
|
||||
ExampleSpec.typed(User.class).withStringMatcher(StringMatcher.STARTING).withIgnorePaths("age", "createdAt"));
|
||||
List<User> users = repository.findAll(example);
|
||||
|
||||
assertThat(users, hasSize(1));
|
||||
assertThat(users.get(0), is(firstUser));
|
||||
@@ -2033,9 +2119,9 @@ public class UserRepositoryTests {
|
||||
User prototype = new User();
|
||||
prototype.setFirstname("ver");
|
||||
|
||||
Example<User> example = newExampleOf(prototype).matchStringsEndingWith().ignore("age", "createdAt").get();
|
||||
|
||||
List<User> users = repository.findAllByExample(example);
|
||||
Example<User> example = Example.of(prototype,
|
||||
ExampleSpec.typed(User.class).withStringMatcher(StringMatcher.ENDING).withIgnorePaths("age", "createdAt"));
|
||||
List<User> users = repository.findAll(example);
|
||||
|
||||
assertThat(users, hasSize(1));
|
||||
assertThat(users.get(0), is(firstUser));
|
||||
@@ -2052,10 +2138,8 @@ public class UserRepositoryTests {
|
||||
User prototype = new User();
|
||||
prototype.setFirstname("^Oliver$");
|
||||
|
||||
Example<User> example = newExampleOf(prototype).withStringMatcher(StringMatcher.REGEX).ignore("age", "createdAt")
|
||||
.get();
|
||||
|
||||
repository.findAllByExample(example);
|
||||
Example<User> example = Example.of(prototype, ExampleSpec.typed(User.class).withStringMatcher(StringMatcher.REGEX));
|
||||
repository.findAll(example);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2069,9 +2153,10 @@ public class UserRepositoryTests {
|
||||
User prototype = new User();
|
||||
prototype.setFirstname("oLiVer");
|
||||
|
||||
Example<User> example = newExampleOf(prototype).matchStringsWithIgnoreCase().ignore("age", "createdAt").get();
|
||||
Example<User> example = Example.of(prototype,
|
||||
ExampleSpec.typed(User.class).withIgnoreCase().withIgnorePaths("age", "createdAt"));
|
||||
|
||||
List<User> users = repository.findAllByExample(example);
|
||||
List<User> users = repository.findAll(example);
|
||||
|
||||
assertThat(users, hasSize(1));
|
||||
assertThat(users.get(0), is(firstUser));
|
||||
@@ -2088,10 +2173,10 @@ public class UserRepositoryTests {
|
||||
User prototype = new User();
|
||||
prototype.setFirstname("oLiV");
|
||||
|
||||
Example<User> example = newExampleOf(prototype).matchStringsStartingWith().matchStringsWithIgnoreCase()
|
||||
.ignore("age", "createdAt").get();
|
||||
Example<User> example = Example.of(prototype, ExampleSpec.typed(User.class)
|
||||
.withStringMatcher(StringMatcher.STARTING).withIgnoreCase().withIgnorePaths("age", "createdAt"));
|
||||
|
||||
List<User> users = repository.findAllByExample(example);
|
||||
List<User> users = repository.findAll(example);
|
||||
|
||||
assertThat(users, hasSize(1));
|
||||
assertThat(users.get(0), is(firstUser));
|
||||
@@ -2122,10 +2207,10 @@ public class UserRepositoryTests {
|
||||
User prototype = new User();
|
||||
prototype.setFirstname(firstUser.getFirstname());
|
||||
|
||||
Example<User> example = newExampleOf(prototype).includeNullValues()
|
||||
.ignore("id", "binaryData", "lastname", "emailAddress", "age", "createdAt").get();
|
||||
Example<User> example = Example.of(prototype, ExampleSpec.typed(User.class).withIncludeNullValues()
|
||||
.withIgnorePaths("id", "binaryData", "lastname", "emailAddress", "age", "createdAt"));
|
||||
|
||||
List<User> users = repository.findAllByExample(example);
|
||||
List<User> users = repository.findAll(example);
|
||||
|
||||
assertThat(users, hasSize(1));
|
||||
assertThat(users.get(0), is(fifthUser));
|
||||
@@ -2142,11 +2227,10 @@ public class UserRepositoryTests {
|
||||
User prototype = new User();
|
||||
prototype.setFirstname("oLi");
|
||||
|
||||
Example<User> example = newExampleOf(prototype).matchStringsWithIgnoreCase().ignore("age", "createdAt")
|
||||
.withPropertySpecifier(PropertySpecifier.newPropertySpecifier("firstname").matchStringStartingWith().get())
|
||||
.get();
|
||||
Example<User> example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnoreCase()
|
||||
.withIgnorePaths("age", "createdAt").withMatcher("firstname", new GenericPropertyMatcher().startsWith()));
|
||||
|
||||
List<User> users = repository.findAllByExample(example);
|
||||
List<User> users = repository.findAll(example);
|
||||
|
||||
assertThat(users, hasSize(1));
|
||||
assertThat(users.get(0), is(firstUser));
|
||||
@@ -2168,10 +2252,10 @@ public class UserRepositoryTests {
|
||||
User prototype = new User();
|
||||
prototype.setFirstname("oLi");
|
||||
|
||||
Example<User> example = newExampleOf(prototype).matchStringsStartingWith().matchStringsWithIgnoreCase()
|
||||
.ignore("age", "createdAt").get();
|
||||
Example<User> example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnoreCase()
|
||||
.withIgnorePaths("age", "createdAt").withStringMatcher(StringMatcher.STARTING).withIgnoreCase());
|
||||
|
||||
List<User> users = repository.findAllByExample(example, new Sort(DESC, "age"));
|
||||
List<User> users = repository.findAll(example, new Sort(DESC, "age"));
|
||||
|
||||
assertThat(users, hasSize(2));
|
||||
assertThat(users.get(0), is(user1));
|
||||
@@ -2196,10 +2280,10 @@ public class UserRepositoryTests {
|
||||
User prototype = new User();
|
||||
prototype.setFirstname("oLi");
|
||||
|
||||
Example<User> example = newExampleOf(prototype).matchStringsStartingWith().matchStringsWithIgnoreCase()
|
||||
.ignore("age", "createdAt").get();
|
||||
Example<User> example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnoreCase()
|
||||
.withIgnorePaths("age", "createdAt").withStringMatcher(StringMatcher.STARTING).withIgnoreCase());
|
||||
|
||||
Page<User> users = repository.findAllByExample(example, new PageRequest(0, 10, new Sort(DESC, "age")));
|
||||
Page<User> users = repository.findAll(example, new PageRequest(0, 10, new Sort(DESC, "age")));
|
||||
|
||||
assertThat(users.getSize(), is(10));
|
||||
assertThat(users.hasNext(), is(true));
|
||||
@@ -2219,10 +2303,10 @@ public class UserRepositoryTests {
|
||||
|
||||
user1.setManager(user1);
|
||||
|
||||
Example<User> example = newExampleOf(user1).matchStringsStartingWith().matchStringsWithIgnoreCase()
|
||||
.ignore("age", "createdAt").get();
|
||||
Example<User> example = Example.of(user1, ExampleSpec.typed(User.class).withIgnoreCase()
|
||||
.withIgnorePaths("age", "createdAt").withStringMatcher(StringMatcher.STARTING).withIgnoreCase());
|
||||
|
||||
repository.findAllByExample(example, new PageRequest(0, 10, new Sort(DESC, "age")));
|
||||
repository.findAll(example, new PageRequest(0, 10, new Sort(DESC, "age")));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2242,10 +2326,61 @@ public class UserRepositoryTests {
|
||||
user1.setManager(user2);
|
||||
user2.setManager(user1);
|
||||
|
||||
Example<User> example = newExampleOf(user1).matchStringsStartingWith().matchStringsWithIgnoreCase()
|
||||
.ignore("age", "createdAt").get();
|
||||
Example<User> example = Example.of(user1, ExampleSpec.typed(User.class).withIgnoreCase()
|
||||
.withIgnorePaths("age", "createdAt").withStringMatcher(StringMatcher.STARTING).withIgnoreCase());
|
||||
|
||||
repository.findAllByExample(example, new PageRequest(0, 10, new Sort(DESC, "age")));
|
||||
repository.findAll(example, new PageRequest(0, 10, new Sort(DESC, "age")));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-218
|
||||
*/
|
||||
@Test
|
||||
public void findOneByExampleWithExcludedAttributes() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
User prototype = new User();
|
||||
prototype.setAge(28);
|
||||
|
||||
Example<User> example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnorePaths("createdAt"));
|
||||
User users = repository.findOne(example);
|
||||
|
||||
assertThat(users, is(firstUser));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-218
|
||||
*/
|
||||
@Test
|
||||
public void countByExampleWithExcludedAttributes() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
User prototype = new User();
|
||||
prototype.setAge(28);
|
||||
|
||||
Example<User> example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnorePaths("createdAt"));
|
||||
long count = repository.count(example);
|
||||
|
||||
assertThat(count, is(1L));
|
||||
}
|
||||
|
||||
/**
|
||||
* @see DATAJPA-218
|
||||
*/
|
||||
@Test
|
||||
public void existsByExampleWithExcludedAttributes() {
|
||||
|
||||
flushTestUsers();
|
||||
|
||||
User prototype = new User();
|
||||
prototype.setAge(28);
|
||||
|
||||
Example<User> example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnorePaths("createdAt"));
|
||||
boolean exists = repository.exists(example);
|
||||
|
||||
assertThat(exists, is(true));
|
||||
}
|
||||
|
||||
private Page<User> executeSpecWithSort(Sort sort) {
|
||||
@@ -2258,5 +2393,4 @@ public class UserRepositoryTests {
|
||||
assertThat(result.getTotalElements(), is(2L));
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user