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 6b8428e41..4afb2aeaa 100644 --- a/src/main/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilder.java +++ b/src/main/java/org/springframework/data/jpa/convert/QueryByExamplePredicateBuilder.java @@ -76,11 +76,23 @@ public class QueryByExamplePredicateBuilder { * @param root must not be {@literal null}. * @param cb must not be {@literal null}. * @param example must not be {@literal null}. - * @param escapeCharacter + * @return never {@literal null}. + */ + public static Predicate getPredicate(Root root, CriteriaBuilder cb, Example example) { + return getPredicate(root, cb, example, EscapeCharacter.DEFAULT); + } + + /** + * 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}. + * @param escapeCharacter Must not be {@literal null}. * @return never {@literal null}. */ public static Predicate getPredicate(Root root, CriteriaBuilder cb, Example example, - EscapeCharacter escapeCharacter) { + EscapeCharacter escapeCharacter) { Assert.notNull(root, "Root must not be null!"); Assert.notNull(cb, "CriteriaBuilder must not be null!"); diff --git a/src/main/java/org/springframework/data/jpa/repository/query/EscapeCharacter.java b/src/main/java/org/springframework/data/jpa/repository/query/EscapeCharacter.java index 15570d8ad..0c9466d3f 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/EscapeCharacter.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/EscapeCharacter.java @@ -33,6 +33,7 @@ import org.springframework.lang.Nullable; @Value(staticConstructor = "of") public class EscapeCharacter { + public static final EscapeCharacter DEFAULT = EscapeCharacter.of('\\'); private static final List TO_REPLACE = Arrays.asList("_", "%"); char escapeCharacter; diff --git a/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java b/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java index 5354a3601..482b2ab7f 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactory.java @@ -69,7 +69,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport { private final CrudMethodMetadataPostProcessor crudMethodMetadataPostProcessor; private EntityPathResolver entityPathResolver; - private EscapeCharacter escapeCharacter = EscapeCharacter.of('\\'); + private EscapeCharacter escapeCharacter = EscapeCharacter.DEFAULT; /** * Creates a new {@link JpaRepositoryFactory}. diff --git a/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBean.java b/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBean.java index b8144f10b..668c7db5b 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBean.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryFactoryBean.java @@ -45,7 +45,7 @@ public class JpaRepositoryFactoryBean, S, ID> private @Nullable EntityManager entityManager; private EntityPathResolver entityPathResolver; - private EscapeCharacter escapeCharacter = EscapeCharacter.of('\\'); + private EscapeCharacter escapeCharacter = EscapeCharacter.DEFAULT; /** * Creates a new {@link JpaRepositoryFactoryBean} for the given repository interface. diff --git a/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryImplementation.java b/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryImplementation.java index 918938bc2..3cbd8cb3a 100644 --- a/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryImplementation.java +++ b/src/main/java/org/springframework/data/jpa/repository/support/JpaRepositoryImplementation.java @@ -42,5 +42,7 @@ public interface JpaRepositoryImplementation extends JpaRepository * * @param escapeCharacter Must not be {@literal null}. */ - void setEscapeCharacter(EscapeCharacter escapeCharacter); + default void setEscapeCharacter(EscapeCharacter escapeCharacter) { + + } } 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 7d115980a..708773fa7 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 @@ -82,7 +82,7 @@ public class SimpleJpaRepository implements JpaRepositoryImplementation QueryByExamplePredicateBuilder.getPredicate(root, cb, of(p), EscapeCharacter.of('\\'))) + .isThrownBy(() -> QueryByExamplePredicateBuilder.getPredicate(root, cb, of(p), EscapeCharacter.DEFAULT)) .withCauseInstanceOf(IllegalArgumentException.class) .withMessageContaining("Unexpected path type"); } @@ -169,7 +169,7 @@ public class QueryByExamplePredicateBuilderUnitTests { p.firstname = "foo"; p.age = 2L; - assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, of(p), EscapeCharacter.of('\\'))) + assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, of(p), EscapeCharacter.DEFAULT)) .isEqualTo(andPredicate); verify(cb, times(1)).equal(any(Expression.class), eq("foo")); @@ -185,7 +185,7 @@ public class QueryByExamplePredicateBuilderUnitTests { Example example = of(person, ExampleMatcher.matchingAny()); - assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.of('\\'))) + assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.DEFAULT)) .isEqualTo(orPredicate); verify(cb, times(1)).or(ArgumentMatchers.any()); @@ -204,7 +204,7 @@ public class QueryByExamplePredicateBuilderUnitTests { .withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) // ); - QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.of('\\')); + QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.DEFAULT); verify(cb, times(1)).like(any(Expression.class), eq("%f\\\\o\\_o%"), eq('\\')); } @@ -223,7 +223,7 @@ public class QueryByExamplePredicateBuilderUnitTests { .withStringMatcher(ExampleMatcher.StringMatcher.STARTING) // ); - QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.of('\\')); + QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.DEFAULT); verify(cb, times(1)).like(any(Expression.class), eq("f\\\\o\\_o%"), eq('\\')); } @@ -241,7 +241,7 @@ public class QueryByExamplePredicateBuilderUnitTests { .withStringMatcher(ExampleMatcher.StringMatcher.ENDING) // ); - QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.of('\\')); + QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.DEFAULT); verify(cb, times(1)).like(any(Expression.class), eq("%f\\\\o\\_o"), eq('\\')); } diff --git a/src/test/java/org/springframework/data/jpa/repository/query/JpaCountQueryCreatorIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/query/JpaCountQueryCreatorIntegrationTests.java index 119ba9bcb..7cd1f0815 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/JpaCountQueryCreatorIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/JpaCountQueryCreatorIntegrationTests.java @@ -60,7 +60,7 @@ public class JpaCountQueryCreatorIntegrationTests { PartTree tree = new PartTree("findDistinctByRolesIn", User.class); ParameterMetadataProvider metadataProvider = new ParameterMetadataProvider(entityManager.getCriteriaBuilder(), - queryMethod.getParameters(), provider, EscapeCharacter.of('\\')); + queryMethod.getParameters(), provider, EscapeCharacter.DEFAULT); JpaCountQueryCreator creator = new JpaCountQueryCreator(tree, queryMethod.getResultProcessor().getReturnedType(), entityManager.getCriteriaBuilder(), metadataProvider); diff --git a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java index 2a3dfe601..39ea1b780 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryLookupStrategyUnitTests.java @@ -76,7 +76,7 @@ public class JpaQueryLookupStrategyUnitTests { public void invalidAnnotatedQueryCausesException() throws Exception { QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, Key.CREATE_IF_NOT_FOUND, extractor, - EVALUATION_CONTEXT_PROVIDER, EscapeCharacter.of('\\')); + EVALUATION_CONTEXT_PROVIDER, EscapeCharacter.DEFAULT); Method method = UserRepository.class.getMethod("findByFoo", String.class); RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class); @@ -92,7 +92,7 @@ public class JpaQueryLookupStrategyUnitTests { public void sholdThrowMorePreciseExceptionIfTryingToUsePaginationInNativeQueries() throws Exception { QueryLookupStrategy strategy = JpaQueryLookupStrategy.create(em, Key.CREATE_IF_NOT_FOUND, extractor, - EVALUATION_CONTEXT_PROVIDER, EscapeCharacter.of('\\')); + EVALUATION_CONTEXT_PROVIDER, EscapeCharacter.DEFAULT); Method method = UserRepository.class.getMethod("findByInvalidNativeQuery", String.class, Sort.class); RepositoryMetadata metadata = new DefaultRepositoryMetadata(UserRepository.class); diff --git a/src/test/java/org/springframework/data/jpa/repository/query/ParameterExpressionProviderTests.java b/src/test/java/org/springframework/data/jpa/repository/query/ParameterExpressionProviderTests.java index c6a4f28c9..41eecc906 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/ParameterExpressionProviderTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/ParameterExpressionProviderTests.java @@ -58,7 +58,7 @@ public class ParameterExpressionProviderTests { CriteriaBuilder builder = em.getCriteriaBuilder(); PersistenceProvider persistenceProvider = PersistenceProvider.fromEntityManager(em); - ParameterMetadataProvider provider = new ParameterMetadataProvider(builder, accessor, persistenceProvider, EscapeCharacter.of('\\')); + ParameterMetadataProvider provider = new ParameterMetadataProvider(builder, accessor, persistenceProvider, EscapeCharacter.DEFAULT); ParameterExpression expression = provider.next(part, Comparable.class).getExpression(); assertThat(expression.getParameterType(), is(typeCompatibleWith(int.class))); } diff --git a/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderIntegrationTests.java index 19a6c5a29..c9115a989 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderIntegrationTests.java @@ -81,7 +81,7 @@ public class ParameterMetadataProviderIntegrationTests { simulateDiscoveredParametername(parameters); return new ParameterMetadataProvider(em.getCriteriaBuilder(), parameters, - PersistenceProvider.fromEntityManager(em), EscapeCharacter.of('\\')); + PersistenceProvider.fromEntityManager(em), EscapeCharacter.DEFAULT); } @SuppressWarnings({ "unchecked", "ConstantConditions" }) diff --git a/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderUnitTests.java index efe0ca170..898f3f074 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/ParameterMetadataProviderUnitTests.java @@ -44,7 +44,7 @@ public class ParameterMetadataProviderUnitTests { when(parameters.getBindableParameters().iterator()).thenReturn(Collections.emptyListIterator()); ParameterMetadataProvider metadataProvider = new ParameterMetadataProvider(builder, parameters, - persistenceProvider, EscapeCharacter.of('\\')); + persistenceProvider, EscapeCharacter.DEFAULT); assertThatExceptionOfType(RuntimeException.class) // .isThrownBy(() -> metadataProvider.next(mock(Part.class))) // diff --git a/src/test/java/org/springframework/data/jpa/repository/query/PartTreeJpaQueryIntegrationTests.java b/src/test/java/org/springframework/data/jpa/repository/query/PartTreeJpaQueryIntegrationTests.java index 7b1b08bec..3a522cd2e 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/PartTreeJpaQueryIntegrationTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/PartTreeJpaQueryIntegrationTests.java @@ -81,7 +81,7 @@ public class PartTreeJpaQueryIntegrationTests { public void test() throws Exception { JpaQueryMethod queryMethod = getQueryMethod("findByFirstname", String.class, Pageable.class); - PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider, EscapeCharacter.of('\\')); + PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider, EscapeCharacter.DEFAULT); jpaQuery.createQuery(new Object[] { "Matthews", PageRequest.of(0, 1) }); jpaQuery.createQuery(new Object[] { "Matthews", PageRequest.of(0, 1) }); @@ -105,7 +105,7 @@ public class PartTreeJpaQueryIntegrationTests { public void recreatesQueryIfNullValueIsGiven() throws Exception { JpaQueryMethod queryMethod = getQueryMethod("findByFirstname", String.class, Pageable.class); - PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider, EscapeCharacter.of('\\')); + PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider, EscapeCharacter.DEFAULT); Query query = jpaQuery.createQuery(new Object[] { "Matthews", PageRequest.of(0, 1) }); @@ -120,7 +120,7 @@ public class PartTreeJpaQueryIntegrationTests { public void shouldLimitExistsProjectionQueries() throws Exception { JpaQueryMethod queryMethod = getQueryMethod("existsByFirstname", String.class); - PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider, EscapeCharacter.of('\\')); + PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider, EscapeCharacter.DEFAULT); Query query = jpaQuery.createQuery(new Object[] { "Matthews" }); @@ -131,7 +131,7 @@ public class PartTreeJpaQueryIntegrationTests { public void shouldSelectAliasedIdForExistsProjectionQueries() throws Exception { JpaQueryMethod queryMethod = getQueryMethod("existsByFirstname", String.class); - PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider, EscapeCharacter.of('\\')); + PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider, EscapeCharacter.DEFAULT); Query query = jpaQuery.createQuery(new Object[] { "Matthews" }); @@ -142,7 +142,7 @@ public class PartTreeJpaQueryIntegrationTests { public void isEmptyCollection() throws Exception { JpaQueryMethod queryMethod = getQueryMethod("findByRolesIsEmpty"); - PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider, EscapeCharacter.of('\\')); + PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider, EscapeCharacter.DEFAULT); Query query = jpaQuery.createQuery(new Object[] {}); @@ -153,7 +153,7 @@ public class PartTreeJpaQueryIntegrationTests { public void isNotEmptyCollection() throws Exception { JpaQueryMethod queryMethod = getQueryMethod("findByRolesIsNotEmpty"); - PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider, EscapeCharacter.of('\\')); + PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, provider, EscapeCharacter.DEFAULT); Query query = jpaQuery.createQuery(new Object[] {}); @@ -164,7 +164,7 @@ public class PartTreeJpaQueryIntegrationTests { public void rejectsIsEmptyOnNonCollectionProperty() throws Exception { JpaQueryMethod method = getQueryMethod("findByFirstnameIsEmpty"); - AbstractJpaQuery jpaQuery = new PartTreeJpaQuery(method, entityManager, provider, EscapeCharacter.of('\\')); + AbstractJpaQuery jpaQuery = new PartTreeJpaQuery(method, entityManager, provider, EscapeCharacter.DEFAULT); jpaQuery.createQuery(new Object[] { "Oliver" }); } @@ -175,7 +175,7 @@ public class PartTreeJpaQueryIntegrationTests { JpaQueryMethod method = getQueryMethod("findByFirstname"); assertThatExceptionOfType(IllegalArgumentException.class) // - .isThrownBy(() -> new PartTreeJpaQuery(method, entityManager, provider, EscapeCharacter.of('\\'))) // + .isThrownBy(() -> new PartTreeJpaQuery(method, entityManager, provider, EscapeCharacter.DEFAULT)) // .withMessageContaining("findByFirstname") // the method being analyzed .withMessageContaining(" firstname ") // the property we are looking for .withMessageContaining("UserRepository"); // the repository @@ -187,7 +187,7 @@ public class PartTreeJpaQueryIntegrationTests { JpaQueryMethod method = getQueryMethod("findByNoSuchProperty", String.class); assertThatExceptionOfType(IllegalArgumentException.class) // - .isThrownBy(() -> new PartTreeJpaQuery(method, entityManager, provider, EscapeCharacter.of('\\'))) // + .isThrownBy(() -> new PartTreeJpaQuery(method, entityManager, provider, EscapeCharacter.DEFAULT)) // .withMessageContaining("findByNoSuchProperty") // the method being analyzed .withMessageContaining(" noSuchProperty ") // the property we are looking for .withMessageContaining("UserRepository"); // the repository @@ -203,7 +203,7 @@ public class PartTreeJpaQueryIntegrationTests { JpaQueryMethod queryMethod = getQueryMethod(methodName, parameterTypes); PartTreeJpaQuery jpaQuery = new PartTreeJpaQuery(queryMethod, entityManager, - PersistenceProvider.fromEntityManager(entityManager), EscapeCharacter.of('\\')); + PersistenceProvider.fromEntityManager(entityManager), EscapeCharacter.DEFAULT); jpaQuery.createQuery(values); }