diff --git a/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java b/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java index e481a699d1b..b85b8c9ea0f 100644 --- a/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java +++ b/src/jdk.jshell/share/classes/jdk/jshell/execution/impl/ConsoleImpl.java @@ -35,6 +35,7 @@ import java.io.Writer; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Locale; +import java.util.Objects; import jdk.internal.io.JdkConsole; import jdk.internal.io.JdkConsoleProvider; @@ -218,10 +219,11 @@ public class ConsoleImpl { */ @Override public String readln(String prompt) { + char[] chars = (prompt == null ? "null" : prompt).toCharArray(); + try { return sendAndReceive(() -> { remoteInput.write(Task.READ_LINE.ordinal()); - char[] chars = (prompt == null ? "null" : prompt).toCharArray(); sendChars(chars, 0, chars.length); char[] line = readChars(); return new String(line); @@ -245,11 +247,14 @@ public class ConsoleImpl { */ @Override public String readLine(Locale locale, String format, Object... args) { + Objects.requireNonNull(format, "the format String must be non-null"); + + String prompt = String.format(locale, format, args); + char[] chars = prompt.toCharArray(); + try { return sendAndReceive(() -> { remoteInput.write(Task.READ_LINE.ordinal()); - String prompt = String.format(locale, format, args); - char[] chars = prompt.toCharArray(); sendChars(chars, 0, chars.length); char[] line = readChars(); return new String(line); @@ -272,11 +277,14 @@ public class ConsoleImpl { */ @Override public char[] readPassword(Locale locale, String format, Object... args) { + Objects.requireNonNull(format, "the format String must be non-null"); + + String prompt = String.format(locale, format, args); + char[] chars = prompt.toCharArray(); + try { return sendAndReceive(() -> { remoteInput.write(Task.READ_PASSWORD.ordinal()); - String prompt = String.format(locale, format, args); - char[] chars = prompt.toCharArray(); sendChars(chars, 0, chars.length); return readChars(); }); diff --git a/test/langtools/jdk/jshell/ConsoleTest.java b/test/langtools/jdk/jshell/ConsoleTest.java index c6ddddac44b..29961a180ba 100644 --- a/test/langtools/jdk/jshell/ConsoleTest.java +++ b/test/langtools/jdk/jshell/ConsoleTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, 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 @@ -40,8 +40,10 @@ import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; +import jdk.jshell.EvalException; import jdk.jshell.JShell; import jdk.jshell.JShellConsole; +import jdk.jshell.Snippet.Status; import org.testng.annotations.Test; import static org.testng.Assert.*; @@ -183,6 +185,15 @@ public class ConsoleTest extends KullaTesting { assertEquals(sb.toString(), expected); } + @Test + public void testNPE() { + console = new ThrowingJShellConsole(); + assertEval("System.console().readLine(null)", DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, chain(added(Status.VALID), null, EvalException.class)); + assertEval("System.console().readPassword(null)", DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, chain(added(Status.VALID), null, EvalException.class)); + assertEval("System.console().readLine(\"%d\", \"\")", DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, chain(added(Status.VALID), null, EvalException.class)); + assertEval("System.console().readPassword(\"%d\", \"\")", DiagCheck.DIAG_OK, DiagCheck.DIAG_OK, chain(added(Status.VALID), null, EvalException.class)); + } + @Override public void setUp(Consumer bc) { super.setUp(bc.andThen(b -> b.console(new JShellConsole() {