Drop to frame feature disabled in Eclipse Debug wh

2019-04-19 20:00发布

问题:

Environment: Linux, Eclipse Juno, Java 7, JUnit

When a simple application (a java class with main method) is run in debug mode, 'Drop to Frame' feature works fine in Eclipse. However if the same method is invoked from a junit test case, 'Drop to Frame' feature is disabled in Eclipse. From the documentation

Note this command is only available if the current VM supports drop to frame and the selected stackframe is not the top frame or a frame in a native method.

As we can see from the stack frames in Debug window when a junit test case is run, there is a frame 'NativeMethodAccessorImpl.invoke' which is native. I'm assuming this is the reason for 'Drop to Frame' being disabled.

Let me know if this reasoning is correct and if yes, any workarounds available to overcome this.

回答1:

I use Eclipse Luna, Java 7 under Windows. The situation is still as described: "Drop to frame" is disabled for the test method which immediately follows the 'NativeMethodAccessorImpl.invoke' frame. The disabled state of the "Drop to frame" is bound to method canDropToFrame() respective supportsDropToFrame() in class org.eclipse.jdt.internal.debug.core.model.JDIStackFrame, (in my distribution) part of plugins/org.eclipse.jdt.debug_3.8.102.v20150115-1323/jdimodel.jar. Method supportsDropToFrame() checks if a specific frame can be dropped, and tests

  1. the JVM must support to drop frames
  2. the frame must not be the top most frame
  3. the frame must not be native
  4. the prior frame must not native

So the assumption of Ramesh was right. This is the original code snippet for tests 3 + 4:

int index = 0;
JDIStackFrame frame = null;
while (index < frames.size()) {
    frame = (JDIStackFrame) frames.get(index);
    index++;
    if (frame.isNative()) {
        return false;
    }
    if (frame.equals(this)) {
        if (jdkSupport) {
            // JDK 1.4 VMs are currently unable to pop the
            // frame directly above a native frame
            if (index < frames.size()
                    && ((JDIStackFrame) frames.get(index))
                            .isNative()) {
                return false;
            }
        }
        return true;
    }
}

The comment suggests that it was written in JDK 1.4 times, so maybe in the meantime the JVM can now also drop frames above native frames.

I created a patched version of JDIStackFrame, which skips test 4. Now when pausing in a Junit test method, "Drop to frame" was enabled, as expected.

But when actually dropping the frame, I received an error message box which stated "com.sun.jdi.InternalException: Got error code in reply: 32 occurred popping stack frame".

I assume that this is a JDWP error code. Therefore it seems that such a "Drop to frame" does not work in JDK 1.7 (don't know about 1.8), and it's not a Eclipse thing.



回答2:

This is an old one, but for the time being this is still an issue with Eclipse 2018-09, Java 1.8 and testng as test runner. The workaround (simple and obvious) is to extract the contents of the test into another method, debug it and then inline it back. E.g.:

@Test
public void test() {
    // test goes here
    assertTrue(true);
}

One may use refactoring shortcuts to speed up things: select the body of the test, press Alt+Shift+M, enter name 'inner', and the result is:

@Test
public void test() {
    inner();
}

private void inner() {
    // test goes here and 'drop-to-frame' works well
    assertTrue(true);
}

When done debugging, inline it back by pressing Alt+Shift+I while inside inner().