From 92cd7e93b3a81bc14ddfcaf5da18ba07b52b45bb Mon Sep 17 00:00:00 2001 From: gyowoo1113 Date: Thu, 13 Aug 2026 21:07:23 +0900 Subject: [PATCH 1/4] [ZEPPELIN-6482] Ensure System streams are restored in StaticRepl --- .../org/apache/zeppelin/java/StaticRepl.java | 99 +++++++++---------- 1 file changed, 48 insertions(+), 51 deletions(-) diff --git a/java/src/main/java/org/apache/zeppelin/java/StaticRepl.java b/java/src/main/java/org/apache/zeppelin/java/StaticRepl.java index 8850ea91477..20071982681 100644 --- a/java/src/main/java/org/apache/zeppelin/java/StaticRepl.java +++ b/java/src/main/java/org/apache/zeppelin/java/StaticRepl.java @@ -102,68 +102,65 @@ public static String execute(String generatedClassName, String code) throws Exce // Save the old System.out! PrintStream oldOut = System.out; PrintStream oldErr = System.err; - // Tell Java to use your special stream - System.setOut(newOut); - System.setErr(newErr); - DiagnosticCollector diagnostics = new DiagnosticCollector<>(); - CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits); - - // executing the compilation process - boolean success = task.call(); - - // if success is false will get error - if (!success) { - for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { - if (diagnostic.getLineNumber() == -1) { - continue; + try { + // Tell Java to use your special stream + System.setOut(newOut); + System.setErr(newErr); + + DiagnosticCollector diagnostics = new DiagnosticCollector<>(); + CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits); + + // executing the compilation process + boolean success = task.call(); + + // if success is false will get error + if (!success) { + for (Diagnostic diagnostic : diagnostics.getDiagnostics()) { + if (diagnostic.getLineNumber() == -1) { + continue; + } + System.err.println("line " + diagnostic.getLineNumber() + " : " + + diagnostic.getMessage(null)); } - System.err.println("line " + diagnostic.getLineNumber() + " : " - + diagnostic.getMessage(null)); - } - System.out.flush(); - System.err.flush(); - - System.setOut(oldOut); - System.setErr(oldErr); - LOGGER.error("Exception in Interpreter while compilation", baosErr.toString()); - throw new Exception(baosErr.toString()); - } else { - try { - - // creating new class loader - URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{new File("").toURI() - .toURL()}); - // execute the Main method - Class.forName(generatedClassName, true, classLoader) - .getDeclaredMethod("main", new Class[]{String[].class}) - .invoke(null, new Object[]{null}); - System.out.flush(); System.err.flush(); - // set the stream to old stream - System.setOut(oldOut); - System.setErr(oldErr); + LOGGER.error("Exception in Interpreter while compilation", baosErr.toString()); + throw new Exception(baosErr.toString()); + } else { + try { - return baosOut.toString(); + // creating new class loader + URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{new File("").toURI() + .toURL()}); + // execute the Main method + Class.forName(generatedClassName, true, classLoader) + .getDeclaredMethod("main", new Class[]{String[].class}) + .invoke(null, new Object[]{null}); - } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException - | InvocationTargetException e) { - LOGGER.error("Exception in Interpreter while execution", e); - System.err.println(e); - e.printStackTrace(newErr); - throw new Exception(baosErr.toString(), e); + System.out.flush(); + System.err.flush(); - } finally { + return baosOut.toString(); - System.out.flush(); - System.err.flush(); + } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException + | InvocationTargetException e) { + LOGGER.error("Exception in Interpreter while execution", e); + System.err.println(e); + e.printStackTrace(newErr); + throw new Exception(baosErr.toString(), e); - System.setOut(oldOut); - System.setErr(oldErr); + } } - } + + } finally { + System.out.flush(); + System.err.flush(); + + System.setOut(oldOut); + System.setErr(oldErr); + } } From 60eeedb0e3b1eb41fbf9f46ab8b9eb3d0547ac59 Mon Sep 17 00:00:00 2001 From: gyowoo1113 Date: Thu, 13 Aug 2026 21:24:04 +0900 Subject: [PATCH 2/4] [ZEPPELIN-6482] Add Mockito dependency to java module --- java/pom.xml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/java/pom.xml b/java/pom.xml index 47798a86fcc..c18854ca72e 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -44,6 +44,12 @@ 2.0-M3 + + org.mockito + mockito-core + test + + From 2ff5ced3833e880a6c91724ae4ad3484b3190bb5 Mon Sep 17 00:00:00 2001 From: gyowoo1113 Date: Thu, 13 Aug 2026 21:25:43 +0900 Subject: [PATCH 3/4] [ZEPPELIN-6482] Add regression test for StaticRepl stream restoration --- .../org/apache/zeppelin/java/StaticRepl.java | 5 +- .../apache/zeppelin/java/StaticReplTest.java | 66 +++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 java/src/test/java/org/apache/zeppelin/java/StaticReplTest.java diff --git a/java/src/main/java/org/apache/zeppelin/java/StaticRepl.java b/java/src/main/java/org/apache/zeppelin/java/StaticRepl.java index 20071982681..559270d0174 100644 --- a/java/src/main/java/org/apache/zeppelin/java/StaticRepl.java +++ b/java/src/main/java/org/apache/zeppelin/java/StaticRepl.java @@ -48,8 +48,11 @@ public class StaticRepl { private static final Logger LOGGER = LoggerFactory.getLogger(StaticRepl.class); public static String execute(String generatedClassName, String code) throws Exception { + return execute(generatedClassName, code, ToolProvider.getSystemJavaCompiler()); + } + + public static String execute(String generatedClassName, String code, JavaCompiler compiler) throws Exception { - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); if (compiler == null) { throw new Exception( "Java compiler not available. Make sure Zeppelin is running on JDK (not JRE)."); diff --git a/java/src/test/java/org/apache/zeppelin/java/StaticReplTest.java b/java/src/test/java/org/apache/zeppelin/java/StaticReplTest.java new file mode 100644 index 00000000000..6156379090b --- /dev/null +++ b/java/src/test/java/org/apache/zeppelin/java/StaticReplTest.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.zeppelin.java; + +import javax.tools.JavaCompiler; +import javax.tools.JavaCompiler.CompilationTask; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertSame; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.PrintStream; + +public class StaticReplTest { + + @Test + void shouldRestoreSystemStreamsWhenCompilationThrows(){ + PrintStream originalOut = System.out; + PrintStream originalErr = System.err; + + JavaCompiler compiler = mock(JavaCompiler.class); + CompilationTask task = mock(CompilationTask.class); + + when(compiler.getTask(any(), any(), any(), any(), any(), any())) + .thenReturn(task); + + when(task.call()) + .thenThrow(new RuntimeException("Compilation failed unexpectedly")); + + String code = "public class TestClass {" + + " public static void main(String[] args) {}" + + "}"; + + try { + assertThrows(RuntimeException.class, () -> StaticRepl.execute("TestClass", code, compiler)); + + assertSame(originalOut, System.out); + assertSame(originalErr, System.err); + + } finally { + System.setOut(originalOut); + System.setErr(originalErr); + } + + } + +} From ef9c75421c2c165bfa738cef4a982ba59d66fa00 Mon Sep 17 00:00:00 2001 From: gyowoo1113 Date: Thu, 13 Aug 2026 21:54:29 +0900 Subject: [PATCH 4/4] [ZEPPELIN-6482] Resolve Checkstyle violations --- .../org/apache/zeppelin/java/StaticRepl.java | 12 +++++- .../apache/zeppelin/java/StaticReplTest.java | 42 +++++++++---------- 2 files changed, 31 insertions(+), 23 deletions(-) diff --git a/java/src/main/java/org/apache/zeppelin/java/StaticRepl.java b/java/src/main/java/org/apache/zeppelin/java/StaticRepl.java index 559270d0174..1780196e820 100644 --- a/java/src/main/java/org/apache/zeppelin/java/StaticRepl.java +++ b/java/src/main/java/org/apache/zeppelin/java/StaticRepl.java @@ -51,7 +51,10 @@ public static String execute(String generatedClassName, String code) throws Exce return execute(generatedClassName, code, ToolProvider.getSystemJavaCompiler()); } - public static String execute(String generatedClassName, String code, JavaCompiler compiler) throws Exception { + public static String execute( + String generatedClassName, + String code, + JavaCompiler compiler) throws Exception { if (compiler == null) { throw new Exception( @@ -112,7 +115,12 @@ public static String execute(String generatedClassName, String code, JavaCompile System.setErr(newErr); DiagnosticCollector diagnostics = new DiagnosticCollector<>(); - CompilationTask task = compiler.getTask(null, null, diagnostics, null, null, compilationUnits); + CompilationTask task = compiler.getTask(null, + null, + diagnostics, + null, + null, + compilationUnits); // executing the compilation process boolean success = task.call(); diff --git a/java/src/test/java/org/apache/zeppelin/java/StaticReplTest.java b/java/src/test/java/org/apache/zeppelin/java/StaticReplTest.java index 6156379090b..9eb1a655e01 100644 --- a/java/src/test/java/org/apache/zeppelin/java/StaticReplTest.java +++ b/java/src/test/java/org/apache/zeppelin/java/StaticReplTest.java @@ -32,35 +32,35 @@ public class StaticReplTest { - @Test - void shouldRestoreSystemStreamsWhenCompilationThrows(){ - PrintStream originalOut = System.out; - PrintStream originalErr = System.err; + @Test + void shouldRestoreSystemStreamsWhenCompilationThrows(){ + PrintStream originalOut = System.out; + PrintStream originalErr = System.err; - JavaCompiler compiler = mock(JavaCompiler.class); - CompilationTask task = mock(CompilationTask.class); + JavaCompiler compiler = mock(JavaCompiler.class); + CompilationTask task = mock(CompilationTask.class); - when(compiler.getTask(any(), any(), any(), any(), any(), any())) + when(compiler.getTask(any(), any(), any(), any(), any(), any())) .thenReturn(task); - - when(task.call()) + + when(task.call()) .thenThrow(new RuntimeException("Compilation failed unexpectedly")); - - String code = "public class TestClass {" + + String code = "public class TestClass {" + " public static void main(String[] args) {}" + "}"; + + try { + assertThrows(RuntimeException.class, () -> StaticRepl.execute("TestClass", code, compiler)); - try { - assertThrows(RuntimeException.class, () -> StaticRepl.execute("TestClass", code, compiler)); - - assertSame(originalOut, System.out); - assertSame(originalErr, System.err); + assertSame(originalOut, System.out); + assertSame(originalErr, System.err); - } finally { - System.setOut(originalOut); - System.setErr(originalErr); - } - + } finally { + System.setOut(originalOut); + System.setErr(originalErr); } + + } }