Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/318.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 从树构建JPA规范_Java_Algorithm_Spring Data Jpa_Jpa Criteria - Fatal编程技术网

Java 从树构建JPA规范

Java 从树构建JPA规范,java,algorithm,spring-data-jpa,jpa-criteria,Java,Algorithm,Spring Data Jpa,Jpa Criteria,我创建了一个API,允许用户使用树构建查询。该树是从SearchOperationRequest类构建的 @Data @ApiModel(value = "SearchOperationRequest", description = "Condition for the query") public class SearchOperationRequest { @ApiModelProperty(value = "Conditional statement for the where

我创建了一个API,允许用户使用树构建查询。该树是从
SearchOperationRequest
类构建的

@Data
@ApiModel(value = "SearchOperationRequest", description = "Condition for the query")
public class SearchOperationRequest {

    @ApiModelProperty(value = "Conditional statement for the where clause", allowableValues = "EQUALS, NOT_EQUALS, GREATER_THAN, LESS_THAN, LIKE, STARTS_WITH, ENDS_WITH, CONTAINS")
    private SearchConditionOperation condition;

    @ApiModelProperty(value = "Column name to be searched on")
    private String column;

    @ApiModelProperty(value = "Value of column")
    private Object value;

    @ApiModelProperty(value = "Value of OR / AND")
    private SearchComparator comparator;

    @ApiModelProperty(value = "Left node of comparator condition")
    private SearchOperationRequest left;

    @ApiModelProperty(value = "Right node of comparator condition")
    private SearchOperationRequest right;

    public boolean isTreeLeaf() {
        return left == null && right == null;
    }

    public boolean isComparator() {
        return comparator != null;
    }
}
因此,从这个示例中,我可以创建一个
SearchOperationRequest
,它要求所有,其中hidden=false和X=88

"searchOperation": {
    "left": {
        "column": "Hidden",
        "condition": "EQUALS",
        "value": false
    },
    "comparator": "AND",
    "right": {
        "left": {
            "column": "X",
            "condition": "EQUALS",
            "value": 88
        },
        "comparator": "AND"
    }
}
此请求使用通用规范生成器构建到规范中

public class GenericSpecificationsBuilder<U> {

    public Specification<U> buildSpecificationFromSearchOperationRequest(SearchOperationRequest root, Function<SpecificationSearchCriteria, Specification<U>> converter) {

        Stack<SearchOperationRequest> stack = new Stack<>();

        Stack<SearchOperationRequest> comparatorStack = new Stack<>();
        Deque<Specification<U>> specStack = new LinkedList<>();

        SearchOperationRequest pointer = root;

        while (pointer != null || !stack.empty()) {

            if (pointer.isTreeLeaf()) {
                specStack.push(converter.apply(new SpecificationSearchCriteria(pointer.getColumn(), pointer.getCondition(), pointer.getValue())));
            }

            if (pointer.isComparator()) {
                comparatorStack.push(pointer);
            }

            if (pointer.getRight() != null) {
                stack.push(pointer.getRight());
            }

            if (pointer.getLeft() != null) {
                pointer.setRight(pointer.getLeft());
                pointer.setLeft(null);
            } else if (!stack.empty()) {
                SearchOperationRequest temp = stack.pop();
                pointer.setRight(temp);
            }

            pointer = pointer.getRight();
        }


        while (specStack.size() <= comparatorStack.size()) {
            comparatorStack.pop();
        }

        while (!comparatorStack.empty()) {

            SearchOperationRequest searchOperationRequest = comparatorStack.pop();

            Specification<U> operand1 = specStack.pop();
            Specification<U> operand2 = specStack.pop();
            if (searchOperationRequest.getComparator().equals(SearchComparator.AND)) {
                specStack.push(Specification.where(operand1)
                        .and(operand2));
            } else if (searchOperationRequest.getComparator().equals(SearchComparator.OR)) {
                specStack.push(Specification.where(operand1)
                        .or(operand2));
            }
        }


        return specStack.pop();
    }
}
但它不适用于构建更复杂的树,在这些树中,大括号中的条件应该优先并首先执行

WHERE (X = 6 OR Z = 9) AND (T=6 OR H=8)
这个更复杂的
SearchOperationRequest
的模型是:

"searchOperation": {
    "left": {
        "left": {
            "column": "X",
            "condition": "EQUALS",
            "value": 6
        },
        "comparator": "AND",
        "right": {
            "column": "Z",
            "condition": "EQUALS",
            "value": 9
        }
    },
    "comparator": "AND",
    "right": {
        "left": {
            "column": "T",
            "condition": "EQUALS",
            "value": 6
        },
        "comparator": "AND",
        "right": {
            "column": "H",
            "condition": "EQUALS",
            "value": 8
        }
    }
}

如何修改我的
genericsspecificationsbuilder
以处理更复杂的
SearchOperationRequest
树?

让我们使用示例树了解执行流程

         AND
      /       \
  leftOR     rightOR
  /    \     /    \ 
X=6   Z=9  T=6   H=8
当我们退出第一个
while
循环时,我们的堆栈如下所示:

stack = {}
comparatorStack = { AND, leftOR, rightOR }
specStack = { X=6, Z=9, T=6, H=8 }
相同的状态进入最后的
,而
循环

while (!comparatorStack.empty()) {

    SearchOperationRequest searchOperationRequest = comparatorStack.pop();

    Specification<U> operand1 = specStack.pop();
    Specification<U> operand2 = specStack.pop();
    if (searchOperationRequest.getComparator().equals(SearchComparator.AND)) {
        specStack.push(Specification.where(operand1)
                .and(operand2));
    } else if (searchOperationRequest.getComparator().equals(SearchComparator.OR)) {
        specStack.push(Specification.where(operand1)
                .or(operand2));
    }
}
此代码的问题是您正在更改树中的节点。在第一个示例中,指针一度指向节点:

    Z=9      
  /     \ 
null   rightOR
这看起来不对。您可以使用队列()免费获取所需的顺序,而不是使用堆栈()分解树

这是否解决了将每个逻辑运算符(
比较器
)应用于正确操作数的问题?不完全是这样,为了能够解决下面两种布局,我们可以在不同的工作流中分解运算符和操作数,而不是将它们全部分解在一起

         AND                    |                    rootAND                 
      /       \                 |                  /         \    
  leftOR     rightOR            |              leftOR       rightOR  
  /    \     /    \             |              /    \       /    \   
X=6   Z=9  T=6   H=8            |            X=6    AND    Z=9   H=8   
                                |                 /    \      
                                |               T=6   Y=3 
解决方案

文章中第一个类似json的表示形式的布局不合逻辑,因为逻辑运算符需要同时对左操作数和右操作数进行操作。相反,你有:

"right": {
    "left": {
        "column": "X",
        "condition": "EQUALS",
        "value": 88
    },
    "comparator": "AND"
}

让我们考虑对称表示的解决方案,其中每个逻辑运算符都有左和右操作数。

首先,我们先逐级处理树的宽度。同时,我们将每个
比较器
放在一个堆栈上,以便在第二个
while
循环中首先取出最后一个

while (!comparatorStack.empty()) {

    SearchOperationRequest searchOperationRequest = comparatorStack.pop();

    Specification<U> operand1 = specStack.pop();
    Specification<U> operand2 = specStack.pop();
    if (searchOperationRequest.getComparator().equals(SearchComparator.AND)) {
        specStack.push(Specification.where(operand1)
                .and(operand2));
    } else if (searchOperationRequest.getComparator().equals(SearchComparator.OR)) {
        specStack.push(Specification.where(operand1)
                .or(operand2));
    }
}
在第二个循环中,我们使用一个新的
队列
来存储“中间结果”,同时返回到根

Queue<SearchOperationRequest> queue = new LinkedList<>();
Deque<SearchOperationRequest> comparatorStack = new LinkedList<>();

if (root == null || !root.isComparator()) return;
queue.add(root);
while(!queue.isEmpty()){
    SearchOperationRequest node = queue.poll();
    comparatorStack.push(node);
    if(node.left != null && node.left.isComparator()) queue.add(node.left);
    if(node.right != null && node.right.isComparator()) queue.add(node.right);
}

Queue<Specification> specQueue = new LinkedList<>();
while(!comparatorStack.isEmpty()){
    SearchOperationRequest comparator = comparatorStack.pop();
    // reverse operand order so already computed values are polled correctly
    Specification operand2; 
    SearchOperationRequest pointer = comparator.getRight();
    if(pointer.isTreeLeaf()) {
        operand2 = converter.apply(new SpecificationSearchCriteria(pointer.getColumn(), pointer.getCondition(), pointer.getValue()));
    } else {
        operand2 = specQueue.poll();
    }
    Specification operand1; 
    pointer = comparator.getLeft();
    if(pointer.isTreeLeaf()) {
        operand1 = converter.apply(new SpecificationSearchCriteria(pointer.getColumn(), pointer.getCondition(), pointer.getValue()));
    } else {
        operand1 = specQueue.poll();
    }
    if (comparator.equals(SearchComparator.AND)) {
        specQueue.add(Specification.where(operand1).and(operand2));
    } else if (comparator.equals(SearchComparator.OR)) {
        specQueue.add(Specification.where(operand1).or(operand2));
    }
} 

return specQueue.poll();
Queue Queue=newlinkedlist();
Deque comparatorStack=新链接列表();
if(root==null | |!root.isComparator())返回;
添加(根);
而(!queue.isEmpty()){
SearchOperationRequest节点=queue.poll();
比较器堆栈推送(节点);
if(node.left!=null&&node.left.isComparator())queue.add(node.left);
如果(node.right!=null&&node.right.isComparator())queue.add(node.right);
}
Queue specQueue=new LinkedList();
而(!comparatorStack.isEmpty()){
SearchOperationRequest comparator=comparatorStack.pop();
//反转操作数顺序,以便正确轮询已计算的值
规格说明2;
SearchOperationRequest指针=comparator.getRight();
if(指针.isTreeLeaf()){
操作数2=converter.apply(新规范SearchCriteria(pointer.getColumn()、pointer.getCondition()、pointer.getValue());
}否则{
操作数2=specQueue.poll();
}
规格说明1;
指针=比较器.getLeft();
if(指针.isTreeLeaf()){
操作数1=converter.apply(新规范SearchCriteria(pointer.getColumn()、pointer.getCondition()、pointer.getValue());
}否则{
操作数1=specQueue.poll();
}
if(比较器等于(搜索比较器与)){
specQueue.add(Specification.where(操作数1.)和(操作数2));
}else if(comparator.equals(SearchComparator.OR)){
specQueue.add(Specification.where(操作数1).或(操作数2));
}
} 
返回specQueue.poll();

我还没有测试代码,但您应该能够提取(并重构)工作流。

看起来我没有将根
比较器
放在堆栈上,修复了代码。你让它工作了吗?@ingen先做了几个测试用例,它工作得很好。
Queue<SearchOperationRequest> queue = new LinkedList<>();
Deque<SearchOperationRequest> comparatorStack = new LinkedList<>();

if (root == null || !root.isComparator()) return;
queue.add(root);
while(!queue.isEmpty()){
    SearchOperationRequest node = queue.poll();
    comparatorStack.push(node);
    if(node.left != null && node.left.isComparator()) queue.add(node.left);
    if(node.right != null && node.right.isComparator()) queue.add(node.right);
}

Queue<Specification> specQueue = new LinkedList<>();
while(!comparatorStack.isEmpty()){
    SearchOperationRequest comparator = comparatorStack.pop();
    // reverse operand order so already computed values are polled correctly
    Specification operand2; 
    SearchOperationRequest pointer = comparator.getRight();
    if(pointer.isTreeLeaf()) {
        operand2 = converter.apply(new SpecificationSearchCriteria(pointer.getColumn(), pointer.getCondition(), pointer.getValue()));
    } else {
        operand2 = specQueue.poll();
    }
    Specification operand1; 
    pointer = comparator.getLeft();
    if(pointer.isTreeLeaf()) {
        operand1 = converter.apply(new SpecificationSearchCriteria(pointer.getColumn(), pointer.getCondition(), pointer.getValue()));
    } else {
        operand1 = specQueue.poll();
    }
    if (comparator.equals(SearchComparator.AND)) {
        specQueue.add(Specification.where(operand1).and(operand2));
    } else if (comparator.equals(SearchComparator.OR)) {
        specQueue.add(Specification.where(operand1).or(operand2));
    }
} 

return specQueue.poll();