Java JPASpecificationExecutor查找其中的null
我设置了一个JPA规范搜索,它主要来源于。总的来说,我有一个针对JavaREST服务的高级搜索系统,它允许一些非常广泛的搜索选项,而简单的示例查询是不允许的。我在这里遇到的问题是,我似乎无法让它用于搜索空值。目前,在null上搜索时,我只收到返回的空列表-[]。即使存在空值。由于没有错误,这就更难追踪了。我假设它忽略了null,而不是搜索它。在引号中使用null也没有帮助。我找了好几个小时,但似乎找不到解决办法。我希望解决方案非常简单,但我只是没有看到 这个解析器是主要关注的领域。为了视觉起见,我在这里硬编码了一个空值。基本上,当启动搜索以检查空值时,预期结果如下:Java JPASpecificationExecutor查找其中的null,java,spring,spring-boot,jpa,spring-data-jpa,Java,Spring,Spring Boot,Jpa,Spring Data Jpa,我设置了一个JPA规范搜索,它主要来源于。总的来说,我有一个针对JavaREST服务的高级搜索系统,它允许一些非常广泛的搜索选项,而简单的示例查询是不允许的。我在这里遇到的问题是,我似乎无法让它用于搜索空值。目前,在null上搜索时,我只收到返回的空列表-[]。即使存在空值。由于没有错误,这就更难追踪了。我假设它忽略了null,而不是搜索它。在引号中使用null也没有帮助。我找了好几个小时,但似乎找不到解决办法。我希望解决方案非常简单,但我只是没有看到 这个解析器是主要关注的领域。为了视觉起见,
output.push(new SearchCriteria("someProperty", "EQUALITY", null, "", ""));
在本例中,最后两项无关紧要。如果将null替换为“”,则在查找空字符串或带空格的字符串时,此搜索会起作用。有人知道如何让这个规范与null一起工作吗?下面是包含上述片段和执行服务调用的解析器
分析器
public Deque<?> parse(String searchParam) {
Deque<Object> output = new LinkedList<>();
Deque<String> stack = new LinkedList<>();
Arrays.stream(searchParam.split("\\|")).forEach(token -> {
if (ops.containsKey(token)) {
while (!stack.isEmpty() && isHigherPrecedenceOperator(token, stack.peek())) {
output.push(stack.pop()
.equalsIgnoreCase(SearchOperation.OR_OPERATOR) ? SearchOperation.OR_OPERATOR : SearchOperation.AND_OPERATOR);
}
stack.push(token.equalsIgnoreCase(SearchOperation.OR_OPERATOR) ? SearchOperation.OR_OPERATOR : SearchOperation.AND_OPERATOR);
} else if (token.equals(SearchOperation.LEFT_PARANTHESIS)) {
stack.push(SearchOperation.LEFT_PARANTHESIS);
} else if (token.equals(SearchOperation.RIGHT_PARANTHESIS)) {
while (!stack.peek().equals(SearchOperation.LEFT_PARANTHESIS)) {
output.push(stack.pop());
}
stack.pop();
} else {
Matcher matcher = criteriaRegex.matcher(token);
System.out.println(matcher.pattern());
// There is two output.push items below because matcher.find() progresses an iterator,
// but is the best way to know if a match was made.
if(matcher.find()){
output.push(new SearchCriteria(matcher.group(1), matcher.group(2), matcher.group(4),
matcher.group(3), matcher.group(5)
));
while (matcher.find()) {
output.push(new SearchCriteria(matcher.group(1), matcher.group(2), matcher.group(4),
matcher.group(3), matcher.group(5)
));
}
}else{
Matcher emptyStringSearch = criteriaEmptyRegex.matcher(token);
if(emptyStringSearch.find()) {
output.push(new SearchCriteria(emptyStringSearch.group(1), emptyStringSearch.group(2),
null, "", ""));
while (emptyStringSearch.find()) {
output.push(new SearchCriteria(emptyStringSearch.group(1), emptyStringSearch.group(2),
null, "", ""));
}
}
}
}
});
while (!stack.isEmpty()) {
output.push(stack.pop());
}
return output;
}
findAll调用上方的注释指示调用的spec值。无论键([])如何,每次都返回一个空列表
/**
* Advanced search using a specification and parser to allow for multiple predicate searches
* @param search String representation of a search ex. ( firstName~ick AND lastName:Sanders ) OR ( firstName:henry )
* @param pageable
* @return returns a paged list of Dashboard view entity with link headers
*/
@Override
public Page<DashboardViewEntity> search(String search, Pageable pageable) {
SearchCriteriaParser parser = new SearchCriteriaParser();
GenericSpecificationBuilder<Object> specBuilder = new GenericSpecificationBuilder<>();
Specification<Object> spec = specBuilder.build(parser.parse(search), GenericSpecification::new);
//spec.criteria = SearchCriteria(key=firstName, operation=EQUALITY, value=null, orPredicate=false)
Page<DashboardViewEntity> cases = recordRepo.findAll(spec, pageable);
return cases;
}
public SearchCriteria(String key, String operation, String value, String prefix, String suffix) {
SearchOperation op = SearchOperation.getSimpleOperation(operation.charAt(0));
if (op != null) {
// TODO: update to allow prefix/suffix with negation
if (op == SearchOperation.EQUALITY) { // the operation may be complex operation
final boolean startWithAsterisk = prefix != null && prefix.contains(SearchOperation.ZERO_OR_MORE_REGEX);
final boolean endWithAsterisk = suffix != null && suffix.contains(SearchOperation.ZERO_OR_MORE_REGEX);
if (startWithAsterisk && endWithAsterisk) {
op = SearchOperation.CONTAINS;
} else if (startWithAsterisk) {
op = SearchOperation.ENDS_WITH;
} else if (endWithAsterisk) {
op = SearchOperation.STARTS_WITH;
}
}
}
this.key = key;
this.operation = op;
this.value = value;
}