From ed7df2eceb24230538bd0276f859ef7d321158a8 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 17 Mar 2016 16:24:59 +0100 Subject: [PATCH] DATAJPA-218 - Polishing. Adapted to API changes in Spring Data Commons. Related tickets: DATACMNS-810. Original pull request: #164. --- src/main/asciidoc/query-by-example.adoc | 9 +-- .../QueryByExamplePredicateBuilder.java | 10 +-- .../support/SimpleJpaRepository.java | 33 +++----- .../jpa/repository/UserRepositoryTests.java | 79 +++++++++---------- 4 files changed, 58 insertions(+), 73 deletions(-) diff --git a/src/main/asciidoc/query-by-example.adoc b/src/main/asciidoc/query-by-example.adoc index 92654f16e..05a4ac1b6 100644 --- a/src/main/asciidoc/query-by-example.adoc +++ b/src/main/asciidoc/query-by-example.adoc @@ -7,9 +7,7 @@ In Spring Data JPA you can use Query by Example with Repositories. ==== [source, java] ---- -public interface PersonRepository extends JpaRepository { - -} +public interface PersonRepository extends JpaRepository { … } public class PersonService { @@ -22,10 +20,7 @@ public class PersonService { ---- ==== -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. - +NOTE: Only `SingularAttribute` properties can currently 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. diff --git a/src/main/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilder.java b/src/main/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilder.java index 72cee28f2..1fa518568 100644 --- a/src/main/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilder.java +++ b/src/main/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilder.java @@ -34,8 +34,8 @@ import javax.persistence.metamodel.SingularAttribute; import org.springframework.dao.InvalidDataAccessApiUsageException; import org.springframework.data.domain.Example; -import org.springframework.data.domain.ExampleSpec; -import org.springframework.data.repository.core.support.ExampleSpecAccessor; +import org.springframework.data.domain.ExampleMatcher; +import org.springframework.data.repository.core.support.ExampleMatcherAccessor; import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper; import org.springframework.orm.jpa.JpaSystemException; import org.springframework.util.Assert; @@ -78,7 +78,7 @@ public class QueryByExamplePredicateBuilder { Assert.notNull(example, "Example must not be null!"); List predicates = getPredicates("", cb, root, root.getModel(), example.getProbe(), - example.getProbeType(), new ExampleSpecAccessor(example.getExampleSpec()), + example.getProbeType(), new ExampleMatcherAccessor(example.getMatcher()), new PathNode("root", null, example.getProbe())); if (predicates.isEmpty()) { @@ -94,7 +94,7 @@ public class QueryByExamplePredicateBuilder { @SuppressWarnings({ "rawtypes", "unchecked" }) static List getPredicates(String path, CriteriaBuilder cb, Path from, ManagedType type, Object value, - Class probeType, ExampleSpecAccessor exampleAccessor, PathNode currentNode) { + Class probeType, ExampleMatcherAccessor exampleAccessor, PathNode currentNode) { List predicates = new ArrayList(); DirectFieldAccessFallbackBeanWrapper beanWrapper = new DirectFieldAccessFallbackBeanWrapper(value); @@ -112,7 +112,7 @@ public class QueryByExamplePredicateBuilder { if (attributeValue == null) { - if (exampleAccessor.getNullHandler().equals(ExampleSpec.NullHandler.INCLUDE)) { + if (exampleAccessor.getNullHandler().equals(ExampleMatcher.NullHandler.INCLUDE)) { predicates.add(cb.isNull(from.get(attribute))); } continue; 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 e33b3d11c..379b78134 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 @@ -44,7 +44,6 @@ 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; @@ -148,8 +147,8 @@ public class SimpleJpaRepository T entity = findOne(id); if (entity == null) { - throw new EmptyResultDataAccessException(String.format("No %s entity with id %s exists!", - entityInformation.getJavaType(), id), 1); + throw new EmptyResultDataAccessException( + String.format("No %s entity with id %s exists!", entityInformation.getJavaType(), id), 1); } delete(entity); @@ -422,7 +421,7 @@ public class SimpleJpaRepository @Override public S findOne(Example example) { try { - return getQuery(new ExampleSpecification(example), getResultType(example), (Sort) null).getSingleResult(); + return getQuery(new ExampleSpecification(example), example.getProbeType(), (Sort) null).getSingleResult(); } catch (NoResultException e) { return null; } @@ -431,10 +430,10 @@ public class SimpleJpaRepository /* (non-Javadoc) * @see org.springframework.data.repository.query.QueryByExampleExecutor#count(org.springframework.data.domain.Example) */ - @SuppressWarnings("unchecked") @Override + @SuppressWarnings("unchecked") public long count(Example example) { - return executeCountQuery(getCountQuery(new ExampleSpecification(example), getResultType(example))); + return executeCountQuery(getCountQuery(new ExampleSpecification(example), example.getProbeType())); } /* (non-Javadoc) @@ -442,7 +441,7 @@ public class SimpleJpaRepository */ @Override public boolean exists(Example example) { - return !getQuery(new ExampleSpecification(example), getResultType(example), (Sort) null).getResultList() + return !getQuery(new ExampleSpecification(example), example.getProbeType(), (Sort) null).getResultList() .isEmpty(); } @@ -452,7 +451,7 @@ public class SimpleJpaRepository */ @Override public List findAll(Example example) { - return getQuery(new ExampleSpecification(example), getResultType(example), (Sort) null).getResultList(); + return getQuery(new ExampleSpecification(example), example.getProbeType(), (Sort) null).getResultList(); } /* @@ -461,7 +460,7 @@ public class SimpleJpaRepository */ @Override public List findAll(Example example, Sort sort) { - return getQuery(new ExampleSpecification(example), getResultType(example), sort).getResultList(); + return getQuery(new ExampleSpecification(example), example.getProbeType(), sort).getResultList(); } /* @@ -472,9 +471,10 @@ public class SimpleJpaRepository public Page findAll(Example example, Pageable pageable) { ExampleSpecification spec = new ExampleSpecification(example); - TypedQuery query = getQuery(new ExampleSpecification(example), getResultType(example), pageable); - return pageable == null ? new PageImpl(query.getResultList()) - : readPage(query, getResultType(example), pageable, spec); + Class probeType = example.getProbeType(); + TypedQuery query = getQuery(new ExampleSpecification(example), probeType, pageable); + + return pageable == null ? new PageImpl(query.getResultList()) : readPage(query, probeType, pageable, spec); } /* @@ -743,15 +743,6 @@ public class SimpleJpaRepository } } - - private Class getResultType(Example example) { - - if(example.getExampleSpec() instanceof TypedExampleSpec){ - return example.getResultType(); - } - return (Class) getDomainClass(); - } - /** * Executes a count query and transparently sums up all values returned. * 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 691ab45e1..6d0563fc6 100644 --- a/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java @@ -19,6 +19,7 @@ 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.ExampleMatcher.*; 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; @@ -53,9 +54,9 @@ 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.ExampleSpec; -import org.springframework.data.domain.ExampleSpec.GenericPropertyMatcher; -import org.springframework.data.domain.ExampleSpec.StringMatcher; +import org.springframework.data.domain.ExampleMatcher; +import org.springframework.data.domain.ExampleMatcher.GenericPropertyMatcher; +import org.springframework.data.domain.ExampleMatcher.StringMatcher; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageImpl; import org.springframework.data.domain.PageRequest; @@ -530,8 +531,8 @@ public class UserRepositoryTests { firstUser = repository.save(firstUser); secondUser = repository.save(secondUser); - assertTrue(repository.findByLastnameOrFirstname("Oliver", "Arrasz").containsAll( - Arrays.asList(firstUser, secondUser))); + assertTrue( + repository.findByLastnameOrFirstname("Oliver", "Arrasz").containsAll(Arrays.asList(firstUser, secondUser))); } @Test @@ -1297,7 +1298,7 @@ public class UserRepositoryTests { repository.saveAndFlush(user); List result = repository - .findAll(Example.of(new User(), ExampleSpec.untyped().withIgnorePaths("age", "createdAt", "dateOfBirth"))); + .findAll(Example.of(new User(), ExampleMatcher.matching().withIgnorePaths("age", "createdAt", "dateOfBirth"))); assertThat(result, hasSize(5)); } @@ -1316,8 +1317,7 @@ public class UserRepositoryTests { repository.saveAndFlush(user); - Example example = Example.of(new User(), - ExampleSpec.typed(User.class).withIgnorePaths("age", "createdAt", "dateOfBirth")); + Example example = Example.of(new User(), matching().withIgnorePaths("age", "createdAt", "dateOfBirth")); List result = repository.findAll(example); assertThat(result, hasSize(5)); @@ -1337,9 +1337,9 @@ public class UserRepositoryTests { repository.saveAndFlush(user); - Example example = Example.of(new User(), - ExampleSpec.typed(SpecialUser.class).withIgnorePaths("age", "createdAt", "dateOfBirth")); - List result = repository.findAll(example); + Example example = Example.of(new SpecialUser(), + matching().withIgnorePaths("age", "createdAt", "dateOfBirth")); + List result = repository.findAll(example); assertThat(result, hasSize(1)); } @@ -1835,8 +1835,8 @@ public class UserRepositoryTests { public void shouldfindUsersBySpELExpressionParametersWithSpelTemplateExpression() { flushTestUsers(); - List users = repository.findUsersByFirstnameForSpELExpressionWithParameterIndexOnlyWithEntityExpression( - "Joachim", "Arrasz"); + List users = repository + .findUsersByFirstnameForSpELExpressionWithParameterIndexOnlyWithEntityExpression("Joachim", "Arrasz"); assertThat(users, hasSize(1)); assertThat(users.get(0), is(secondUser)); @@ -2008,7 +2008,7 @@ public class UserRepositoryTests { prototype.setCreatedAt(null); List users = repository - .findAll(of(prototype, ExampleSpec.untyped().withIgnorePaths("age", "createdAt", "active"))); + .findAll(of(prototype, ExampleMatcher.matching().withIgnorePaths("age", "createdAt", "active"))); assertThat(users, hasSize(4)); } @@ -2018,7 +2018,7 @@ public class UserRepositoryTests { */ @Test(expected = InvalidDataAccessApiUsageException.class) public void findAllByNullExample() { - repository.findAll((Example) null); + repository.findAll((Example) null); } /** @@ -2032,7 +2032,7 @@ public class UserRepositoryTests { User prototype = new User(); prototype.setAge(28); - Example example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnorePaths("createdAt")); + Example example = Example.of(prototype, matching().withIgnorePaths("createdAt")); List users = repository.findAll(example); assertThat(users, hasSize(1)); @@ -2060,7 +2060,7 @@ public class UserRepositoryTests { prototype.setCreatedAt(null); prototype.setManager(manager); - Example example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnorePaths("age")); + Example example = Example.of(prototype, matching().withIgnorePaths("age")); List users = repository.findAll(example); assertThat(users, hasSize(1)); @@ -2082,7 +2082,7 @@ public class UserRepositoryTests { prototype.setCreatedAt(null); prototype.setAddress(new Address("germany", null, null, null)); - Example example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnorePaths("age")); + Example example = Example.of(prototype, matching().withIgnorePaths("age")); List users = repository.findAll(example); assertThat(users, hasSize(1)); @@ -2101,7 +2101,7 @@ public class UserRepositoryTests { prototype.setFirstname("Ol"); Example example = Example.of(prototype, - ExampleSpec.typed(User.class).withStringMatcher(StringMatcher.STARTING).withIgnorePaths("age", "createdAt")); + matching().withStringMatcher(StringMatcher.STARTING).withIgnorePaths("age", "createdAt")); List users = repository.findAll(example); assertThat(users, hasSize(1)); @@ -2120,7 +2120,7 @@ public class UserRepositoryTests { prototype.setFirstname("ver"); Example example = Example.of(prototype, - ExampleSpec.typed(User.class).withStringMatcher(StringMatcher.ENDING).withIgnorePaths("age", "createdAt")); + matching().withStringMatcher(StringMatcher.ENDING).withIgnorePaths("age", "createdAt")); List users = repository.findAll(example); assertThat(users, hasSize(1)); @@ -2138,7 +2138,7 @@ public class UserRepositoryTests { User prototype = new User(); prototype.setFirstname("^Oliver$"); - Example example = Example.of(prototype, ExampleSpec.typed(User.class).withStringMatcher(StringMatcher.REGEX)); + Example example = Example.of(prototype, matching().withStringMatcher(StringMatcher.REGEX)); repository.findAll(example); } @@ -2153,8 +2153,7 @@ public class UserRepositoryTests { User prototype = new User(); prototype.setFirstname("oLiVer"); - Example example = Example.of(prototype, - ExampleSpec.typed(User.class).withIgnoreCase().withIgnorePaths("age", "createdAt")); + Example example = Example.of(prototype, matching().withIgnoreCase().withIgnorePaths("age", "createdAt")); List users = repository.findAll(example); @@ -2173,8 +2172,8 @@ public class UserRepositoryTests { User prototype = new User(); prototype.setFirstname("oLiV"); - Example example = Example.of(prototype, ExampleSpec.typed(User.class) - .withStringMatcher(StringMatcher.STARTING).withIgnoreCase().withIgnorePaths("age", "createdAt")); + Example example = Example.of(prototype, + matching().withStringMatcher(StringMatcher.STARTING).withIgnoreCase().withIgnorePaths("age", "createdAt")); List users = repository.findAll(example); @@ -2207,8 +2206,8 @@ public class UserRepositoryTests { User prototype = new User(); prototype.setFirstname(firstUser.getFirstname()); - Example example = Example.of(prototype, ExampleSpec.typed(User.class).withIncludeNullValues() - .withIgnorePaths("id", "binaryData", "lastname", "emailAddress", "age", "createdAt")); + Example example = Example.of(prototype, matching().withIncludeNullValues().withIgnorePaths("id", "binaryData", + "lastname", "emailAddress", "age", "createdAt")); List users = repository.findAll(example); @@ -2227,8 +2226,8 @@ public class UserRepositoryTests { User prototype = new User(); prototype.setFirstname("oLi"); - Example example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnoreCase() - .withIgnorePaths("age", "createdAt").withMatcher("firstname", new GenericPropertyMatcher().startsWith())); + Example example = Example.of(prototype, matching().withIgnoreCase().withIgnorePaths("age", "createdAt") + .withMatcher("firstname", new GenericPropertyMatcher().startsWith())); List users = repository.findAll(example); @@ -2252,8 +2251,8 @@ public class UserRepositoryTests { User prototype = new User(); prototype.setFirstname("oLi"); - Example example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnoreCase() - .withIgnorePaths("age", "createdAt").withStringMatcher(StringMatcher.STARTING).withIgnoreCase()); + Example example = Example.of(prototype, matching().withIgnoreCase().withIgnorePaths("age", "createdAt") + .withStringMatcher(StringMatcher.STARTING).withIgnoreCase()); List users = repository.findAll(example, new Sort(DESC, "age")); @@ -2280,8 +2279,8 @@ public class UserRepositoryTests { User prototype = new User(); prototype.setFirstname("oLi"); - Example example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnoreCase() - .withIgnorePaths("age", "createdAt").withStringMatcher(StringMatcher.STARTING).withIgnoreCase()); + Example example = Example.of(prototype, matching().withIgnoreCase().withIgnorePaths("age", "createdAt") + .withStringMatcher(StringMatcher.STARTING).withIgnoreCase()); Page users = repository.findAll(example, new PageRequest(0, 10, new Sort(DESC, "age"))); @@ -2303,8 +2302,8 @@ public class UserRepositoryTests { user1.setManager(user1); - Example example = Example.of(user1, ExampleSpec.typed(User.class).withIgnoreCase() - .withIgnorePaths("age", "createdAt").withStringMatcher(StringMatcher.STARTING).withIgnoreCase()); + Example example = Example.of(user1, matching().withIgnoreCase().withIgnorePaths("age", "createdAt") + .withStringMatcher(StringMatcher.STARTING).withIgnoreCase()); repository.findAll(example, new PageRequest(0, 10, new Sort(DESC, "age"))); } @@ -2326,8 +2325,8 @@ public class UserRepositoryTests { user1.setManager(user2); user2.setManager(user1); - Example example = Example.of(user1, ExampleSpec.typed(User.class).withIgnoreCase() - .withIgnorePaths("age", "createdAt").withStringMatcher(StringMatcher.STARTING).withIgnoreCase()); + Example example = Example.of(user1, matching().withIgnoreCase().withIgnorePaths("age", "createdAt") + .withStringMatcher(StringMatcher.STARTING).withIgnoreCase()); repository.findAll(example, new PageRequest(0, 10, new Sort(DESC, "age"))); } @@ -2343,7 +2342,7 @@ public class UserRepositoryTests { User prototype = new User(); prototype.setAge(28); - Example example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnorePaths("createdAt")); + Example example = Example.of(prototype, matching().withIgnorePaths("createdAt")); User users = repository.findOne(example); assertThat(users, is(firstUser)); @@ -2360,7 +2359,7 @@ public class UserRepositoryTests { User prototype = new User(); prototype.setAge(28); - Example example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnorePaths("createdAt")); + Example example = Example.of(prototype, matching().withIgnorePaths("createdAt")); long count = repository.count(example); assertThat(count, is(1L)); @@ -2377,7 +2376,7 @@ public class UserRepositoryTests { User prototype = new User(); prototype.setAge(28); - Example example = Example.of(prototype, ExampleSpec.typed(User.class).withIgnorePaths("createdAt")); + Example example = Example.of(prototype, matching().withIgnorePaths("createdAt")); boolean exists = repository.exists(example); assertThat(exists, is(true));