在java中使用scriptenengine,我如何提取函数列表

Using ScriptEngine in java, How can I extract function list?

本文关键字:何提取 提取 列表 函数 java scriptenengine      更新时间:2023-09-26

使用Jsoup,我提取html文件中的JavaScript部分。并将其存储为java字符串对象

和我想提取函数列表,变量列表在js的函数使用javax.script.ScriptEngine

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

bc

列表varListA

a_1a₂…

列表varListB

b_1b_2…

列表varListC

c₁c₂…

我如何提取函数列表和变量列表(或值)?

我认为你可以通过在引擎中加载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脚本引擎的内部机制(因此使用不安全)。

这很棘手。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);
           }
       }

我也有类似的问题。也许它会对别人有帮助。我使用groove作为脚本语言。我的任务是从脚本中检索所有可调用的函数。然后根据一些标准筛选这些函数。

不幸的是,这种方法只对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();
    } 
}

从脚本中获取函数。我没有找到其他方法如何从脚本中获得所有可调用的方法,除了反射。是的,我知道这种方法取决于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);  
}