[process] java.lang.Process should implement Closeable

XMLWordPrintable

    • source, behavioral
    • low
    • Hide
      The compatibility risk is minimal for the addition of the `close()` method and implementation of `Closeable` and `AutoCloseable`.
      java.lang.Process is not final and subclasses exist in OpenJDK itself and in other libraries. Clients of an existing subclass that implements a `close()` method will not be affected since the overridden implementation is used, not the implementation in Process. in a corpus search a few subclasses of Process were found that implemented a `close` method. All implementations of close() destroyed the Process, either by delegating to Process or by using OS specific APIs or commands to kill the process. None of the implementations closed the streams.
      Show
      The compatibility risk is minimal for the addition of the `close()` method and implementation of `Closeable` and `AutoCloseable`. java.lang.Process is not final and subclasses exist in OpenJDK itself and in other libraries. Clients of an existing subclass that implements a `close()` method will not be affected since the overridden implementation is used, not the implementation in Process. in a corpus search a few subclasses of Process were found that implemented a `close` method. All implementations of close() destroyed the Process, either by delegating to Process or by using OS specific APIs or commands to kill the process. None of the implementations closed the streams.
    • Java API
    • SE

      Summary

      With the introduction of Process.close(), process resource cleanup is now straightforward and complete. By launching a process inside a try-with-resources block, both the process streams and the process itself are properly cleaned up and terminated when exiting the block.

      Problem

      Previously, callers were responsible for manually closing each process stream and ensuring the process itself was terminated, as there was no unified method to handle all cleanup. While try-with-resources could manage streams, it could not be applied to Process directly since it lacked a close() method and did not implement AutoCloseable or Closeable.

      Solution

      The addition of Process.close() and the implementation of Closeable and AutoCloseable interfaces to java.lang.Process allow for consistent and reliable cleanup. Now, try-with-resources can be used with Process to automatically close its streams and terminate the process upon exit from try-with-resources. Inside a try-with-resources block, applications have full access to process APIs and streams, enabling them to read, write, close streams, wait for process completion, and check exit status as needed.

      Specification

      Updates to Process class javadoc.

      @@ -85,7 +85,24 @@
        * <p>As of 1.5, {@link ProcessBuilder#start()} is the preferred way
        * to create a {@code Process}.
        *
      - * <p>Subclasses of Process should override the {@link #onExit()} and
      + * <p>Subclasses of Process should ensure that each overridden method
      + * invokes the superclass method.
      + * For example, if {@linkplain #close() close} is overridden, the subclass should
      + * ensure that {@code Process.close()} is called.
      + * {@snippet lang = "java" :
      + * public class LoggingProcess extends java.lang.Process {
      + *     ...
      + *     @Override
      + *     public void close() throws IOException  {
      + *         try {
      + *             super.close();
      + *         } catch (IOException ex) {
      + *             LOGGER.log(ex);
      + *          } finally {
      + *             LOGGER.log("process closed");
      + *         }
      + *     }
      + *     ...
      + * }
      + * }
      + *
      + * <p>Subclasses of Process that wrap another Process instance
      + * should override and delegate the {@link #onExit()} and
        * {@link #toHandle()} methods to provide a fully functional Process including the
        * {@linkplain #pid() process id},
        * {@linkplain #info() information about the process},
      @@ -99,7 +116,10 @@
        * process and for the communication streams between them.
        * The resources to control the process and for communication between the processes are retained
        * until there are no longer any references to the Process or the input, error, and output streams
      - * or readers, or they have been closed.
      + * or readers, or they have been closed. The Process {@linkplain Process#close close} method closes
      + * all the streams and terminates the process to release the resources. Using try-with-resources to
      + * {@linkplain ProcessBuilder#start()} the process can ensure the process
      + * is terminated when the try-with-resources block exits.
        *
        * <p>The process is not killed when there are no more references to the {@code Process} object,
        * but rather the process continues executing asynchronously.
      @@ -114,8 +134,8 @@
        * {@snippet lang = "java" :
        * List<String> capture(List<String> args) throws Exception {
        *     ProcessBuilder pb = new ProcessBuilder(args);
      - *     Process process = pb.start();
      - *     try (BufferedReader in = process.inputReader()) {
      + *     try (Process process = pb.start();
      + *          BufferedReader in = process.inputReader()) {
        *         List<String> captured = in.readAllLines();
        *         int status = process.waitFor();
        *         if (status != 0) {
      @@ -139,7 +159,7 @@
        *
        * @since   1.0
        */
      -public abstract class Process {
      +public abstract class Process implements Closeable {
      

      Additional close method in Process:

          /**
           * Closes all reader and writer streams and waits for the process to terminate.
           * This method is idempotent, if this {@code Process} has already been closed
           * invoking this method has no effect.
           * <p>
           * If the data from the process input or error streams is needed, it must be read before
           * calling this method. The contents of streams that have not been read to end of stream
           * are lost, they are discarded or ignored.
           * <p>
           * If the process exit value is of interest, then the caller must
           * {@linkplain #waitFor() wait for} the process to terminate before calling this method.
           * <p>
           * Streams should be closed when no longer needed.
           * Closing an already closed stream usually has no effect but is specific to the stream.
           * If an {@code IOException} occurs when closing a stream it is thrown
           * after the process has terminated.
           * Exceptions thrown by closing the streams, if any, are added to the first
           * {@code IOException} as {@linkplain IOException#addSuppressed suppressed exceptions}.
           * <p>
           * After the streams are closed this method {@linkplain #waitFor() waits for} the
           * process to terminate. If {@linkplain Thread#interrupt interrupted} while waiting
           * the process is {@linkplain #destroyForcibly() forcibly destroyed} and
           * this method continues to wait for the process to terminate.
           * The interrupted status is re-asserted before this method returns or
           * any {@code IOExceptions} are thrown.
           * @apiNote
           * Try-with-resources example to write text to a process, read back the
           * response, and close the streams and process:
           * {@snippet file="ProcessExamples.java" region=example}
           *
           * @implNote
           * Concrete implementations that override this class are strongly encouraged to
           * override this method and invoke the superclass {@code close} method.
           *
           * @implSpec
           * This method closes the process I/O streams and then
           * {@linkplain #waitFor() waits for} the process to terminate.
           * If {@link #waitFor() waitFor()} is {@linkplain Thread#interrupt() interrupted}
           * the process is {@linkplain #destroyForcibly() forcibly destroyed}
           * and then {@code close()} waits for the process to terminate.
           * @throws IOException if closing any of the streams throws an exception
           * @since 26
           */
          @Override
          public void close() throws IOException {...}
      

      The apidiff and javadoc are attached.

            Assignee:
            Roger Riggs
            Reporter:
            Roger Riggs
            Alan Bateman, Brian Burkhalter, Jaikiran Pai, Lance Andersen, Naoto Sato
            Votes:
            1 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: