在java中使用ScriptEngine,如何提取函数列表?

时间:2013-03-21 11:44:50

标签: java javascript scriptengine

使用Jsoup,我在html文件中提取JavaScript部分。并将其存储为java String Object。

我想使用 javax.script.ScriptEngine

在js的函数中提取函数列表,变量列表

JavaScript部分有几个功能部分。

离)

function a() {
var a_1;
var a_2
...
}

function b() {
    var b_1;
    var b_2;
...
}

function c() {
    var c_1;
    var c_2;
...
}

我的目标就在下面。

列出funcList

一 b ç

列出varListA

A_1 a2 ...

列出varListB

B_1 B_2 ...

列出varListC

C_1 C_2 ...

如何提取功能列表和变量列表(或可能是值)?

3 个答案:

答案 0 :(得分:0)

我认为你可以通过在引擎中加载javascript后使用javascript自省来实现这一点 - 例如功能:

ScriptEngine engine;
// create the engine and have it load your javascript
Bindings bind = engine.getBindings(ScriptContext.ENGINE_SCOPE);
Set<String> allAttributes = bind.keySet();
Set<String> allFunctions = new HashSet<String>();
for ( String attr : allAttributes ) {
    if ( "function".equals( engine.eval("typeof " + attr) ) ) {
        allFunctions.add(attr);
    }
}
System.out.println(allFunctions);

我还没有找到一种方法来提取函数(局部变量)中的变量,而无需深入研究javascript脚本引擎的内部机制(因此使用不安全)。

答案 1 :(得分:0)

这很棘手。 ScriptEngine API似乎不适合检查代码。所以,对于instance ofcast运算符,我有这种非常难看的解决方案。

       Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
       for (Map.Entry<String, Object> scopeEntry : bindings.entrySet()) {
           Object value = scopeEntry.getValue();
           String name = scopeEntry.getKey();
           if (value instanceof NativeFunction) {
               log.info("Function -> " + name);
               NativeFunction function = NativeFunction.class.cast(value);
               DebuggableScript debuggableFunction = function.getDebuggableView();
               for (int i = 0; i < debuggableFunction.getParamAndVarCount(); i++) {
                   log.info("First level arg: " + debuggableFunction.getParamOrVarName(i));
               }
           } else if (value instanceof Undefined
                   || value instanceof String
                   || value instanceof Number) {
               log.info("Global arg -> " + name);
           }
       }

答案 2 :(得分:0)

我有类似的问题。也许这对其他人有帮助。 我用凹槽作为脚本朗。我的任务是从脚本中检索所有可调用的函数。然后按照某些标准过滤此功能。

不幸的是,这种方法仅适用于groovy ...

获取脚本引擎

public ScriptEngine getEngine() throws Exception {
    if (engine == null)
        engine = new ScriptEngineManager().getEngineByName(scriptType);
    if (engine == null) 
        throw new Exception("Could not find implementation of " + scriptType);
    return engine;
}  

编译和评估脚本:

public void evaluateScript(String script) throws Exception {
    Bindings bindings = getEngine().getBindings(ScriptContext.ENGINE_SCOPE);
    bindings.putAll(binding);
    try {
        if (engine instanceof Compilable)
            compiledScript = ((Compilable)getEngine()).compile(script);
        getEngine().eval(script);
    } catch (Throwable e) {
        e.printStackTrace();
    } 
}

从脚本中获取函数。我没有找到其他方法如何从除了Reflection之外的脚本中获取所有可调用方法。是的,我知道这种方法取决于ScriptEngine实现,但它是唯一的:)

public List getInvokableList() throws ScriptException {                
    List list = new ArrayList();
    try {
        Class compiledClass = compiledScript.getClass();
        Field clasz = compiledClass.getDeclaredField("clasz");       
        clasz.setAccessible(true);
        Class scrClass = (Class)clasz.get(compiledScript);
        Method[] methods = scrClass.getDeclaredMethods();            
        clasz.setAccessible(false);
        for (int i = 0, j = methods.length; i < j; i++) {
            Annotation[] annotations = methods[i].getDeclaredAnnotations();
            boolean ok = false;
            for (int k = 0, m = annotations.length; k < m; k++) {
                ok = annotations[k] instanceof CalculatedField;
                if (ok) break;
            }
            if (ok) 
                list.add(methods[i].getName());
        }
    } catch (NoSuchFieldException e) {
        e.printStackTrace(); 
    } catch (IllegalAccessException e) {

    }
    return list;
}

在我的任务中,我不需要所有的功能,为此我创建自定义注释并在脚本中使用它:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CalculatedField {    
}

<强> Script example:

import com.vssk.CalculatedField;

def utilFunc(s) {     
    s
}

@CalculatedField
def func3() {     
    utilFunc('Testing func from groovy')
}

通过名称调用脚本函数的方法:

public Object executeFunc(String name) throws Exception {
    return ((Invocable)getEngine()).invokeFunction(name);  
}