检查非null后检测到空指针异常

时间:2012-11-23 14:23:02

标签: java nullpointerexception java-bytecode-asm javaagents

我对一个不应为null的变量有一个奇怪的java.lang.NullPointerException。

Object[] params = new Object[10];
if (param1 != null)
    params[0] = param1;

param1作为方法参数给出,它可以为null。 通常,当影响param1到params [0]时,它不为null(否则它不会传递if语句)。

这是错误(第144行是“params [0] = param1;”):

Exception in thread "Jalen Agent" java.lang.NullPointerException
    at jalen.MethodStats.onMethodEntry(MethodStats.java:144)
    at hanoi.TowersOfHanoi.solveHanoi(TowersOfHanoi.java)
    at hanoi.TowersOfHanoi.main(TowersOfHanoi.java:29)

以下是发生异常的方法的完整代码:

public static void onMethodEntry(int id, String className, String methodName, Object param1, Object param2, Object param3, Object param4, Object param5) {
    synchronized (globalLock) {
        Object[] params = new Object[10];
        if (param1 != null)
            params[0] = param1;
        if (param2 != null)
            params[1] = param2;
        if (param3 != null)
            params[2] = param3;
        if (param4 != null)
            params[3] = param4;
        if (param5 != null)
            params[4] = param5;
        MethodStats.onMethodEntry(id, className, methodName, params);
    }
}

修改

为了澄清我的例子,我的目的是:

  1. 使用ASM检测Java应用程序
  2. 使用Java代理时运行新的已检测类
  3. 代理将使用由检测代码收集的信息来运行某些测量
  4. 代理还会收集应用程序方法参数的值。
  5. 为此,在每个方法运行时执行onMethodEntry。我有几种具有不同签名的方法。特别是:

    public static void onMethodEntry(int id, String className, String methodName, Object[] params) {
        synchronized (globalLock) {
            StringBuilder fullMethodName = new StringBuilder(className).append('.').append(methodName).append('-').append(Thread.currentThread().getId());
            MethodStats.addNewMethod(id, fullMethodName.toString());
            System.out.println(fullMethodName.toString() + " -- " + id);
            for (Object param : params) {
                if (param != null)
                    System.out.println("Param: " + param.toString());
            }
            startTimes[depth] = System.nanoTime();
            stack[depth++] = MethodStats.getMethodInfo(id);
        }
    }
    
    public static void onMethodEntry(int id, String className, String methodName, Object param1) {
        synchronized (globalLock) {
            Object[] params = new Object[10];
            if (param1 != null)
                params[0] = param1;
            MethodStats.onMethodEntry(id, className, methodName, params);
        }
    }
    
    public static void onMethodEntry(int id, String className, String methodName, Object param1, Object param2) {
        synchronized (globalLock) {
            Object[] params = new Object[10];
            if (param1 != null)
                params[0] = param1;
            if (param2 != null)
                params[1] = param2;
            MethodStats.onMethodEntry(id, className, methodName, params);
        }
    }
    

    这是我用来检测程序类(即河内之塔)的代码:

    public void visitCode() {
        mv.visitLdcInsn(new Integer(this.methodID));
        this.visitLdcInsn(this.className);
        this.visitLdcInsn(this.methodName);
        String paramCall = "";
        if (this.numParam > 0) {
            // Load parameters
            for (int i=1; i<=this.numParam; i++) {
                this.visitVarInsn(Opcodes.ALOAD, i);
                paramCall += "Ljava/lang/Object;";
            }
        }
        System.out.println(paramCall);
        mv.visitMethodInsn(Opcodes.INVOKESTATIC,
                "jalen/MethodStats",
                "onMethodEntry",
                "(ILjava/lang/String;Ljava/lang/String;" + paramCall + ")V");
        super.visitCode();
    }
    

2 个答案:

答案 0 :(得分:5)

首先,params[0] = param1行上的错误,因为堆栈跟踪显示您的代码已输入onMethodEntry方法。

添加if语句绝对没有意义:如果param1null,则不会null分配,但params[0]会< em>保持 null,因为new Object[10]中所有未分配的职位最初都设为null

为了解决问题,您应首先弄清楚必须在数组中放置哪些对象而不是null参数,然后按如下方式修改条件:

if (param1 != null) {
    params[0] = param1;
} else {
    params[0] = // something else
}

答案 1 :(得分:0)

为什么不替换

onMethodEntry(int id, String className, String methodName, Object[] params) {

使用 varargs 版本的方法:

onMethodEntry(int id, String className, String methodName, Object... params) {

这样,您可以摆脱其他方法,这些方法都是相同的,只是使用不同数量的参数。包含错误的方法也会消失。如果错误仍然存​​在,那么您距离找到它还有一步之遥。 此外,您不必更改调用方法的任何代码,因为它的签名是相同的。