8198801: JShell: user exception chained cause not retained

Reviewed-by: jlahoda
This commit is contained in:
Robert Field 2018-04-03 13:27:58 -07:00
parent c1efa0a4d6
commit 4ecc488704
12 changed files with 385 additions and 85 deletions

View File

@ -81,6 +81,7 @@ import jdk.jshell.ExpressionSnippet;
import jdk.jshell.ImportSnippet;
import jdk.jshell.JShell;
import jdk.jshell.JShell.Subscription;
import jdk.jshell.JShellException;
import jdk.jshell.MethodSnippet;
import jdk.jshell.Snippet;
import jdk.jshell.Snippet.Kind;
@ -3357,21 +3358,61 @@ public class JShellTool implements MessageHandler {
/**
* Print out a snippet exception.
*
* @param exception the exception to print
* @param exception the throwable to print
* @return true on fatal exception
*/
private boolean displayException(Exception exception) {
if (exception instanceof EvalException) {
printEvalException((EvalException) exception);
return true;
} else if (exception instanceof UnresolvedReferenceException) {
printUnresolvedException((UnresolvedReferenceException) exception);
return false;
private boolean displayException(Throwable exception) {
Throwable rootCause = exception;
while (rootCause instanceof EvalException) {
rootCause = rootCause.getCause();
}
if (rootCause != exception && rootCause instanceof UnresolvedReferenceException) {
// An unresolved reference caused a chained exception, just show the unresolved
return displayException(rootCause, null);
} else {
return displayException(exception, null);
}
}
//where
private boolean displayException(Throwable exception, StackTraceElement[] caused) {
if (exception instanceof EvalException) {
// User exception
return displayEvalException((EvalException) exception, caused);
} else if (exception instanceof UnresolvedReferenceException) {
// Reference to an undefined snippet
return displayUnresolvedException((UnresolvedReferenceException) exception);
} else {
// Should never occur
error("Unexpected execution exception: %s", exception);
return true;
}
}
//where
private boolean displayUnresolvedException(UnresolvedReferenceException ex) {
// Display the resolution issue
printSnippetStatus(ex.getSnippet(), false);
return false;
}
//where
private boolean displayEvalException(EvalException ex, StackTraceElement[] caused) {
// The message for the user exception is configured based on the
// existance of an exception message and if this is a recursive
// invocation for a chained exception.
String msg = ex.getMessage();
String key = "jshell.err.exception" +
(caused == null? ".thrown" : ".cause") +
(msg == null? "" : ".message");
errormsg(key, ex.getExceptionClassName(), msg);
// The caused trace is sent to truncate duplicate elements in the cause trace
printStackTrace(ex.getStackTrace(), caused);
JShellException cause = ex.getCause();
if (cause != null) {
// Display the cause (recursively)
displayException(cause, ex.getStackTrace());
}
return true;
}
/**
* Display a list of diagnostics.
@ -3518,9 +3559,19 @@ public class JShellTool implements MessageHandler {
}
return false;
}
//where
void printStackTrace(StackTraceElement[] stes) {
for (StackTraceElement ste : stes) {
// Print a stack trace, elide frames displayed for the caused exception
void printStackTrace(StackTraceElement[] stes, StackTraceElement[] caused) {
int overlap = 0;
if (caused != null) {
int maxOverlap = Math.min(stes.length, caused.length);
while (overlap < maxOverlap
&& stes[stes.length - (overlap + 1)].equals(caused[caused.length - (overlap + 1)])) {
++overlap;
}
}
for (int i = 0; i < stes.length - overlap; ++i) {
StackTraceElement ste = stes[i];
StringBuilder sb = new StringBuilder();
String cn = ste.getClassName();
if (!cn.isEmpty()) {
@ -3548,19 +3599,9 @@ public class JShellTool implements MessageHandler {
error(" at %s(%s)", sb, loc);
}
}
//where
void printUnresolvedException(UnresolvedReferenceException ex) {
printSnippetStatus(ex.getSnippet(), false);
}
//where
void printEvalException(EvalException ex) {
if (ex.getMessage() == null) {
error("%s thrown", ex.getExceptionClassName());
} else {
error("%s thrown: %s", ex.getExceptionClassName(), ex.getMessage());
if (overlap != 0) {
error(" ...");
}
printStackTrace(ex.getStackTrace());
}
private FormatAction toAction(Status status, Status previousStatus, boolean isSignatureChange) {

View File

@ -163,6 +163,11 @@ jshell.err.retained.mode.failure = Failure in retained modes (modes cleared) --
jshell.err.corrupted.stored.startup = Corrupted stored startup, using default -- {0}
jshell.err.exception.thrown = Exception {0}
jshell.err.exception.thrown.message = Exception {0}: {1}
jshell.err.exception.cause = Caused by: {0}
jshell.err.exception.cause.message = Caused by: {0}: {1}
jshell.console.see.synopsis = <press tab again to see synopsis>
jshell.console.see.full.documentation = <press tab again to see full documentation>
jshell.console.see.documentation = <press tab again to see documentation>

View File

@ -850,17 +850,15 @@ class Eval {
? expunge(value)
: "";
} catch (ResolutionException ex) {
DeclarationSnippet sn = (DeclarationSnippet) state.maps.getSnippetDeadOrAlive(ex.id());
exception = new UnresolvedReferenceException(sn, translateExceptionStack(ex));
exception = asUnresolvedReferenceException(ex);
} catch (UserException ex) {
exception = new EvalException(ex.getMessage(),
ex.causeExceptionClass(),
translateExceptionStack(ex));
exception = asEvalException(ex);
} catch (RunException ex) {
// StopException - no-op
} catch (InternalException ex) {
state.debug(ex, "invoke");
} catch (EngineTerminationException ex) {
state.debug(ex, "termination");
state.closeDown();
}
} else if (si.subKind() == SubKind.VAR_DECLARATION_SUBKIND) {
@ -890,6 +888,36 @@ class Eval {
return events(c, outs, value, exception);
}
// Convert an internal UserException to an API EvalException, translating
// the stack to snippet form. Convert any chained exceptions
private EvalException asEvalException(UserException ue) {
return new EvalException(ue.getMessage(),
ue.causeExceptionClass(),
translateExceptionStack(ue),
asJShellException(ue.getCause()));
}
// Convert an internal ResolutionException to an API UnresolvedReferenceException,
// translating the snippet id to snipper and the stack to snippet form
private UnresolvedReferenceException asUnresolvedReferenceException(ResolutionException re) {
DeclarationSnippet sn = (DeclarationSnippet) state.maps.getSnippetDeadOrAlive(re.id());
return new UnresolvedReferenceException(sn, translateExceptionStack(re));
}
// Convert an internal UserException/ResolutionException to an API
// EvalException/UnresolvedReferenceException
private JShellException asJShellException(Throwable e) {
if (e == null) {
return null;
} else if (e instanceof UserException) {
return asEvalException((UserException) e);
} else if (e instanceof ResolutionException) {
return asUnresolvedReferenceException((ResolutionException) e);
} else {
throw new AssertionError(e);
}
}
private boolean interestingEvent(SnippetEvent e) {
return e.isSignatureChange()
|| e.causeSnippet() == null

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -26,10 +26,10 @@
package jdk.jshell;
/**
* Wraps an exception thrown in the remotely executing client.
* Wraps an throwable thrown in the executing client.
* An instance of <code>EvalException</code> can be returned in the
* {@link jdk.jshell.SnippetEvent#exception()} query.
* The name of the exception thrown is available from
* The name of the throwable thrown is available from
* {@link jdk.jshell.EvalException#getExceptionClassName()}.
* Message and stack can be queried by methods on <code>Exception</code>.
* <p>
@ -45,8 +45,9 @@ package jdk.jshell;
public class EvalException extends JShellException {
private final String exceptionClass;
EvalException(String message, String exceptionClass, StackTraceElement[] stackElements) {
super(message);
EvalException(String message, String exceptionClass,
StackTraceElement[] stackElements, JShellException cause) {
super(message, cause);
this.exceptionClass = exceptionClass;
this.setStackTrace(stackElements);
}
@ -63,4 +64,18 @@ public class EvalException extends JShellException {
return exceptionClass;
}
/**
* Returns the wrapped cause of the throwable in the executing client
* represented by this {@code EvalException} or {@code null} if the cause is
* nonexistent or unknown.
*
* @return the cause wrapped in a {@code EvalException} or
* {@link UnresolvedReferenceException} or return {@code null} if the cause
* is nonexistent or unknown.
* @since 11
*/
@Override
public JShellException getCause() {
return (JShellException) super.getCause();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -36,4 +36,8 @@ public class JShellException extends Exception {
JShellException(String message) {
super(message);
}
JShellException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -45,7 +45,7 @@ public class UnresolvedReferenceException extends JShellException {
final DeclarationSnippet snippet;
UnresolvedReferenceException(DeclarationSnippet snippet, StackTraceElement[] stackElements) {
super("Attempt to use definition snippet with unresolved references");
super("Attempt to use definition snippet with unresolved references in " + snippet);
this.snippet = snippet;
this.setStackTrace(stackElements);
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, 2017, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -288,11 +288,20 @@ public class DirectExecutionControl implements ExecutionControl {
* @throws ExecutionControl.InternalException for internal problems
*/
protected String throwConvertedInvocationException(Throwable cause) throws RunException, InternalException {
if (cause instanceof SPIResolutionException) {
SPIResolutionException spire = (SPIResolutionException) cause;
throw new ResolutionException(spire.id(), spire.getStackTrace());
throw asRunException(cause);
}
private RunException asRunException(Throwable ex) {
if (ex instanceof SPIResolutionException) {
SPIResolutionException spire = (SPIResolutionException) ex;
return new ResolutionException(spire.id(), spire.getStackTrace());
} else {
throw new UserException(cause.getMessage(), cause.getClass().getName(), cause.getStackTrace());
UserException ue = new UserException(ex.getMessage(),
ex.getClass().getName(),
ex.getStackTrace());
Throwable cause = ex.getCause();
ue.initCause(cause == null ? null : asRunException(cause));
return ue;
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -195,8 +195,7 @@ class ExecutionControlForwarder {
flush();
return true;
} catch (InternalException ex) {
writeStatus(RESULT_INTERNAL_PROBLEM);
writeUTF(ex.getMessage());
writeInternalException(ex);
flush();
return true;
} catch (ClassInstallException ex) {
@ -206,16 +205,24 @@ class ExecutionControlForwarder {
flush();
return true;
} catch (UserException ex) {
writeStatus(RESULT_USER_EXCEPTION);
writeNullOrUTF(ex.getMessage());
writeUTF(ex.causeExceptionClass());
writeObject(ex.getStackTrace());
writeStatus(RESULT_USER_EXCEPTION_CHAINED);
for (Throwable e = ex; e != null; ) {
if (e instanceof UserException) {
writeUserException((UserException) e);
e = e.getCause();
} else if (e instanceof ResolutionException) {
writeResolutionException((ResolutionException) e);
e = null;
} else {
writeInternalException(e);
e = null;
}
}
writeStatus(RESULT_SUCCESS);
flush();
return true;
} catch (ResolutionException ex) {
writeStatus(RESULT_CORRALLED);
writeInt(ex.id());
writeObject(ex.getStackTrace());
writeResolutionException(ex);
flush();
return true;
} catch (StoppedException ex) {
@ -232,6 +239,24 @@ class ExecutionControlForwarder {
}
}
void writeInternalException(Throwable ex) throws IOException {
writeStatus(RESULT_INTERNAL_PROBLEM);
writeUTF(ex.getMessage());
}
void writeUserException(UserException ex) throws IOException {
writeStatus(RESULT_USER_EXCEPTION);
writeNullOrUTF(ex.getMessage());
writeUTF(ex.causeExceptionClass());
writeObject(ex.getStackTrace());
}
void writeResolutionException(ResolutionException ex) throws IOException {
writeStatus(RESULT_CORRALLED);
writeInt(ex.id());
writeObject(ex.getStackTrace());
}
void commandLoop() {
try {
while (processCommand()) {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -89,7 +89,7 @@ class RemoteCodes {
*/
static final int RESULT_INTERNAL_PROBLEM = 103;
/**
* User exception encountered.
* User exception encountered. Legacy and used within RESULT_USER_EXCEPTION_CHAINED
*/
static final int RESULT_USER_EXCEPTION = 104;
/**
@ -104,5 +104,9 @@ class RemoteCodes {
* The invoke has been stopped.
*/
static final int RESULT_STOPPED = 107;
/**
* User exception encountered.
* @since 11
*/
static final int RESULT_USER_EXCEPTION_CHAINED = 108;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -283,18 +283,46 @@ public class StreamingExecutionControl implements ExecutionControl {
throw new NotImplementedException(message);
}
case RESULT_USER_EXCEPTION: {
// A user exception was encountered.
String message = readNullOrUTF();
String exceptionClassName = in.readUTF();
StackTraceElement[] elems = (StackTraceElement[]) in.readObject();
throw new UserException(message, exceptionClassName, elems);
// A user exception was encountered. Handle pre JDK 11 back-ends
throw readUserException();
}
case RESULT_CORRALLED: {
// An unresolved reference was encountered.
int id = in.readInt();
StackTraceElement[] elems = (StackTraceElement[]) in.readObject();
ResolutionException re = new ResolutionException(id, elems);
throw re;
throw readResolutionException();
}
case RESULT_USER_EXCEPTION_CHAINED: {
// A user exception was encountered -- transmit chained.
in.readInt(); // always RESULT_USER_EXCEPTION
UserException result = readUserException();
RunException caused = result;
// Loop through the chained causes (if any) building a chained exception
loop: while (true) {
RunException ex;
int cstatus = in.readInt();
switch (cstatus) {
case RESULT_USER_EXCEPTION: {
// A user exception was the proximal cause.
ex = readUserException();
break;
}
case RESULT_CORRALLED: {
// An unresolved reference was the underlying cause.
ex = readResolutionException();
break;
}
case RESULT_SUCCESS: {
// End of chained exceptions
break loop;
}
default: {
throw new EngineTerminationException("Bad chained remote result code: " + cstatus);
}
}
caused.initCause(ex);
caused = ex;
}
caused.initCause(null); // root cause has no cause
throw result;
}
case RESULT_STOPPED: {
// Execution was aborted by the stop()
@ -314,8 +342,21 @@ public class StreamingExecutionControl implements ExecutionControl {
}
}
} catch (IOException | ClassNotFoundException ex) {
ex.printStackTrace();
throw new EngineTerminationException(ex.toString());
}
}
private UserException readUserException() throws IOException, ClassNotFoundException {
String message = readNullOrUTF();
String exceptionClassName = in.readUTF();
StackTraceElement[] elems = (StackTraceElement[]) in.readObject();
return new UserException(message, exceptionClassName, elems);
}
private ResolutionException readResolutionException() throws IOException, ClassNotFoundException {
int id = in.readInt();
StackTraceElement[] elems = (StackTraceElement[]) in.readObject();
return new ResolutionException(id, elems);
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -24,16 +24,20 @@
/*
* @test
* @summary Tests for exceptions
* @bug 8198801
* @build KullaTesting TestingInputStream
* @run testng ExceptionsTest
*/
import jdk.jshell.SnippetEvent;
import jdk.jshell.EvalException;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import jdk.jshell.EvalException;
import jdk.jshell.JShellException;
import jdk.jshell.Snippet;
import jdk.jshell.SnippetEvent;
import jdk.jshell.UnresolvedReferenceException;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
@ -81,6 +85,54 @@ public class ExceptionsTest extends KullaTesting {
newStackTraceElement("", "", cr3.snippet(), 1)));
}
public void throwChained() {
String message1 = "error_message1";
String message2 = "error_message2";
Snippet s1 = methodKey(assertEval("void p() throws Exception { ((String) null).toString(); }"));
Snippet s2 = methodKey(assertEval("void n() throws Exception { try { p(); } catch (Exception ex) { throw new java.io.IOException(\"" + message2 + "\", ex); }}"));
Snippet s3 = methodKey(assertEval("void m() {\n"
+ "try { n(); }\n"
+ "catch (Exception ex) {\n"
+ " throw new RuntimeException(\"" + message1 + "\", ex);\n"
+ "}}"));
SnippetEvent cr4 = assertEvalException("m();");
assertExceptionMatch(cr4,
new ExceptionInfo(RuntimeException.class, message1,
new ExceptionInfo(IOException.class, message2,
new ExceptionInfo(NullPointerException.class, null,
newStackTraceElement("", "p", s1, 1),
newStackTraceElement("", "n", s2, 1),
newStackTraceElement("", "m", s3, 2),
newStackTraceElement("", "", cr4.snippet(), 1)),
newStackTraceElement("", "n", s2, 1),
newStackTraceElement("", "m", s3, 2),
newStackTraceElement("", "", cr4.snippet(), 1)),
newStackTraceElement("", "m", s3, 4),
newStackTraceElement("", "", cr4.snippet(), 1)));
}
public void throwChainedUnresolved() {
String message1 = "error_message1";
String message2 = "error_message2";
Snippet s1 = methodKey(assertEval("void p() throws Exception { ((String) null).toString(); }"));
Snippet s2 = methodKey(assertEval("void n() throws Exception { try { p(); } catch (Exception ex) { throw new java.io.IOException(\"" + message2 + "\", ex); }}"));
Snippet s3 = methodKey(assertEval("void m() {\n"
+ "try { n(); }\n"
+ "catch (Exception ex) {\n"
+ " throw new RuntimeException(\"" + message1 + "\", ex);\n"
+ "}}"));
getState().drop(s1);
SnippetEvent cr4 = assertEvalException("m();");
assertExceptionMatch(cr4,
new ExceptionInfo(RuntimeException.class, message1,
new UnresolvedExceptionInfo(s2,
newStackTraceElement("", "n", s2, 1),
newStackTraceElement("", "m", s3, 2),
newStackTraceElement("", "", cr4.snippet(), 1)),
newStackTraceElement("", "m", s3, 4),
newStackTraceElement("", "", cr4.snippet(), 1)));
}
public void throwFromConstructor() {
String message = "error_message";
Snippet s1 = methodKey(assertEval("void f() { throw new RuntimeException(\"" + message + "\"); }"));
@ -171,15 +223,42 @@ public class ExceptionsTest extends KullaTesting {
return new StackTraceElement(className, methodName, "#" + key.id(), lineNumber);
}
private static class ExceptionInfo {
public final Class<? extends Throwable> exception;
public final String message;
private static class AnyExceptionInfo {
public final StackTraceElement[] stackTraceElements;
public ExceptionInfo(Class<? extends Throwable> exception, String message, StackTraceElement...stackTraceElements) {
public AnyExceptionInfo(StackTraceElement... stackTraceElements) {
this.stackTraceElements = stackTraceElements.length == 0 ? null : stackTraceElements;
}
}
private static class UnresolvedExceptionInfo extends AnyExceptionInfo {
public final Snippet sn;
public UnresolvedExceptionInfo(Snippet sn, StackTraceElement... stackTraceElements) {
super(stackTraceElements);
this.sn = sn;
}
}
private static class ExceptionInfo extends AnyExceptionInfo {
public final Class<? extends Throwable> exception;
public final String message;
public final AnyExceptionInfo cause;
public ExceptionInfo(Class<? extends Throwable> exception, String message,
StackTraceElement... stackTraceElements) {
this(exception, message, null, stackTraceElements);
}
public ExceptionInfo(Class<? extends Throwable> exception, String message,
AnyExceptionInfo cause, StackTraceElement... stackTraceElements) {
super(stackTraceElements);
this.exception = exception;
this.message = message;
this.stackTraceElements = stackTraceElements.length == 0 ? null : stackTraceElements;
this.cause = cause;
}
}
@ -188,28 +267,51 @@ public class ExceptionsTest extends KullaTesting {
}
private void assertExceptionMatch(SnippetEvent cr, ExceptionInfo exceptionInfo) {
assertNotNull(cr.exception(), "Expected exception was not thrown: " + exceptionInfo.exception);
if (cr.exception() instanceof EvalException) {
EvalException ex = (EvalException) cr.exception();
assertExceptionMatch(cr.exception(), cr.snippet().source(), exceptionInfo);
}
private void assertExceptionMatch(Throwable exception, String source, ExceptionInfo exceptionInfo) {
assertNotNull(exception, "Expected exception was not thrown: " + exceptionInfo.exception);
if (exception instanceof EvalException) {
EvalException ex = (EvalException) exception;
String actualException = ex.getExceptionClassName();
String expectedException = exceptionInfo.exception.getCanonicalName();
String stackTrace = getStackTrace(ex);
String source = cr.snippet().source();
assertEquals(actualException, expectedException,
String.format("Given \"%s\" expected exception: %s, got: %s%nStack trace:%n%s",
source, expectedException, actualException, stackTrace));
source, expectedException, actualException, getStackTrace(ex)));
if (exceptionInfo.message != null) {
assertEquals(ex.getMessage(), exceptionInfo.message,
String.format("Given \"%s\" expected message: %s, got: %s",
source, exceptionInfo.message, ex.getMessage()));
}
if (exceptionInfo.stackTraceElements != null) {
assertStackTrace(ex.getStackTrace(), exceptionInfo.stackTraceElements,
String.format("Given \"%s\"%nStack trace:%n%s%n",
source, stackTrace));
assertStackMatch(ex, source, exceptionInfo);
if (exceptionInfo.cause != null) {
assertAnyExceptionMatch(exception.getCause(), exceptionInfo.cause);
}
} else {
fail("Unexpected execution exceptionInfo: " + cr.exception());
fail("Unexpected exception: " + exception + " or exceptionInfo: " + exceptionInfo);
}
}
private void assertStackMatch(JShellException exception, String source, AnyExceptionInfo exceptionInfo) {
if (exceptionInfo.stackTraceElements != null) {
assertStackTrace(exception.getStackTrace(), exceptionInfo.stackTraceElements,
String.format("Given \"%s\"%nStack trace:%n%s%n",
source, getStackTrace(exception)));
}
}
private void assertAnyExceptionMatch(Throwable exception, AnyExceptionInfo exceptionInfo) {
if (exceptionInfo instanceof ExceptionInfo) {
assertExceptionMatch(exception, "", (ExceptionInfo) exceptionInfo);
} else {
assertTrue(exceptionInfo instanceof UnresolvedExceptionInfo, "Bad exceptionInfo: " + exceptionInfo);
assertTrue(exception instanceof UnresolvedReferenceException,
"Expected UnresolvedReferenceException: " + exception);
UnresolvedExceptionInfo uei = (UnresolvedExceptionInfo) exceptionInfo;
UnresolvedReferenceException ure = (UnresolvedReferenceException) exception;
assertEquals(ure.getSnippet(), uei.sn);
assertStackMatch(ure, "", exceptionInfo);
}
}
@ -236,7 +338,7 @@ public class ExceptionsTest extends KullaTesting {
}
}
private String getStackTrace(EvalException ex) {
private String getStackTrace(Throwable ex) {
StringWriter st = new StringWriter();
ex.printStackTrace(new PrintWriter(st));
return st.toString();

View File

@ -23,7 +23,7 @@
/*
* @test
* @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508 8177466 8172154 8192979 8191842 8198573
* @bug 8153716 8143955 8151754 8150382 8153920 8156910 8131024 8160089 8153897 8167128 8154513 8170015 8170368 8172102 8172103 8165405 8173073 8173848 8174041 8173916 8174028 8174262 8174797 8177079 8180508 8177466 8172154 8192979 8191842 8198573 8198801
* @summary Simple jshell tool tests
* @modules jdk.compiler/com.sun.tools.javac.api
* jdk.compiler/com.sun.tools.javac.main
@ -86,6 +86,32 @@ public class ToolSimpleTest extends ReplToolTesting {
);
}
@Test
public void testChainedThrow() {
test(
(a) -> assertCommand(a, "void p() throws Exception { ((String) null).toString(); }",
"| created method p()"),
(a) -> assertCommand(a, "void n() throws Exception { try { p(); } catch (Exception ex) { throw new IOException(\"bar\", ex); }}",
"| created method n()"),
(a) -> assertCommand(a, "void m() { try { n(); } catch (Exception ex) { throw new RuntimeException(\"foo\", ex); }}",
"| created method m()"),
(a) -> assertCommand(a, "m()",
"| Exception java.lang.RuntimeException: foo\n"
+ "| at m (#3:1)\n"
+ "| at (#4:1)\n"
+ "| Caused by: java.io.IOException: bar\n"
+ "| at n (#2:1)\n"
+ "| ...\n"
+ "| Caused by: java.lang.NullPointerException\n"
+ "| at p (#1:1)\n"
+ "| ..."),
(a) -> assertCommand(a, "/drop p",
"| dropped method p()"),
(a) -> assertCommand(a, "m()",
"| attempted to call method n() which cannot be invoked until method p() is declared")
);
}
@Test
public void oneLineOfError() {
test(