diff --git a/jjava/pom.xml b/jjava/pom.xml index a326bf6..d14635b 100644 --- a/jjava/pom.xml +++ b/jjava/pom.xml @@ -189,6 +189,15 @@ + + org.apache.maven.plugins + maven-surefire-plugin + + + --add-opens jdk.jshell/jdk.jshell=ALL-UNNAMED + + + diff --git a/jjava/src/main/java/org/dflib/jjava/JJavaExtension.java b/jjava/src/main/java/org/dflib/jjava/JJavaExtension.java index 5ed5151..84de8b4 100644 --- a/jjava/src/main/java/org/dflib/jjava/JJavaExtension.java +++ b/jjava/src/main/java/org/dflib/jjava/JJavaExtension.java @@ -25,10 +25,6 @@ public class JJavaExtension implements Extension { @Override public void install(BaseKernel kernel) { - try { - kernel.eval(STARTUP_SCRIPT); - } catch (Exception e) { - throw new RuntimeException(e); - } + kernel.eval(STARTUP_SCRIPT); } } diff --git a/jjava/src/main/java/org/dflib/jjava/JavaKernel.java b/jjava/src/main/java/org/dflib/jjava/JavaKernel.java index b84c9c8..6546309 100644 --- a/jjava/src/main/java/org/dflib/jjava/JavaKernel.java +++ b/jjava/src/main/java/org/dflib/jjava/JavaKernel.java @@ -210,7 +210,7 @@ public boolean autoLoadExtensions() { } @Override - public List formatError(Exception e) { + public List formatError(Throwable e) { if (e instanceof CompilationException) { return formatCompilationException((CompilationException) e); } else if (e instanceof IncompleteSourceException) { @@ -331,22 +331,21 @@ private List formatEvaluationInterruptedException(EvaluationInterruptedE return fmt; } - public Object evalRaw(String expr) throws Exception { + public Object evalRaw(String expr) { expr = this.magicsTransformer.transformMagics(expr); return this.evaluator.eval(expr); } @Override - public DisplayData eval(String expr) throws Exception { + public DisplayData eval(String expr) { Object result = this.evalRaw(expr); - - if (result != null) - return result instanceof DisplayData - ? (DisplayData) result - : this.getRenderer().render(result); - - return null; + if (result == null) { + return null; + } + return result instanceof DisplayData + ? (DisplayData) result + : this.getRenderer().render(result); } @Override diff --git a/jjava/src/main/java/org/dflib/jjava/execution/CodeEvaluator.java b/jjava/src/main/java/org/dflib/jjava/execution/CodeEvaluator.java index 7bf15d8..a8cf566 100644 --- a/jjava/src/main/java/org/dflib/jjava/execution/CodeEvaluator.java +++ b/jjava/src/main/java/org/dflib/jjava/execution/CodeEvaluator.java @@ -79,14 +79,14 @@ private SourceCodeAnalysis.CompletionInfo analyzeCompletion(String source) { return this.sourceAnalyzer.analyzeCompletion(source); } - private void init() throws Exception { + private void init() { for (String script : this.startupScripts) eval(script); this.startupScripts.clear(); } - protected Object evalSingle(String code) throws Exception { + protected Object evalSingle(String code) { JJavaExecutionControl executionControl = this.executionControlProvider.getRegisteredControlByID(this.executionControlID); @@ -139,11 +139,11 @@ protected Object evalSingle(String code) throws Exception { case JJavaExecutionControl.EXECUTION_INTERRUPTED_NAME: throw new EvaluationInterruptedException(code.trim()); default: - throw e; + throw new RuntimeException(e); } } - throw e; + throw new RuntimeException(e); } if (!event.status().isDefined()) @@ -154,7 +154,7 @@ protected Object evalSingle(String code) throws Exception { return result; } - public Object eval(String code) throws Exception { + public Object eval(String code) { // The init() method runs some code in the shell to initialize the environment. As such // it is deferred until the first user requested evaluation to cleanly return errors when // they happen. @@ -178,7 +178,7 @@ public Object eval(String code) throws Exception { /** * Try to clean up information linked to a code snippet and the snippet itself */ - private void dropSnippet(Snippet snippet) throws Exception { + private void dropSnippet(Snippet snippet) { JJavaExecutionControl executionControl = this.executionControlProvider.getRegisteredControlByID(this.executionControlID); this.shell.drop(snippet); diff --git a/jjava/src/main/java/org/dflib/jjava/execution/CompilationException.java b/jjava/src/main/java/org/dflib/jjava/execution/CompilationException.java index fee801e..77bf0b4 100644 --- a/jjava/src/main/java/org/dflib/jjava/execution/CompilationException.java +++ b/jjava/src/main/java/org/dflib/jjava/execution/CompilationException.java @@ -25,7 +25,7 @@ import jdk.jshell.SnippetEvent; -public class CompilationException extends Exception { +public class CompilationException extends RuntimeException { private final SnippetEvent badSnippetCompilation; public CompilationException(SnippetEvent badSnippetCompilation) { diff --git a/jjava/src/main/java/org/dflib/jjava/execution/EvaluationInterruptedException.java b/jjava/src/main/java/org/dflib/jjava/execution/EvaluationInterruptedException.java index ffcb6a5..5b2919c 100644 --- a/jjava/src/main/java/org/dflib/jjava/execution/EvaluationInterruptedException.java +++ b/jjava/src/main/java/org/dflib/jjava/execution/EvaluationInterruptedException.java @@ -23,7 +23,7 @@ */ package org.dflib.jjava.execution; -public class EvaluationInterruptedException extends Exception { +public class EvaluationInterruptedException extends RuntimeException { private final String source; public EvaluationInterruptedException(String source) { diff --git a/jjava/src/main/java/org/dflib/jjava/execution/EvaluationTimeoutException.java b/jjava/src/main/java/org/dflib/jjava/execution/EvaluationTimeoutException.java index c6622a8..18ac8fb 100644 --- a/jjava/src/main/java/org/dflib/jjava/execution/EvaluationTimeoutException.java +++ b/jjava/src/main/java/org/dflib/jjava/execution/EvaluationTimeoutException.java @@ -25,7 +25,7 @@ import java.util.concurrent.TimeUnit; -public class EvaluationTimeoutException extends Exception { +public class EvaluationTimeoutException extends RuntimeException { private final long duration; private final TimeUnit unit; private final String source; diff --git a/jjava/src/main/java/org/dflib/jjava/execution/IncompleteSourceException.java b/jjava/src/main/java/org/dflib/jjava/execution/IncompleteSourceException.java index 36895d7..6b5ba08 100644 --- a/jjava/src/main/java/org/dflib/jjava/execution/IncompleteSourceException.java +++ b/jjava/src/main/java/org/dflib/jjava/execution/IncompleteSourceException.java @@ -23,7 +23,7 @@ */ package org.dflib.jjava.execution; -public class IncompleteSourceException extends Exception { +public class IncompleteSourceException extends RuntimeException { private final String source; public IncompleteSourceException(String source) { diff --git a/jjava/src/main/java/org/dflib/jjava/execution/JJavaExecutionControl.java b/jjava/src/main/java/org/dflib/jjava/execution/JJavaExecutionControl.java index 7c43087..2ddd96c 100644 --- a/jjava/src/main/java/org/dflib/jjava/execution/JJavaExecutionControl.java +++ b/jjava/src/main/java/org/dflib/jjava/execution/JJavaExecutionControl.java @@ -103,7 +103,7 @@ public Object takeResult(String key) { return result == NULL ? null : result; } - private Object execute(String key, Method doitMethod) throws TimeoutException, Exception { + private Object execute(String key, Method doitMethod) throws Exception { Future runningTask = this.executor.submit(() -> doitMethod.invoke(null)); this.running.put(key, runningTask); @@ -137,7 +137,7 @@ private Object execute(String key, Method doitMethod) throws TimeoutException, E else if (cause instanceof SPIResolutionException) throw new ResolutionException(((SPIResolutionException) cause).id(), cause.getStackTrace()); else - throw new UserException(String.valueOf(cause.getMessage()), String.valueOf(cause.getClass().getName()), cause.getStackTrace()); + throw new UserException(String.valueOf(cause.getMessage()), cause.getClass().getName(), cause.getStackTrace()); } catch (TimeoutException e) { throw new UserException( String.format("Execution timed out after configured timeout of %d %s.", this.timeoutTime, this.timeoutUnit.toString().toLowerCase()), @@ -199,7 +199,7 @@ protected Class findClass(String name) throws ClassNotFoundException { return loaderDelegate.findClass(name); } - void unloadClass(String className) throws ClassNotFoundException { + void unloadClass(String className) { this.loaderDelegate.unloadClass(className); } diff --git a/jupyter-jvm-basekernel/src/main/java/org/dflib/jjava/jupyter/kernel/BaseKernel.java b/jupyter-jvm-basekernel/src/main/java/org/dflib/jjava/jupyter/kernel/BaseKernel.java index 864cf2c..22f6fe3 100644 --- a/jupyter-jvm-basekernel/src/main/java/org/dflib/jjava/jupyter/kernel/BaseKernel.java +++ b/jupyter-jvm-basekernel/src/main/java/org/dflib/jjava/jupyter/kernel/BaseKernel.java @@ -59,7 +59,9 @@ public abstract class BaseKernel { protected final AtomicInteger executionCount = new AtomicInteger(1); - protected static final Map KERNEL_META = ((Supplier>) () -> { + protected static final Map KERNEL_META; + + static { Map meta = null; InputStream metaStream = BaseKernel.class.getClassLoader().getResourceAsStream("kernel-metadata.json"); @@ -83,8 +85,8 @@ public abstract class BaseKernel { meta.put("project", "unknown"); } - return meta; - }).get(); + KERNEL_META = meta; + } private final JupyterIO io; private boolean shouldReplaceStdStreams; @@ -161,7 +163,28 @@ public HistoryManager getHistoryManager() { return null; } - public abstract DisplayData eval(String expr) throws Exception; + /** + * Evaluates a code expression in the kernel's language environment and returns the result + * as display data. This is the core evaluation method called when executing code cells + * in a Jupyter notebook. + * + *

The implementation should: + *

    + *
  • Parse and evaluate the provided expression string
  • + *
  • Convert the evaluation result into appropriate display data formats
  • + *
  • Handle any language-specific evaluation context/scope
  • + *
+ * + *

The returned {@link DisplayData} can contain multiple representations of the result + * (e.g. text/plain, text/html, image/png) to allow rich display in the notebook. + * Return null if the expression produces no displayable result. + * + * @param expr The code expression to evaluate as received from the Jupyter frontend + * + * @return A {@link DisplayData} object containing the evaluation result in one or more + * MIME formats, or null if there is no displayable result + */ + public abstract DisplayData eval(String expr); /** * Inspect the code to get things such as documentation for a function. This is @@ -178,10 +201,9 @@ public HistoryManager getHistoryManager() { * * @return an output bundle for displaying the documentation or null if nothing is found * - * @throws Exception if the code cannot be inspected for some reason (such as it not - * compiling) + * @throws RuntimeException if the code cannot be inspected for some reason (such as it not compiling) */ - public DisplayData inspect(String code, int at, boolean extraDetail) throws Exception { + public DisplayData inspect(String code, int at, boolean extraDetail) { return null; } @@ -204,11 +226,11 @@ public DisplayData inspect(String code, int at, boolean extraDetail) throws Exce * @return the replacement options containing a list of replacement texts and a * source range to overwrite with a user selected replacement from the list * - * @throws Exception if code cannot be completed due to code compilation issues, or - * similar. This should not be thrown if not replacements are available but rather just - * an empty replacements returned. + * @throws RuntimeException if code cannot be completed due to code compilation issues, or similar. + * This should not be thrown if not replacements are available but rather just + * an empty replacements returned. */ - public ReplacementOptions complete(String code, int at) throws Exception { + public ReplacementOptions complete(String code, int at) { return null; } @@ -283,7 +305,7 @@ public void interrupt() { * not include strings with newlines but rather separate strings each to go on a * new line. */ - public List formatError(Exception e) { + public List formatError(Throwable e) { List lines = new LinkedList<>(); lines.add(this.errorStyler.secondary("---------------------------------------------------------------------------"));