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包下。

相關文章
相關標籤/搜索