[BAEL-9557] - Migrated the spring-rest-query-language to Java 8 idioms

This commit is contained in:
amit2103 2018-10-27 21:10:33 +05:30
parent e31557b2dc
commit 14db73cf02
8 changed files with 142 additions and 82 deletions

View File

@ -1,10 +1,13 @@
package org.baeldung.persistence.dao; package org.baeldung.persistence.dao;
import com.querydsl.core.types.dsl.BooleanExpression;
import org.baeldung.web.util.SearchCriteria;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors;
import org.baeldung.web.util.SearchCriteria;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
public final class MyUserPredicatesBuilder { public final class MyUserPredicatesBuilder {
private final List<SearchCriteria> params; private final List<SearchCriteria> params;
@ -22,21 +25,34 @@ public final class MyUserPredicatesBuilder {
if (params.size() == 0) { if (params.size() == 0) {
return null; return null;
} }
final List<BooleanExpression> predicates = new ArrayList<>(); final List<BooleanExpression> predicates = params.stream().map(param -> {
MyUserPredicate predicate; MyUserPredicate predicate = new MyUserPredicate(param);
for (final SearchCriteria param : params) { return predicate.getPredicate();
predicate = new MyUserPredicate(param); }).filter(predicate -> predicate != null).collect(Collectors.toCollection(ArrayList::new));
final BooleanExpression exp = predicate.getPredicate();
if (exp != null) { BooleanExpression result = Expressions.asBoolean(true).isTrue();
predicates.add(exp); for (BooleanExpression predicate : predicates) {
} result = result.and(predicate);
}
BooleanExpression result = predicates.get(0);
for (int i = 1; i < predicates.size(); i++) {
result = result.and(predicates.get(i));
} }
return result; return result;
} }
static class BooleanExpressionWrapper {
private BooleanExpression result;
public BooleanExpressionWrapper(final BooleanExpression result) {
super();
this.result = result;
}
public BooleanExpression getResult() {
return result;
}
public void setResult(BooleanExpression result) {
this.result = result;
}
}
} }

View File

