DATAJPA-1534 - Escape wildcards in QBE Like-queries.
The `StringMatcher` values `STARTING`, `ENDING`, and `CONTAINING` now escape wildcards in their parameters. See also: DATAJPA-1519, DATAJPA-1522.
This commit is contained in:
@@ -36,6 +36,7 @@ import org.springframework.dao.InvalidDataAccessApiUsageException;
|
|||||||
import org.springframework.data.domain.Example;
|
import org.springframework.data.domain.Example;
|
||||||
import org.springframework.data.domain.ExampleMatcher;
|
import org.springframework.data.domain.ExampleMatcher;
|
||||||
import org.springframework.data.domain.ExampleMatcher.PropertyValueTransformer;
|
import org.springframework.data.domain.ExampleMatcher.PropertyValueTransformer;
|
||||||
|
import org.springframework.data.jpa.repository.query.EscapeCharacter;
|
||||||
import org.springframework.data.repository.core.support.ExampleMatcherAccessor;
|
import org.springframework.data.repository.core.support.ExampleMatcherAccessor;
|
||||||
import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper;
|
import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
@@ -55,6 +56,7 @@ import org.springframework.util.StringUtils;
|
|||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Jens Schauder
|
||||||
* @since 1.10
|
* @since 1.10
|
||||||
*/
|
*/
|
||||||
public class QueryByExamplePredicateBuilder {
|
public class QueryByExamplePredicateBuilder {
|
||||||
@@ -76,9 +78,11 @@ public class QueryByExamplePredicateBuilder {
|
|||||||
* @param root must not be {@literal null}.
|
* @param root must not be {@literal null}.
|
||||||
* @param cb must not be {@literal null}.
|
* @param cb must not be {@literal null}.
|
||||||
* @param example must not be {@literal null}.
|
* @param example must not be {@literal null}.
|
||||||
|
* @param escapeCharacter
|
||||||
* @return never {@literal null}.
|
* @return never {@literal null}.
|
||||||
*/
|
*/
|
||||||
public static <T> Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Example<T> example) {
|
public static <T> Predicate getPredicate(Root<T> root, CriteriaBuilder cb, Example<T> example,
|
||||||
|
EscapeCharacter escapeCharacter) {
|
||||||
|
|
||||||
Assert.notNull(root, "Root must not be null!");
|
Assert.notNull(root, "Root must not be null!");
|
||||||
Assert.notNull(cb, "CriteriaBuilder must not be null!");
|
Assert.notNull(cb, "CriteriaBuilder must not be null!");
|
||||||
@@ -87,7 +91,8 @@ public class QueryByExamplePredicateBuilder {
|
|||||||
ExampleMatcher matcher = example.getMatcher();
|
ExampleMatcher matcher = example.getMatcher();
|
||||||
|
|
||||||
List<Predicate> predicates = getPredicates("", cb, root, root.getModel(), example.getProbe(),
|
List<Predicate> predicates = getPredicates("", cb, root, root.getModel(), example.getProbe(),
|
||||||
example.getProbeType(), new ExampleMatcherAccessor(matcher), new PathNode("root", null, example.getProbe()));
|
example.getProbeType(), new ExampleMatcherAccessor(matcher), new PathNode("root", null, example.getProbe()),
|
||||||
|
escapeCharacter);
|
||||||
|
|
||||||
if (predicates.isEmpty()) {
|
if (predicates.isEmpty()) {
|
||||||
return cb.isTrue(cb.literal(true));
|
return cb.isTrue(cb.literal(true));
|
||||||
@@ -104,7 +109,8 @@ public class QueryByExamplePredicateBuilder {
|
|||||||
|
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
static List<Predicate> getPredicates(String path, CriteriaBuilder cb, Path<?> from, ManagedType<?> type, Object value,
|
static List<Predicate> getPredicates(String path, CriteriaBuilder cb, Path<?> from, ManagedType<?> type, Object value,
|
||||||
Class<?> probeType, ExampleMatcherAccessor exampleAccessor, PathNode currentNode) {
|
Class<?> probeType, ExampleMatcherAccessor exampleAccessor, PathNode currentNode,
|
||||||
|
EscapeCharacter escapeCharacter) {
|
||||||
|
|
||||||
List<Predicate> predicates = new ArrayList<>();
|
List<Predicate> predicates = new ArrayList<>();
|
||||||
DirectFieldAccessFallbackBeanWrapper beanWrapper = new DirectFieldAccessFallbackBeanWrapper(value);
|
DirectFieldAccessFallbackBeanWrapper beanWrapper = new DirectFieldAccessFallbackBeanWrapper(value);
|
||||||
@@ -133,8 +139,9 @@ public class QueryByExamplePredicateBuilder {
|
|||||||
|
|
||||||
if (attribute.getPersistentAttributeType().equals(PersistentAttributeType.EMBEDDED)) {
|
if (attribute.getPersistentAttributeType().equals(PersistentAttributeType.EMBEDDED)) {
|
||||||
|
|
||||||
predicates.addAll(getPredicates(currentPath, cb, from.get(attribute.getName()),
|
predicates
|
||||||
(ManagedType<?>) attribute.getType(), attributeValue, probeType, exampleAccessor, currentNode));
|
.addAll(getPredicates(currentPath, cb, from.get(attribute.getName()), (ManagedType<?>) attribute.getType(),
|
||||||
|
attributeValue, probeType, exampleAccessor, currentNode, escapeCharacter));
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +160,7 @@ public class QueryByExamplePredicateBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
predicates.addAll(getPredicates(currentPath, cb, ((From<?, ?>) from).join(attribute.getName()),
|
predicates.addAll(getPredicates(currentPath, cb, ((From<?, ?>) from).join(attribute.getName()),
|
||||||
(ManagedType<?>) attribute.getType(), attributeValue, probeType, exampleAccessor, node));
|
(ManagedType<?>) attribute.getType(), attributeValue, probeType, exampleAccessor, node, escapeCharacter));
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -173,13 +180,25 @@ public class QueryByExamplePredicateBuilder {
|
|||||||
predicates.add(cb.equal(expression, attributeValue));
|
predicates.add(cb.equal(expression, attributeValue));
|
||||||
break;
|
break;
|
||||||
case CONTAINING:
|
case CONTAINING:
|
||||||
predicates.add(cb.like(expression, "%" + attributeValue + "%"));
|
predicates.add(cb.like( //
|
||||||
|
expression, //
|
||||||
|
"%" + escapeCharacter.escape(attributeValue.toString()) + "%", //
|
||||||
|
escapeCharacter.getEscapeCharacter() //
|
||||||
|
));
|
||||||
break;
|
break;
|
||||||
case STARTING:
|
case STARTING:
|
||||||
predicates.add(cb.like(expression, attributeValue + "%"));
|
predicates.add(cb.like(//
|
||||||
|
expression, //
|
||||||
|
escapeCharacter.escape(attributeValue.toString()) + "%", //
|
||||||
|
escapeCharacter.getEscapeCharacter()) //
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case ENDING:
|
case ENDING:
|
||||||
predicates.add(cb.like(expression, "%" + attributeValue));
|
predicates.add(cb.like( //
|
||||||
|
expression, //
|
||||||
|
"%" + escapeCharacter.escape(attributeValue.toString()), //
|
||||||
|
escapeCharacter.getEscapeCharacter()) //
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
|
|||||||
@@ -133,6 +133,7 @@ public class JpaRepositoryFactory extends RepositoryFactorySupport {
|
|||||||
|
|
||||||
JpaRepositoryImplementation<?, ?> repository = getTargetRepository(information, entityManager);
|
JpaRepositoryImplementation<?, ?> repository = getTargetRepository(information, entityManager);
|
||||||
repository.setRepositoryMethodMetadata(crudMethodMetadataPostProcessor.getCrudMethodMetadata());
|
repository.setRepositoryMethodMetadata(crudMethodMetadataPostProcessor.getCrudMethodMetadata());
|
||||||
|
repository.setEscapeCharacter(escapeCharacter);
|
||||||
|
|
||||||
return repository;
|
return repository;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ package org.springframework.data.jpa.repository.support;
|
|||||||
|
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
|
||||||
|
import org.springframework.data.jpa.repository.query.EscapeCharacter;
|
||||||
import org.springframework.data.repository.NoRepositoryBean;
|
import org.springframework.data.repository.NoRepositoryBean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -24,6 +25,7 @@ import org.springframework.data.repository.NoRepositoryBean;
|
|||||||
*
|
*
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
* @author Stefan Fussenegger
|
* @author Stefan Fussenegger
|
||||||
|
* @author Jens Schauder
|
||||||
*/
|
*/
|
||||||
@NoRepositoryBean
|
@NoRepositoryBean
|
||||||
public interface JpaRepositoryImplementation<T, ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
|
public interface JpaRepositoryImplementation<T, ID> extends JpaRepository<T, ID>, JpaSpecificationExecutor<T> {
|
||||||
@@ -34,4 +36,11 @@ public interface JpaRepositoryImplementation<T, ID> extends JpaRepository<T, ID>
|
|||||||
* @param crudMethodMetadata must not be {@literal null}.
|
* @param crudMethodMetadata must not be {@literal null}.
|
||||||
*/
|
*/
|
||||||
void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata);
|
void setRepositoryMethodMetadata(CrudMethodMetadata crudMethodMetadata);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures the {@link EscapeCharacter} to be used with the repository.
|
||||||
|
*
|
||||||
|
* @param escapeCharacter Must not be {@literal null}.
|
||||||
|
*/
|
||||||
|
void setEscapeCharacter(EscapeCharacter escapeCharacter);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import org.springframework.data.jpa.convert.QueryByExamplePredicateBuilder;
|
|||||||
import org.springframework.data.jpa.domain.Specification;
|
import org.springframework.data.jpa.domain.Specification;
|
||||||
import org.springframework.data.jpa.provider.PersistenceProvider;
|
import org.springframework.data.jpa.provider.PersistenceProvider;
|
||||||
import org.springframework.data.jpa.repository.EntityGraph;
|
import org.springframework.data.jpa.repository.EntityGraph;
|
||||||
|
import org.springframework.data.jpa.repository.query.EscapeCharacter;
|
||||||
import org.springframework.data.jpa.repository.query.QueryUtils;
|
import org.springframework.data.jpa.repository.query.QueryUtils;
|
||||||
import org.springframework.data.jpa.repository.support.QueryHints.NoHints;
|
import org.springframework.data.jpa.repository.support.QueryHints.NoHints;
|
||||||
import org.springframework.data.repository.support.PageableExecutionUtils;
|
import org.springframework.data.repository.support.PageableExecutionUtils;
|
||||||
@@ -81,6 +82,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
|||||||
private final PersistenceProvider provider;
|
private final PersistenceProvider provider;
|
||||||
|
|
||||||
private @Nullable CrudMethodMetadata metadata;
|
private @Nullable CrudMethodMetadata metadata;
|
||||||
|
private EscapeCharacter escapeCharacter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@link SimpleJpaRepository} to manage objects of the given {@link JpaEntityInformation}.
|
* Creates a new {@link SimpleJpaRepository} to manage objects of the given {@link JpaEntityInformation}.
|
||||||
@@ -118,6 +120,11 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
|||||||
this.metadata = crudMethodMetadata;
|
this.metadata = crudMethodMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setEscapeCharacter(EscapeCharacter escapeCharacter) {
|
||||||
|
this.escapeCharacter = escapeCharacter;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
protected CrudMethodMetadata getRepositoryMethodMetadata() {
|
protected CrudMethodMetadata getRepositoryMethodMetadata() {
|
||||||
return metadata;
|
return metadata;
|
||||||
@@ -405,7 +412,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
return Optional.of(
|
return Optional.of(
|
||||||
getQuery(new ExampleSpecification<S>(example), example.getProbeType(), Sort.unsorted()).getSingleResult());
|
getQuery(new ExampleSpecification<S>(example, escapeCharacter), example.getProbeType(), Sort.unsorted()).getSingleResult());
|
||||||
} catch (NoResultException e) {
|
} catch (NoResultException e) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
@@ -417,7 +424,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <S extends T> long count(Example<S> example) {
|
public <S extends T> long count(Example<S> example) {
|
||||||
return executeCountQuery(getCountQuery(new ExampleSpecification<S>(example), example.getProbeType()));
|
return executeCountQuery(getCountQuery(new ExampleSpecification<S>(example, escapeCharacter), example.getProbeType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -426,7 +433,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <S extends T> boolean exists(Example<S> example) {
|
public <S extends T> boolean exists(Example<S> example) {
|
||||||
return !getQuery(new ExampleSpecification<S>(example), example.getProbeType(), Sort.unsorted()).getResultList()
|
return !getQuery(new ExampleSpecification<S>(example, escapeCharacter), example.getProbeType(), Sort.unsorted()).getResultList()
|
||||||
.isEmpty();
|
.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -436,7 +443,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <S extends T> List<S> findAll(Example<S> example) {
|
public <S extends T> List<S> findAll(Example<S> example) {
|
||||||
return getQuery(new ExampleSpecification<S>(example), example.getProbeType(), Sort.unsorted()).getResultList();
|
return getQuery(new ExampleSpecification<S>(example, escapeCharacter), example.getProbeType(), Sort.unsorted()).getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -445,7 +452,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public <S extends T> List<S> findAll(Example<S> example, Sort sort) {
|
public <S extends T> List<S> findAll(Example<S> example, Sort sort) {
|
||||||
return getQuery(new ExampleSpecification<S>(example), example.getProbeType(), sort).getResultList();
|
return getQuery(new ExampleSpecification<S>(example, escapeCharacter), example.getProbeType(), sort).getResultList();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -455,9 +462,9 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
|||||||
@Override
|
@Override
|
||||||
public <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {
|
public <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {
|
||||||
|
|
||||||
ExampleSpecification<S> spec = new ExampleSpecification<>(example);
|
ExampleSpecification<S> spec = new ExampleSpecification<>(example, escapeCharacter);
|
||||||
Class<S> probeType = example.getProbeType();
|
Class<S> probeType = example.getProbeType();
|
||||||
TypedQuery<S> query = getQuery(new ExampleSpecification<>(example), probeType, pageable);
|
TypedQuery<S> query = getQuery(new ExampleSpecification<>(example, escapeCharacter), probeType, pageable);
|
||||||
|
|
||||||
return isUnpaged(pageable) ? new PageImpl<>(query.getResultList()) : readPage(query, probeType, pageable, spec);
|
return isUnpaged(pageable) ? new PageImpl<>(query.getResultList()) : readPage(query, probeType, pageable, spec);
|
||||||
}
|
}
|
||||||
@@ -791,16 +798,21 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
|||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
private final Example<T> example;
|
private final Example<T> example;
|
||||||
|
private final EscapeCharacter escapeCharacter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates new {@link ExampleSpecification}.
|
* Creates new {@link ExampleSpecification}.
|
||||||
*
|
*
|
||||||
* @param example
|
* @param example
|
||||||
|
* @param escapeCharacter
|
||||||
*/
|
*/
|
||||||
ExampleSpecification(Example<T> example) {
|
ExampleSpecification(Example<T> example, EscapeCharacter escapeCharacter) {
|
||||||
|
|
||||||
Assert.notNull(example, "Example must not be null!");
|
Assert.notNull(example, "Example must not be null!");
|
||||||
|
Assert.notNull(escapeCharacter, "EscapeCharacter must not be null!");
|
||||||
|
|
||||||
this.example = example;
|
this.example = example;
|
||||||
|
this.escapeCharacter = escapeCharacter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -809,7 +821,7 @@ public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
|
public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
|
||||||
return QueryByExamplePredicateBuilder.getPredicate(root, cb, example);
|
return QueryByExamplePredicateBuilder.getPredicate(root, cb, example, escapeCharacter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ import org.mockito.Mock;
|
|||||||
import org.mockito.junit.MockitoJUnitRunner;
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
import org.springframework.data.domain.Example;
|
import org.springframework.data.domain.Example;
|
||||||
import org.springframework.data.domain.ExampleMatcher;
|
import org.springframework.data.domain.ExampleMatcher;
|
||||||
|
import org.springframework.data.jpa.repository.query.EscapeCharacter;
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,6 +57,7 @@ import org.springframework.util.ObjectUtils;
|
|||||||
* @author Christoph Strobl
|
* @author Christoph Strobl
|
||||||
* @author Mark Paluch
|
* @author Mark Paluch
|
||||||
* @author Oliver Gierke
|
* @author Oliver Gierke
|
||||||
|
* @author Jens Schauder
|
||||||
*/
|
*/
|
||||||
@RunWith(MockitoJUnitRunner.Silent.class)
|
@RunWith(MockitoJUnitRunner.Silent.class)
|
||||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
@@ -118,22 +120,23 @@ public class QueryByExamplePredicateBuilderUnitTests {
|
|||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class) // DATAJPA-218
|
@Test(expected = IllegalArgumentException.class) // DATAJPA-218
|
||||||
public void getPredicateShouldThrowExceptionOnNullRoot() {
|
public void getPredicateShouldThrowExceptionOnNullRoot() {
|
||||||
QueryByExamplePredicateBuilder.getPredicate(null, cb, of(new Person()));
|
QueryByExamplePredicateBuilder.getPredicate(null, cb, of(new Person()), EscapeCharacter.of('\\'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class) // DATAJPA-218
|
@Test(expected = IllegalArgumentException.class) // DATAJPA-218
|
||||||
public void getPredicateShouldThrowExceptionOnNullCriteriaBuilder() {
|
public void getPredicateShouldThrowExceptionOnNullCriteriaBuilder() {
|
||||||
QueryByExamplePredicateBuilder.getPredicate(root, null, of(new Person()));
|
QueryByExamplePredicateBuilder.getPredicate(root, null, of(new Person()), EscapeCharacter.of('\\'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException.class) // DATAJPA-218
|
@Test(expected = IllegalArgumentException.class) // DATAJPA-218
|
||||||
public void getPredicateShouldThrowExceptionOnNullExample() {
|
public void getPredicateShouldThrowExceptionOnNullExample() {
|
||||||
QueryByExamplePredicateBuilder.getPredicate(root, null, null);
|
QueryByExamplePredicateBuilder.getPredicate(root, null, null, EscapeCharacter.of('\\'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATAJPA-218
|
@Test // DATAJPA-218
|
||||||
public void emptyCriteriaListShouldResultTruePredicate() {
|
public void emptyCriteriaListShouldResultTruePredicate() {
|
||||||
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, of(new Person())), equalTo(truePredicate));
|
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, of(new Person()), EscapeCharacter.of('\\')),
|
||||||
|
equalTo(truePredicate));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATAJPA-218
|
@Test // DATAJPA-218
|
||||||
@@ -142,7 +145,8 @@ public class QueryByExamplePredicateBuilderUnitTests {
|
|||||||
Person p = new Person();
|
Person p = new Person();
|
||||||
p.firstname = "foo";
|
p.firstname = "foo";
|
||||||
|
|
||||||
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, of(p)), equalTo(dummyPredicate));
|
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, of(p), EscapeCharacter.of('\\')),
|
||||||
|
equalTo(dummyPredicate));
|
||||||
verify(cb, times(1)).equal(any(Expression.class), eq("foo"));
|
verify(cb, times(1)).equal(any(Expression.class), eq("foo"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,7 +161,7 @@ public class QueryByExamplePredicateBuilderUnitTests {
|
|||||||
exception.expectCause(IsInstanceOf.<Throwable> instanceOf(IllegalArgumentException.class));
|
exception.expectCause(IsInstanceOf.<Throwable> instanceOf(IllegalArgumentException.class));
|
||||||
exception.expectMessage("Unexpected path type");
|
exception.expectMessage("Unexpected path type");
|
||||||
|
|
||||||
QueryByExamplePredicateBuilder.getPredicate(root, cb, of(p));
|
QueryByExamplePredicateBuilder.getPredicate(root, cb, of(p), EscapeCharacter.of('\\'));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test // DATAJPA-218
|
@Test // DATAJPA-218
|
||||||
@@ -167,7 +171,8 @@ public class QueryByExamplePredicateBuilderUnitTests {
|
|||||||
p.firstname = "foo";
|
p.firstname = "foo";
|
||||||
p.age = 2L;
|
p.age = 2L;
|
||||||
|
|
||||||
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, of(p)), equalTo(andPredicate));
|
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, of(p), EscapeCharacter.of('\\')),
|
||||||
|
equalTo(andPredicate));
|
||||||
|
|
||||||
verify(cb, times(1)).equal(any(Expression.class), eq("foo"));
|
verify(cb, times(1)).equal(any(Expression.class), eq("foo"));
|
||||||
verify(cb, times(1)).equal(any(Expression.class), eq(2L));
|
verify(cb, times(1)).equal(any(Expression.class), eq(2L));
|
||||||
@@ -182,11 +187,67 @@ public class QueryByExamplePredicateBuilderUnitTests {
|
|||||||
|
|
||||||
Example<Person> example = of(person, ExampleMatcher.matchingAny());
|
Example<Person> example = of(person, ExampleMatcher.matchingAny());
|
||||||
|
|
||||||
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, example), equalTo(orPredicate));
|
assertThat(QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.of('\\')),
|
||||||
|
equalTo(orPredicate));
|
||||||
|
|
||||||
verify(cb, times(1)).or(ArgumentMatchers.any());
|
verify(cb, times(1)).or(ArgumentMatchers.any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // DATAJPA-1534
|
||||||
|
public void likePatternsGetEscapedContaining() {
|
||||||
|
|
||||||
|
Person person = new Person();
|
||||||
|
person.firstname = "f\\o_o";
|
||||||
|
|
||||||
|
Example<Person> example = of( //
|
||||||
|
person, //
|
||||||
|
ExampleMatcher //
|
||||||
|
.matchingAny() //
|
||||||
|
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING) //
|
||||||
|
);
|
||||||
|
|
||||||
|
QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.of('\\'));
|
||||||
|
|
||||||
|
verify(cb, times(1)).like(any(Expression.class), eq("%f\\\\o\\_o%"), eq('\\'));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATAJPA-1534
|
||||||
|
|
||||||
|
public void likePatternsGetEscapedStarting() {
|
||||||
|
|
||||||
|
Person person = new Person();
|
||||||
|
person.firstname = "f\\o_o";
|
||||||
|
|
||||||
|
Example<Person> example = of( //
|
||||||
|
person, //
|
||||||
|
ExampleMatcher //
|
||||||
|
.matchingAny() //
|
||||||
|
.withStringMatcher(ExampleMatcher.StringMatcher.STARTING) //
|
||||||
|
);
|
||||||
|
|
||||||
|
QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.of('\\'));
|
||||||
|
|
||||||
|
verify(cb, times(1)).like(any(Expression.class), eq("f\\\\o\\_o%"), eq('\\'));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test // DATAJPA-1534
|
||||||
|
public void likePatternsGetEscapedEnding() {
|
||||||
|
|
||||||
|
Person person = new Person();
|
||||||
|
person.firstname = "f\\o_o";
|
||||||
|
|
||||||
|
Example<Person> example = of( //
|
||||||
|
person, //
|
||||||
|
ExampleMatcher //
|
||||||
|
.matchingAny() //
|
||||||
|
.withStringMatcher(ExampleMatcher.StringMatcher.ENDING) //
|
||||||
|
);
|
||||||
|
|
||||||
|
QueryByExamplePredicateBuilder.getPredicate(root, cb, example, EscapeCharacter.of('\\'));
|
||||||
|
|
||||||
|
verify(cb, times(1)).like(any(Expression.class), eq("%f\\\\o\\_o"), eq('\\'));
|
||||||
|
}
|
||||||
|
|
||||||
static class Person {
|
static class Person {
|
||||||
|
|
||||||
@Id Long id;
|
@Id Long id;
|
||||||
|
|||||||
Reference in New Issue
Block a user