diff --git a/src/java.base/share/classes/java/io/Console.java b/src/java.base/share/classes/java/io/Console.java index bbf2e39eb48..2ad5d2c0c1f 100644 --- a/src/java.base/share/classes/java/io/Console.java +++ b/src/java.base/share/classes/java/io/Console.java @@ -35,0 +36 @@ +import jdk.internal.javac.PreviewFeature; @@ -147,0 +149,63 @@ public Reader reader() { + /** + * Writes a string representation of the specified object to this console's + * output stream, terminates the line using {@link System#lineSeparator()} + * and then flushes the console. + * + * <p> The string representation of the specified object is obtained as if + * by calling {@link String#valueOf(Object)}. + * + * @param obj + * An object whose string representation is to be written, + * may be {@code null}. + * + * @return This console + * + * @since 23 + */ + @PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) + public Console println(Object obj) { + throw newUnsupportedOperationException(); + } + + /** + * Writes a string representation of the specified object to this console's + * output stream and then flushes the console. + * + * <p> The string representation of the specified object is obtained as if + * by calling {@link String#valueOf(Object)}. + * + * @param obj + * An object whose string representation is to be written, + * may be {@code null}. + * + * @return This console + * + * @since 23 + */ + @PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) + public Console print(Object obj) { + throw newUnsupportedOperationException(); + } + + /** + * Writes a prompt as if by calling {@code print}, then reads a single line + * of text from this console. + * + * @param prompt + * A prompt string, may be {@code null}. + * + * @throws IOError + * If an I/O error occurs. + * + * @return A string containing the line read from the console, not + * including any line-termination characters, or {@code null} + * if an end of stream has been reached without having read + * any characters. + * + * @since 23 + */ + @PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) + public String readln(String prompt) { + throw newUnsupportedOperationException(); + } + diff --git a/src/java.base/share/classes/java/io/IO.java b/src/java.base/share/classes/java/io/IO.java new file mode 100644 index 00000000000..7485f87f03f --- /dev/null +++ b/src/java.base/share/classes/java/io/IO.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 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 + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package java.io; + +import jdk.internal.javac.PreviewFeature; + +/** + * A collection of static convenience methods that provide access to + * {@linkplain System#console() system console} for implicitly declared classes. + * + * <p> Each of this class' methods throws {@link IOError} if the system console + * is {@code null}; otherwise, the effect is as if a similarly-named method + * had been called on that console. + * + * <p> Input and output from methods in this class use the character set of + * the system console as specified by {@link Console#charset}. + * + * @since 23 + */ +@PreviewFeature(feature = PreviewFeature.Feature.IMPLICIT_CLASSES) +public final class IO { + + private IO() { + throw new Error("no instances"); + } + + /** + * Writes a string representation of the specified object to the system + * console, terminates the line and then flushes that console. + * + * <p> The effect is as if {@link Console#println(Object) println(obj)} + * had been called on {@code System.console()}. + * + * @param obj the object to print, may be {@code null} + * + * @throws IOError if {@code System.console()} returns {@code null}, + * or if an I/O error occurs + */ + public static void println(Object obj) { + con().println(obj); + } + + /** + * Writes a string representation of the specified object to the system + * console and then flushes that console. + * + * <p> The effect is as if {@link Console#print(Object) print(obj)} + * had been called on {@code System.console()}. + * + * @param obj the object to print, may be {@code null} + * + * @throws IOError if {@code System.console()} returns {@code null}, + * or if an I/O error occurs + */ + public static void print(Object obj) { + con().print(obj); + } + + /** + * Writes a prompt as if by calling {@code print}, then reads a single line + * of text from the system console. + * + * <p> The effect is as if {@link Console#readln(String) readln(prompt)} + * had been called on {@code System.console()}. + * + * @param prompt the prompt string, may be {@code null} + * + * @return a string containing the line read from the system console, not + * including any line-termination characters. Returns {@code null} if an + * end of stream has been reached without having read any characters. + * + * @throws IOError if {@code System.console()} returns {@code null}, + * or if an I/O error occurs + */ + public static String readln(String prompt) { + return con().readln(prompt); + } + + private static Console con() { + var con = System.console(); + if (con != null) { + return con; + } else { + throw new IOError(null); + } + } +} diff --git a/src/java.base/share/classes/java/io/ProxyingConsole.java b/src/java.base/share/classes/java/io/ProxyingConsole.java index 0e8a6e83301..a24ea192447 100644 --- a/src/java.base/share/classes/java/io/ProxyingConsole.java +++ b/src/java.base/share/classes/java/io/ProxyingConsole.java @@ -2 +2 @@ - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. @@ -81,0 +82,36 @@ public Reader reader() { + /** + * {@inheritDoc} + */ + @Override + public Console println(Object obj) { + synchronized (writeLock) { + delegate.println(obj); + } + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public Console print(Object obj) { + synchronized (writeLock) { + delegate.print(obj); + } + return this; + } + + /** + * {@inheritDoc} + * + * @throws IOError {@inheritDoc} + */ + @Override + public String readln(String prompt) { + synchronized (writeLock) { + synchronized (readLock) { + return delegate.readln(prompt); + } + } + } + diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsole.java b/src/java.base/share/classes/jdk/internal/io/JdkConsole.java index a75941fd2a5..ad93ceb234b 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsole.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsole.java @@ -2 +2 @@ - * Copyright (c) 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. @@ -40,0 +41,3 @@ public interface JdkConsole { + JdkConsole println(Object obj); + JdkConsole print(Object obj); + String readln(String prompt); diff --git a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java index a75ff582085..90d2a4f93f7 100644 --- a/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java +++ b/src/java.base/share/classes/jdk/internal/io/JdkConsoleImpl.java @@ -2 +2 @@ - * Copyright (c) 2022, 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2022, 2024, Oracle and/or its affiliates. All rights reserved. @@ -58,0 +59,33 @@ public Reader reader() { + @Override + public JdkConsole println(Object obj) { + pw.println(obj); + // automatic flushing covers println + return this; + } + + @Override + public JdkConsole print(Object obj) { + pw.print(obj); + pw.flush(); // automatic flushing does not cover print + return this; + } + + @Override + public String readln(String prompt) { + String line = null; + synchronized (writeLock) { + synchronized(readLock) { + pw.print(prompt); + pw.flush(); // automatic flushing does not cover print + try { + char[] ca = readline(false); + if (ca != null) + line = new String(ca); + } catch (IOException x) { + throw new IOError(x); + } + } + } + return line; + } + diff --git a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java index 64255b5ab60..d474f08be77 100644 --- a/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java +++ b/src/jdk.internal.le/share/classes/jdk/internal/org/jline/JdkConsoleProviderImpl.java @@ -85,0 +86,24 @@ public Reader reader() { + @Override + public JdkConsole println(Object obj) { + writer().println(obj); + writer().flush(); + return this; + } + + @Override + public JdkConsole print(Object obj) { + writer().print(obj); + writer().flush(); + return this; + } + + @Override + public String readln(String prompt) { + try { + initJLineIfNeeded(); + return jline.readLine(prompt == null ? "null" : prompt.replace("%", "%%")); + } catch (EndOfFileException eofe) { + return null; + } + } + 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 202f29e3140..bc12728d3aa 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 @@ -2 +2 @@ - * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. @@ -191,0 +192,40 @@ public void close() throws IOException { + /** + * {@inheritDoc} + */ + @Override + public JdkConsole println(Object obj) { + writer().println(obj); + writer().flush(); + return this; + } + + /** + * {@inheritDoc} + */ + @Override + public JdkConsole print(Object obj) { + writer().print(obj); + writer().flush(); + return this; + } + + /** + * {@inheritDoc} + * + * @throws IOError {@inheritDoc} + */ + @Override + public String readln(String prompt) { + 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); + }); + } catch (IOException ex) { + throw new IOError(ex); + } + } +