@ -1,8 +1,6 @@
package org.baeldung.persistence.dao; package org.baeldung.persistence.dao;
import org.baeldung.persistence.model.User; import java.util.List;
import org.baeldung.web.util.SearchCriteria;
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext; import javax.persistence.PersistenceContext;
@ -10,7 +8,10 @@ import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import java.util.List;
import org.baeldung.persistence.model.User;
import org.baeldung.web.util.SearchCriteria;
import org.springframework.stereotype.Repository;
@Repository @Repository
public class UserDAO implements IUserDAO { public class UserDAO implements IUserDAO {
@ -25,20 +26,9 @@ public class UserDAO implements IUserDAO {
final Root r = query.from(User.class); final Root r = query.from(User.class);
Predicate predicate = builder.conjunction(); Predicate predicate = builder.conjunction();
UserSearchQueryCriteriaConsumer searchConsumer = new UserSearchQueryCriteriaConsumer(predicate, builder, r);
for (final SearchCriteria param : params) { params.stream().forEach(searchConsumer);
if (param.getOperation().equalsIgnoreCase(">")) { predicate = searchConsumer.getPredicate();
predicate = builder.and(predicate, builder.greaterThanOrEqualTo(r.get(param.getKey()), param.getValue().toString()));
} else if (param.getOperation().equalsIgnoreCase("<")) {
predicate = builder.and(predicate, builder.lessThanOrEqualTo(r.get(param.getKey()), param.getValue().toString()));
} else if (param.getOperation().equalsIgnoreCase(":")) {
if (r.get(param.getKey()).getJavaType() == String.class) {
predicate = builder.and(predicate, builder.like(r.get(param.getKey()), "%" + param.getValue() + "%"));
} else {
predicate = builder.and(predicate, builder.equal(r.get(param.getKey()), param.getValue()));
}
}
}
query.where(predicate); query.where(predicate);
return entityManager.createQuery(query).getResultList(); return entityManager.createQuery(query).getResultList();

View File

@ -0,0 +1,43 @@
package org.baeldung.persistence.dao;
import java.util.function.Consumer;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import org.baeldung.web.util.SearchCriteria;
public class UserSearchQueryCriteriaConsumer implements Consumer<SearchCriteria>{
private Predicate predicate;
private CriteriaBuilder builder;
private Root r;
public UserSearchQueryCriteriaConsumer(Predicate predicate, CriteriaBuilder builder, Root r) {
super();
this.predicate = predicate;
this.builder = builder;
this.r= r;
}
@Override
public void accept(SearchCriteria param) {
if (param.getOperation().equalsIgnoreCase(">")) {
predicate = builder.and(predicate, builder.greaterThanOrEqualTo(r.get(param.getKey()), param.getValue().toString()));
} else if (param.getOperation().equalsIgnoreCase("<")) {
predicate = builder.and(predicate, builder.lessThanOrEqualTo(r.get(param.getKey()), param.getValue().toString()));
} else if (param.getOperation().equalsIgnoreCase(":")) {
if (r.get(param.getKey()).getJavaType() == String.class) {
predicate = builder.and(predicate, builder.like(r.get(param.getKey()), "%" + param.getValue() + "%"));
} else {
predicate = builder.and(predicate, builder.equal(r.get(param.getKey()), param.getValue()));
}
}
}
public Predicate getPredicate() {
return predicate;
}
}

View File

@ -1,14 +1,15 @@
package org.baeldung.persistence.dao; package org.baeldung.persistence.dao;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.baeldung.persistence.model.User; import org.baeldung.persistence.model.User;
import org.baeldung.web.util.SearchOperation; import org.baeldung.web.util.SearchOperation;
import org.baeldung.web.util.SpecSearchCriteria; import org.baeldung.web.util.SpecSearchCriteria;
import org.springframework.data.jpa.domain.Specification; import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.domain.Specifications; import org.springframework.data.jpa.domain.Specifications;
import java.util.ArrayList;
import java.util.List;
public final class UserSpecificationsBuilder { public final class UserSpecificationsBuilder {
private final List<SpecSearchCriteria> params; private final List<SpecSearchCriteria> params;
@ -48,15 +49,19 @@ public final class UserSpecificationsBuilder {
if (params.size() == 0) if (params.size() == 0)
return null; return null;
Specification<User> result = new UserSpecification(params.get(0)); final List<Specification<User>> specs = params.stream()
.map(UserSpecification::new)
.collect(Collectors.toCollection(ArrayList::new));
Specification<User> result = specs.get(0);
for (int i = 1; i < params.size(); i++) { for (int i = 1; i < params.size(); i++) {
result = params.get(i) result = params.get(i)
.isOrPredicate() .isOrPredicate()
? Specifications.where(result) ? Specifications.where(result)
.or(new UserSpecification(params.get(i))) .or(specs.get(i))
: Specifications.where(result) : Specifications.where(result)
.and(new UserSpecification(params.get(i))); .and(specs.get(i));
} }

View File

@ -1,13 +1,15 @@
package org.baeldung.persistence.dao.rsql; package org.baeldung.persistence.dao.rsql;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import org.springframework.data.jpa.domain.Specifications;
import cz.jirutka.rsql.parser.ast.ComparisonNode; import cz.jirutka.rsql.parser.ast.ComparisonNode;
import cz.jirutka.rsql.parser.ast.LogicalNode; import cz.jirutka.rsql.parser.ast.LogicalNode;
import cz.jirutka.rsql.parser.ast.LogicalOperator; import cz.jirutka.rsql.parser.ast.LogicalOperator;
import cz.jirutka.rsql.parser.ast.Node; import cz.jirutka.rsql.parser.ast.Node;
import org.springframework.data.jpa.domain.Specifications;
import java.util.ArrayList;
import java.util.List;
public class GenericRsqlSpecBuilder<T> { public class GenericRsqlSpecBuilder<T> {
@ -22,29 +24,24 @@ public class GenericRsqlSpecBuilder<T> {
} }
public Specifications<T> createSpecification(final LogicalNode logicalNode) { public Specifications<T> createSpecification(final LogicalNode logicalNode) {
final List<Specifications<T>> specs = new ArrayList<Specifications<T>>();
Specifications<T> temp; List<Specifications<T>> specs = logicalNode.getChildren()
for (final Node node : logicalNode.getChildren()) { .stream()
temp = createSpecification(node); .map(node -> createSpecification(node))
if (temp != null) { .filter(specifications -> specifications != null)
specs.add(temp); .collect(Collectors.toCollection(ArrayList::new));
Specifications<T> initialSpec = specs.stream().findFirst().get();
Specifications<T> result = specs.stream().skip(1).reduce(initialSpec, (firstSpec, secondSpec) -> {
if (logicalNode.getOperator() == LogicalOperator.AND) {
return Specifications.where(firstSpec).and(secondSpec);
} else if (logicalNode.getOperator() == LogicalOperator.OR) {
return Specifications.where(firstSpec).or(secondSpec);
} }
} return firstSpec;
});
Specifications<T> result = specs.get(0);
if (logicalNode.getOperator() == LogicalOperator.AND) {
for (int i = 1; i < specs.size(); i++) {
result = Specifications.where(result).and(specs.get(i));
}
}
else if (logicalNode.getOperator() == LogicalOperator.OR) {
for (int i = 1; i < specs.size(); i++) {
result = Specifications.where(result).or(specs.get(i));
}
}
return result; return result;
} }

View File

@ -1,14 +1,17 @@
package org.baeldung.persistence.dao.rsql; package org.baeldung.persistence.dao.rsql;
import cz.jirutka.rsql.parser.ast.ComparisonOperator; import java.util.ArrayList;
import org.springframework.data.jpa.domain.Specification; import java.util.List;
import java.util.stream.Collectors;
import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery; import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate; import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root; import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.List; import org.springframework.data.jpa.domain.Specification;
import cz.jirutka.rsql.parser.ast.ComparisonOperator;
public class GenericRsqlSpecification<T> implements Specification<T> { public class GenericRsqlSpecification<T> implements Specification<T> {
@ -71,18 +74,22 @@ public class GenericRsqlSpecification<T> implements Specification<T> {
// === private // === private
private List<Object> castArguments(final Root<T> root) { private List<Object> castArguments(final Root<T> root) {
final List<Object> args = new ArrayList<Object>();
final Class<? extends Object> type = root.get(property).getJavaType(); final Class<? extends Object> type = root.get(property).getJavaType();
for (final String argument : arguments) { final List<Object> args = arguments.stream().map(arg -> {
Object obj;
if (type.equals(Integer.class)) { if (type.equals(Integer.class)) {
args.add(Integer.parseInt(argument)); obj = Integer.parseInt(arg);
} else if (type.equals(Long.class)) { } else if (type.equals(Long.class)) {
args.add(Long.parseLong(argument)); obj = Long.parseLong(arg);
} else { } else {
args.add(argument); obj = arg;
} }
} return obj;
}).collect(Collectors.toCollection(ArrayList::new));
return args; return args;
} }

View File

@ -2,6 +2,7 @@ package org.baeldung.web.controller;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
@ -63,7 +64,7 @@ public class UserController {
@ResponseBody @ResponseBody
public List<User> findAll(@RequestParam(value = "search", required = false) String search) { public List<User> findAll(@RequestParam(value = "search", required = false) String search) {
List<SearchCriteria> params = new ArrayList<SearchCriteria>(); List<SearchCriteria> params = new ArrayList<SearchCriteria>();
if (search != null) { if (Optional.ofNullable(search).isPresent()) {
Pattern pattern = Pattern.compile("(\\w+?)(:|<|>)(\\w+?),"); Pattern pattern = Pattern.compile("(\\w+?)(:|<|>)(\\w+?),");
Matcher matcher = pattern.matcher(search + ","); Matcher matcher = pattern.matcher(search + ",");
while (matcher.find()) { while (matcher.find()) {
@ -126,7 +127,7 @@ public class UserController {
@ResponseBody @ResponseBody
public Iterable<MyUser> findAllByQuerydsl(@RequestParam(value = "search") String search) { public Iterable<MyUser> findAllByQuerydsl(@RequestParam(value = "search") String search) {
MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder(); MyUserPredicatesBuilder builder = new MyUserPredicatesBuilder();
if (search != null) { if (Optional.ofNullable(search).isPresent()) {
Pattern pattern = Pattern.compile("(\\w+?)(:|<|>)(\\w+?),"); Pattern pattern = Pattern.compile("(\\w+?)(:|<|>)(\\w+?),");
Matcher matcher = pattern.matcher(search + ","); Matcher matcher = pattern.matcher(search + ",");
while (matcher.find()) { while (matcher.find()) {

View File

@ -1,5 +1,6 @@
package org.baeldung.web.util; package org.baeldung.web.util;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Deque; import java.util.Deque;
import java.util.HashMap; import java.util.HashMap;
@ -45,7 +46,7 @@ public class CriteriaParser {
Deque<Object> output = new LinkedList<>(); Deque<Object> output = new LinkedList<>();
Deque<String> stack = new LinkedList<>(); Deque<String> stack = new LinkedList<>();
for (String token : searchParam.split("\\s+")) { Arrays.stream(searchParam.split("\\s+")).forEach(token -> {
if (ops.containsKey(token)) { if (ops.containsKey(token)) {
while (!stack.isEmpty() && isHigerPrecedenceOperator(token, stack.peek())) while (!stack.isEmpty() && isHigerPrecedenceOperator(token, stack.peek()))
output.push(stack.pop() output.push(stack.pop()
@ -65,7 +66,7 @@ public class CriteriaParser {
output.push(new SpecSearchCriteria(matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(4), matcher.group(5))); output.push(new SpecSearchCriteria(matcher.group(1), matcher.group(2), matcher.group(3), matcher.group(4), matcher.group(5)));
} }
} }
} });
while (!stack.isEmpty()) while (!stack.isEmpty())
output.push(stack.pop()); output.push(stack.pop());