如何从 Spring 查询 dsl 谓词中提取表达式路径和值?

How to extract expression path and value from Spring query dsl Predicate?

我在我的一个项目中使用 Spring 查询 DSL。查询 DSL 谓词是在 Controller 端点上自动创建的,就像这样

public ResponseEntity<MyDTO> agentWinLoseSA(
        @QuerydslPredicate(root = MyObject.class) Predicate filter, Pageable pageable) throws URISyntaxException

它是通过这样的查询参数提供的

https://myhost:port/api/myobj?person.name=Dave

有没有办法从创建的谓词中提取表达式(路径=值)?

我找到了如何从 Predicate 对象中提取表达式路径,但我找不到有意义的方法来提取该路径下的值。

路径可以像这样提取(对于当前示例,它将是 person.name)

    List<Expression<?>> expressions = ((PredicateOperation) filter).getArgs();
    for (Expression<?> expression : expressions)
    {
        String expressionPath = expression.accept(PathExtractor.DEFAULT, null).toString();
    }

我想,这应该通过具有提取路径的访问者以某种方式完成,但我不知道如何做。

更新。我找到了解决方案:

import com.querydsl.core.types.Constant;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.FactoryExpression;
import com.querydsl.core.types.Operation;
import com.querydsl.core.types.ParamExpression;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.SubQueryExpression;
import com.querydsl.core.types.TemplateExpression;
import com.querydsl.core.types.Visitor;


public class ConstantExtractor implements Visitor<Constant<?>, Void>
{

    public static final ConstantExtractor DEFAULT = new ConstantExtractor();


    private ConstantExtractor()
    {
    }


    @Override
    public Constant<?> visit(Constant<?> expr, Void context)
    {
        return expr;
    }


    @Override
    public Constant<?> visit(FactoryExpression<?> expr, Void context)
    {
        return visit(expr.getArgs());
    }


    @Override
    public Constant<?> visit(Operation<?> expr, Void context)
    {
        return visit(expr.getArgs());
    }


    @Override
    public Constant<?> visit(ParamExpression<?> expr, Void context)
    {
        return null;
    }


    @Override
    public Constant<?> visit(Path<?> expr, Void context)
    {
        return null;
    }


    @Override
    public Constant<?> visit(SubQueryExpression<?> expr, Void context)
    {
        return null;
    }


    @Override
    public Constant<?> visit(TemplateExpression<?> expr, Void context)
    {
        return visit(expr.getArgs());
    }


    private Constant<?> visit(List<?> exprs)
    {
        for (Object e : exprs)
        {
            if (e instanceof Expression)
            {
                Constant<?> constant = ((Expression<?>) e).accept(this, null);
                if (constant != null)
                {
                    return constant;
                }
            }
        }

        return null;
    }

   }

用法很简单:

Constant constant = expression.accept(ConstantExtractor.DEFAULT, null);

我找到了解决方案。下面的代码首先提取表达式的常量值,它使用它自己的访问者。可以轻松修改解决方案以使用一些常量集合(因为有时同一路径下有多个值,例如,在日期范围内)

import com.querydsl.core.types.Constant;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.FactoryExpression;
import com.querydsl.core.types.Operation;
import com.querydsl.core.types.ParamExpression;
import com.querydsl.core.types.Path;
import com.querydsl.core.types.SubQueryExpression;
import com.querydsl.core.types.TemplateExpression;
import com.querydsl.core.types.Visitor;


public class ConstantExtractor implements Visitor<Constant<?>, Void>
{

    public static final ConstantExtractor DEFAULT = new ConstantExtractor();


    private ConstantExtractor()
    {
    }


    @Override
    public Constant<?> visit(Constant<?> expr, Void context)
    {
        return expr;
    }


    @Override
    public Constant<?> visit(FactoryExpression<?> expr, Void context)
    {
        return visit(expr.getArgs());
    }


    @Override
    public Constant<?> visit(Operation<?> expr, Void context)
    {
        return visit(expr.getArgs());
    }


    @Override
    public Constant<?> visit(ParamExpression<?> expr, Void context)
    {
        return null;
    }


    @Override
    public Constant<?> visit(Path<?> expr, Void context)
    {
        return null;
    }


    @Override
    public Constant<?> visit(SubQueryExpression<?> expr, Void context)
    {
        return null;
    }


    @Override
    public Constant<?> visit(TemplateExpression<?> expr, Void context)
    {
        return visit(expr.getArgs());
    }


    private Constant<?> visit(List<?> exprs)
    {
        for (Object e : exprs)
        {
            if (e instanceof Expression)
            {
                Constant<?> constant = ((Expression<?>) e).accept(this, null);
                if (constant != null)
                {
                    return constant;
                }
            }
        }

        return null;
    }

   }

和用法:

List<Expression<?>> expressions = ((PredicateOperation) filter).getArgs();
for (Expression<?> expression : expressions)
{
    String expressionPath = expression.accept(PathExtractor.DEFAULT, null).toString();
    Constant constant = expression.accept(ConstantExtractor.DEFAULT, null);
}