New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

调用超过20个参数的自定义函数抛出NoSuchMethodError #12

Closed
resurgencedna opened this Issue Oct 23, 2016 · 6 comments

Comments

Projects
None yet
3 participants
@resurgencedna

resurgencedna commented Oct 23, 2016

我自定义的函数GetFirstNonNullFunction类如下:


package com.meituan.rc.zeus.aviator.function;

import com.googlecode.aviator.runtime.function.AbstractFunction;
import com.googlecode.aviator.runtime.type.AviatorObject;
import com.googlecode.aviator.runtime.type.AviatorString;

import java.util.Map;

public class GetFirstNonNullFunction extends AbstractFunction {

private AviatorObject firstNonNull(Map<String, Object> env, AviatorObject... args) {
    if (args != null) {
        for (AviatorObject arg : args) {
            if (arg.getValue(env) != null) {
                return arg;
            }
        }
    }
    return new AviatorString(null);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2) {
    return firstNonNull(env, arg1, arg2);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3) {
    return firstNonNull(env, arg1, arg2, arg3);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4) {
    return firstNonNull(env, arg1, arg2, arg3, arg4);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8, AviatorObject arg9) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8, AviatorObject arg9, AviatorObject arg10) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8, AviatorObject arg9, AviatorObject arg10, AviatorObject arg11) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8, AviatorObject arg9, AviatorObject arg10, AviatorObject arg11, AviatorObject arg12) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8, AviatorObject arg9, AviatorObject arg10, AviatorObject arg11, AviatorObject arg12, AviatorObject arg13) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8, AviatorObject arg9, AviatorObject arg10, AviatorObject arg11, AviatorObject arg12, AviatorObject arg13, AviatorObject arg14) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8, AviatorObject arg9, AviatorObject arg10, AviatorObject arg11, AviatorObject arg12, AviatorObject arg13, AviatorObject arg14, AviatorObject arg15) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8, AviatorObject arg9, AviatorObject arg10, AviatorObject arg11, AviatorObject arg12, AviatorObject arg13, AviatorObject arg14, AviatorObject arg15, AviatorObject arg16) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8, AviatorObject arg9, AviatorObject arg10, AviatorObject arg11, AviatorObject arg12, AviatorObject arg13, AviatorObject arg14, AviatorObject arg15, AviatorObject arg16, AviatorObject arg17) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8, AviatorObject arg9, AviatorObject arg10, AviatorObject arg11, AviatorObject arg12, AviatorObject arg13, AviatorObject arg14, AviatorObject arg15, AviatorObject arg16, AviatorObject arg17, AviatorObject arg18) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8, AviatorObject arg9, AviatorObject arg10, AviatorObject arg11, AviatorObject arg12, AviatorObject arg13, AviatorObject arg14, AviatorObject arg15, AviatorObject arg16, AviatorObject arg17, AviatorObject arg18, AviatorObject arg19) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8, AviatorObject arg9, AviatorObject arg10, AviatorObject arg11, AviatorObject arg12, AviatorObject arg13, AviatorObject arg14, AviatorObject arg15, AviatorObject arg16, AviatorObject arg17, AviatorObject arg18, AviatorObject arg19, AviatorObject arg20) {
    return firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20);
}

@Override
public AviatorObject call(Map<String, Object> env, AviatorObject arg1, AviatorObject arg2, AviatorObject arg3, AviatorObject arg4, AviatorObject arg5, AviatorObject arg6, AviatorObject arg7, AviatorObject arg8, AviatorObject arg9, AviatorObject arg10, AviatorObject arg11, AviatorObject arg12, AviatorObject arg13, AviatorObject arg14, AviatorObject arg15, AviatorObject arg16, AviatorObject arg17, AviatorObject arg18, AviatorObject arg19, AviatorObject arg20, AviatorObject... args) {
    AviatorObject result = firstNonNull(env, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10, arg11, arg12, arg13, arg14, arg15, arg16, arg17, arg18, arg19, arg20);
    if (result.getValue(env) != null) {
        return result;
    } else {
        return firstNonNull(env, args);
    }
}

@Override
public String getName() {
    return "getFirstNonNull";
}

}



但在执行表达式调用时发现超过20个参数时,无论如何都会返回null,调试发现在ClassExpression类中execute方法调用execute0(env)时抛出了NoSuchMethodError,经查看ASMCodeGenerator类中的方法:

    
    @Override
    private String getInvokeMethodDesc(int paramCount) {
        StringBuilder sb = new StringBuilder("(Ljava/util/Map;");
        for (int i = 0; i < paramCount; i++) {
            sb.append("Lcom/googlecode/aviator/runtime/type/AviatorObject;");
        }
        sb.append(")Lcom/googlecode/aviator/runtime/type/AviatorObject;");
        return sb.toString();
    }


    @Override
    public void onMethodInvoke(Token lookhead) {
        final MethodMetaData methodMetaData = this.methodMetaDataStack.pop();
        final int parameterCount = methodMetaData.parameterCount;
        this.mv.visitMethodInsn(INVOKEINTERFACE, "com/googlecode/aviator/runtime/type/AviatorFunction", "call",
            this.getInvokeMethodDesc(parameterCount));

        this.popOperand(); // method object
        this.popOperand(); // env map
        // pop operands
        for (int i = 0; i < parameterCount; i++) {
            this.popOperand();
        }
        // push result
        this.pushOperand(0);
    }
    

发现在getInvokeMethodDesc方法中并未有对参数超过20个时做额外处理转化为数组的代码,因此猜测(当然只是猜测)您是否忽略了参数超过了20个参数时对于反射调用可变参数时的处理,如果是这样,请问能不能支持一下这个特性?(长篇大论了些,请见谅!!!)

@killme2008 killme2008 added this to the 2.3.7 milestone Oct 25, 2016

@killme2008 killme2008 self-assigned this Oct 25, 2016

@killme2008

This comment has been minimized.

Owner

killme2008 commented Nov 14, 2016

感谢,这是个bug,会尽快修复。

@Troy-GitHub

This comment has been minimized.

Troy-GitHub commented Nov 21, 2016

遇到了同样的问题

public class FunctionSUM extends AbstractFunction {
public AviatorObject call(Map<String, Object> env, AviatorObject...args) {
//运算逻辑
}

@Override
public String getName() {
	return "SUM";
}

}

用 SUM(a, b, c) 去 execute 的时候会报表达式错误,源码好像是因为找不到对应的方法

@killme2008

This comment has been minimized.

Owner

killme2008 commented Nov 24, 2016

@Troy-GitHub 你的问题不是这个,而是 AviatorFunction 并没有这个方法签名

public AviatorObject call(Map<String, Object> env, AviatorObject...args)
@killme2008

This comment has been minimized.

Owner

killme2008 commented Nov 24, 2016

修复了,发布了 2.3.7,同步 maven 可能需要一点时间,明天估计可用。

@resurgencedna

@resurgencedna

This comment has been minimized.

resurgencedna commented Dec 1, 2016

Great, Thanks! @killme2008

@killme2008

This comment has been minimized.

Owner

killme2008 commented Dec 9, 2016

@resurgencedna
客气,发布了 3.0.0,支持新的方式来定义这种不定参数函数,会方便很多,参考

https://github.com/killme2008/aviator/blob/master/src/test/java/com/googlecode/aviator/runtime/function/custom/GetFirstNonNullFunction.java

继承 AbstractVariadicFunction 实现一个方法就可以,同时可以覆写其他方法。

还有其他改进,参考

https://github.com/killme2008/aviator/releases/tag/aviator-3.0.0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment