1
16 package org.springframework.data.jpa.domain;
17
18 import java.io.Serializable;
19
20 import javax.persistence.criteria.CriteriaBuilder;
21 import javax.persistence.criteria.CriteriaQuery;
22 import javax.persistence.criteria.Predicate;
23 import javax.persistence.criteria.Root;
24
25 import org.springframework.lang.Nullable;
26
27
36 class SpecificationComposition {
37
38 interface Combiner extends Serializable {
39 Predicate combine(CriteriaBuilder builder, @Nullable Predicate lhs, @Nullable Predicate rhs);
40 }
41
42 static <T> Specification<T> composed(@Nullable Specification<T> lhs, @Nullable Specification<T> rhs,
43 Combiner combiner) {
44
45 return (root, query, builder) -> {
46
47 Predicate otherPredicate = toPredicate(lhs, root, query, builder);
48 Predicate thisPredicate = toPredicate(rhs, root, query, builder);
49
50 if (thisPredicate == null) {
51 return otherPredicate;
52 }
53
54 return otherPredicate == null ? thisPredicate : combiner.combine(builder, thisPredicate, otherPredicate);
55 };
56 }
57
58 @Nullable
59 private static <T> Predicate toPredicate(@Nullable Specification<T> specification, Root<T> root, CriteriaQuery<?> query,
60 CriteriaBuilder builder) {
61 return specification == null ? null : specification.toPredicate(root, query, builder);
62 }
63 }
64