Ognl表达式分析-使用apache commons-ognl 修改源码

导读

本文介绍使用commons-ognl来对ongl表达式的AST树进行分析,对想要在OGNL表达式中提取出部分信息的需求有帮助。 为何用commons-ognl呢?是由于commons-ognl比原始的ognl多了一个accept方法的支持(不支持accept树)。 另外本文的方法会简单修改commons-ognl的源码来实现。java

得到commons-ognl

commons-ognl在github上有仓库,可直接克隆。node

git clone https://github.com/apache/commons-ognl.git

源码改造

存在一个org.apache.commons.ognl.Node接口,此接口是全部Ognl表达式AST树中的基本接口,全部类型的节点都是org.apache.commons.ognl.SimpleNode类的派生类。git

查看org.apache.commons.ognl.Node接口, 包含一个accept方法,定义看图:github

查看accept方法的实现,竟只对visitor回调了当前节点,并无visit其树枝下的子节点(证明导读部分)。shell

咱们想要的是分析AST树,而不单单是独立的节点。 因此修改一下源码,java8能够直接写在Node接口中:apache

default <R, P> R acceptTree(NodeVisitor<? extends R, ? super P> visitor, P data)throws OgnlException{
        R result = accept(visitor, data);
        for (int i = 0; i < jjtGetNumChildren(); i++) {
            result = jjtGetChild(i).acceptTree(visitor, data);
        }
        return result;
    }

添加一个adapter类NodeVisitorAdapterapp

package org.apache.commons.ognl;

public class NodeVisitorAdapter<R,P> implements NodeVisitor<R,P>{
    @Override
    public R visit(ASTSequence node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTAssign node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTTest node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTOr node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTAnd node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTBitOr node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTXor node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTBitAnd node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTEq node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTNotEq node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTLess node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTGreater node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTLessEq node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTGreaterEq node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTIn node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTNotIn node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTShiftLeft node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTShiftRight node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTUnsignedShiftRight node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTAdd node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTSubtract node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTMultiply node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTDivide node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTRemainder node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTNegate node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTBitNegate node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTNot node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTInstanceof node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTChain node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTEval node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTConst node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTThisVarRef node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTRootVarRef node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTVarRef node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTList node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTMap node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTKeyValue node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTStaticField node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTCtor node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTProperty node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTStaticMethod node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTMethod node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTProject node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTSelect node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTSelectFirst node, P data) throws OgnlException {
        return null;
    }

    @Override
    public R visit(ASTSelectLast node, P data) throws OgnlException {
        return null;
    }
}

java8如下须要将acceptTree写在SimpleNode中,使用时须要强制转换,这里就再也不单独把代码列出来了。maven

使用

完成了改造就能够visit整颗树了,如今来了一个需求,把Ognl中全部使用到的变量都get出来。 上代码片段ide

package org.apache.commons.ognl;

import org.junit.Test;

import java.util.HashSet;
import java.util.Set;

public class AstVisitorTest {

    @Test
    public void astVisitorTest() throws OgnlException {
        String ognlExpr = "map1.keyv1.name=='name1'";
        Node rootNode = (Node) Ognl.parseExpression(ognlExpr);
        Set<String> variables = new HashSet<>();
        rootNode.acceptTree(new NodeVisitorAdapter<Set<String>, Set<String>>() {
            @Override
            public Set<String> visit(ASTProperty node, Set<String> data) throws OgnlException {
                data.add(String.valueOf(node));
                return data;
            }
        }, variables);
        System.out.println(new StringBuilder(1 << 10).append("variables  \n\t").append(variables));
    }
}

运行结果:ui

[map1, name, keyv1]

后记说明

修改pom.xml修改成默认为java8

/properties/

<maven.compile.source>1.8</maven.compile.source>
    <maven.compile.target>1.8</maven.compile.target>

部分节点的访问限制为 package public ,如(org.apache.commons.ognl.ASTAndorg.apache.commons.ognl.ASTNot等),须要将visitor放在org.apache.commons.ognl包下。

相关文章
相关标签/搜索