Wrap native JS exceptions as java.lang.RuntimeException

This commit is contained in:
Alexey Andreev 2018-11-26 14:01:50 +03:00
parent 1c09a52ef9
commit 85f901362f
5 changed files with 69 additions and 11 deletions

View File

@ -251,6 +251,12 @@ public class JavaScriptTarget implements TeaVMTarget, TeaVMJavaScriptHost {
exceptionCons.use(); exceptionCons.use();
exceptionCons.getVariable(0).propagate(dependencyAnalyzer.getType(NoSuchMethodError.class.getName())); exceptionCons.getVariable(0).propagate(dependencyAnalyzer.getType(NoSuchMethodError.class.getName()));
exceptionCons.getVariable(1).propagate(dependencyAnalyzer.getType("java.lang.String")); exceptionCons.getVariable(1).propagate(dependencyAnalyzer.getType("java.lang.String"));
exceptionCons = dependencyAnalyzer.linkMethod(new MethodReference(
RuntimeException.class, "<init>", String.class, void.class), null);
exceptionCons.getVariable(0).propagate(dependencyAnalyzer.getType(RuntimeException.class.getName()));
exceptionCons.getVariable(1).propagate(dependencyAnalyzer.getType("java.lang.String"));
exceptionCons.use();
} }
@Override @Override

View File

@ -50,6 +50,7 @@ public class RuntimeRenderer {
renderRuntimeNullCheck(); renderRuntimeNullCheck();
renderRuntimeIntern(); renderRuntimeIntern();
renderRuntimeThreads(); renderRuntimeThreads();
renderRuntimeCreateException();
} catch (NamingException e) { } catch (NamingException e) {
throw new RenderingException("Error rendering runtime methods. See a cause for details", e); throw new RenderingException("Error rendering runtime methods. See a cause for details", e);
} catch (IOException e) { } catch (IOException e) {
@ -160,4 +161,13 @@ public class RuntimeRenderer {
.append("(t);").softNewLine(); .append("(t);").softNewLine();
writer.outdent().append("}").newLine(); writer.outdent().append("}").newLine();
} }
private void renderRuntimeCreateException() throws IOException {
writer.append("function $rt_createException(message)").ws().append("{").indent().softNewLine();
writer.append("return ");
writer.append(writer.getNaming().getNameForInit(new MethodReference(RuntimeException.class,
"<init>", String.class, void.class)));
writer.append("(message);").softNewLine();
writer.outdent().append("}").newLine();
}
} }

View File

@ -1400,24 +1400,46 @@ public class StatementRenderer implements ExprVisitor, StatementVisitor {
visitStatements(protectedBody); visitStatements(protectedBody);
writer.outdent().append("}").ws().append("catch").ws().append("($$e)") writer.outdent().append("}").ws().append("catch").ws().append("($$e)")
.ws().append("{").indent().softNewLine(); .ws().append("{").indent().softNewLine();
writer.append("$$je").ws().append("=").ws().append("$$e.$javaException;").softNewLine(); writer.append("$$je").ws().append("=").ws().append("$rt_wrapException($$e);").softNewLine();
boolean first = true;
boolean defaultHandlerOccurred = false;
for (TryCatchStatement catchClause : sequence) { for (TryCatchStatement catchClause : sequence) {
writer.append("if").ws().append("($$je"); if (!first) {
if (catchClause.getExceptionType() != null) { writer.ws().append("else");
writer.ws().append("&&").ws().append("$$je instanceof ")
.appendClass(catchClause.getExceptionType());
} }
writer.append(")").ws().append("{").indent().softNewLine(); if (catchClause.getExceptionType() != null) {
if (!first) {
writer.append(" ");
}
writer.append("if").ws().append("($$je instanceof ").appendClass(catchClause.getExceptionType());
writer.append(")").ws();
} else {
defaultHandlerOccurred = true;
}
if (catchClause.getExceptionType() != null || !first) {
writer.append("{").indent().softNewLine();
}
if (catchClause.getExceptionVariable() != null) { if (catchClause.getExceptionVariable() != null) {
writer.append(variableName(catchClause.getExceptionVariable())).ws().append("=").ws() writer.append(variableName(catchClause.getExceptionVariable())).ws().append("=").ws()
.append("$$je;").softNewLine(); .append("$$je;").softNewLine();
} }
visitStatements(catchClause.getHandler()); visitStatements(catchClause.getHandler());
writer.outdent().append("}").ws().append("else ");
if (catchClause.getExceptionType() != null || !first) {
writer.outdent().append("}");
}
first = false;
}
if (!defaultHandlerOccurred) {
writer.ws().append("else").ws().append("{").indent().softNewLine();
writer.append("throw $$je;").softNewLine();
writer.outdent().append("}").softNewLine();
} else {
writer.softNewLine();
} }
writer.append("{").indent().softNewLine();
writer.append("throw $$e;").softNewLine();
writer.outdent().append("}").softNewLine();
writer.outdent().append("}").softNewLine(); writer.outdent().append("}").softNewLine();
} catch (IOException e) { } catch (IOException e) {
throw new RenderingException("IO error occurred", e); throw new RenderingException("IO error occurred", e);

View File

@ -614,10 +614,18 @@ function $rt_intBitsToFloat(n) {
function $rt_javaException(e) { function $rt_javaException(e) {
return e instanceof Error && typeof e.$javaException === 'object' ? e.$javaException : null; return e instanceof Error && typeof e.$javaException === 'object' ? e.$javaException : null;
} }
function $rt_jsException(e) { function $rt_jsException(e) {
return typeof e.$jsException === 'object' ? e.$jsException : null; return typeof e.$jsException === 'object' ? e.$jsException : null;
} }
function $rt_wrapException(err) {
var ex = err.$javaException;
if (!ex) {
ex = $rt_createException($rt_str("(JavaScript) " + err.toString()));
err.$javaException = ex;
ex.$jsException = err;
}
return ex;
}
function $dbg_class(obj) { function $dbg_class(obj) {
var cls = obj.constructor; var cls = obj.constructor;

View File

@ -96,6 +96,18 @@ public class ExceptionsTest {
assertEquals("foobar", sb.toString()); assertEquals("foobar", sb.toString());
} }
@Test
public void catchNativeExceptionAsRuntimeException() {
StringBuilder sb = new StringBuilder();
try {
throwNativeException();
} catch (RuntimeException e) {
sb.append(e.getMessage());
}
assertEquals("(JavaScript) Error: foo", sb.toString());
}
@JSBody(params = "runnable", script = "runnable();") @JSBody(params = "runnable", script = "runnable();")
private static native void runJsCode(JSRunnable runnable); private static native void runJsCode(JSRunnable runnable);