changeset 51032:8c88df2e8a78

8203891: Upgrade JOpt Simple to 5.0.4 Reviewed-by: alanb, chegar, mchung
author jlahoda
date Wed, 06 Jun 2018 15:36:29 +0200
parents b06f330492cd
children 83aec1d357d4
files make/CompileJavaModules.gmk src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AbstractOptionSpec.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AlternativeLongOptionSpec.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentAcceptingOptionSpec.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentList.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/BuiltinHelpFormatter.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ExceptionMessages.properties src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatter.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatterMessages.properties src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/IllegalOptionSpecificationException.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MissingRequiredOptionException.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MissingRequiredOptionsException.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MultipleArgumentsForOptionException.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NoArgumentOptionSpec.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NonOptionArgumentSpec.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionArgumentConversionException.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDeclarer.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDescriptor.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionException.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionMissingRequiredArgumentException.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParser.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParserState.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSet.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpec.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecBuilder.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecTokenizer.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionalArgumentOptionSpec.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ParserRules.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/README src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/RequiredArgumentOptionSpec.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnacceptableNumberOfNonOptionsException.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnavailableOptionException.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnconfiguredOptionException.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnrecognizedOptionException.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConversionException.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConverter.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/AbbreviationMap.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Classes.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Columns.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ConstructorInvokingValueConverter.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Messages.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/MethodInvokingValueConverter.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Objects.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/OptionNameMap.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Reflection.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ReflectionException.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Row.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Rows.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/SimpleOptionNameMap.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Strings.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/DateConverter.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/EnumConverter.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/InetAddressConverter.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/KeyValuePair.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/PathConverter.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/PathProperties.java src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/RegexMatcher.java src/jdk.internal.opt/share/legal/jopt-simple.md src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java test/jdk/tools/jmod/JmodNegativeTest.java test/jdk/tools/jmod/JmodTest.java
diffstat 61 files changed, 1728 insertions(+), 603 deletions(-) [+]
line wrap: on
line diff
--- a/make/CompileJavaModules.gmk	Wed Jun 06 13:06:21 2018 +0100
+++ b/make/CompileJavaModules.gmk	Wed Jun 06 15:36:29 2018 +0200
@@ -325,6 +325,10 @@
 
 ################################################################################
 
+jdk.internal.opt_COPY += .properties
+
+################################################################################
+
 jdk.jcmd_COPY += _options
 
 ################################################################################
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AbstractOptionSpec.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AbstractOptionSpec.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -56,7 +56,6 @@
 package jdk.internal.joptsimple;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 
 import static java.util.Collections.*;
@@ -70,22 +69,22 @@
  * @param <V> represents the type of the arguments this option accepts
  * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
  */
-abstract class AbstractOptionSpec<V> implements OptionSpec<V>, OptionDescriptor {
-    private final List<String> options = new ArrayList<String>();
+public abstract class AbstractOptionSpec<V> implements OptionSpec<V>, OptionDescriptor {
+    private final List<String> options = new ArrayList<>();
     private final String description;
     private boolean forHelp;
 
-    protected AbstractOptionSpec( String option ) {
+    AbstractOptionSpec( String option ) {
         this( singletonList( option ), EMPTY );
     }
 
-    protected AbstractOptionSpec( Collection<String> options, String description ) {
+    AbstractOptionSpec( List<String> options, String description ) {
         arrangeOptions( options );
 
         this.description = description;
     }
 
-    public final Collection<String> options() {
+    public final List<String> options() {
         return unmodifiableList( options );
     }
 
@@ -119,12 +118,8 @@
     protected V convertWith( ValueConverter<V> converter, String argument ) {
         try {
             return Reflection.convertWith( converter, argument );
-        }
-        catch ( ReflectionException ex ) {
-            throw new OptionArgumentConversionException( options(), argument, ex );
-        }
-        catch ( ValueConversionException ex ) {
-            throw new OptionArgumentConversionException( options(), argument, ex );
+        } catch ( ReflectionException | ValueConversionException ex ) {
+            throw new OptionArgumentConversionException( this, argument, ex );
         }
     }
 
@@ -139,14 +134,14 @@
     abstract void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions,
         String detectedArgument );
 
-    private void arrangeOptions( Collection<String> unarranged ) {
+    private void arrangeOptions( List<String> unarranged ) {
         if ( unarranged.size() == 1 ) {
             options.addAll( unarranged );
             return;
         }
 
-        List<String> shortOptions = new ArrayList<String>();
-        List<String> longOptions = new ArrayList<String>();
+        List<String> shortOptions = new ArrayList<>();
+        List<String> longOptions = new ArrayList<>();
 
         for ( String each : unarranged ) {
             if ( each.length() == 1 )
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AlternativeLongOptionSpec.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/AlternativeLongOptionSpec.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,26 +55,40 @@
 
 package jdk.internal.joptsimple;
 
+import jdk.internal.joptsimple.internal.Messages;
+
+import java.util.Locale;
+
 import static java.util.Collections.*;
 
 import static jdk.internal.joptsimple.ParserRules.*;
 
 /**
- * Represents the <kbd>"-W"</kbd> form of long option specification.
+ * Represents the {@code "-W"} form of long option specification.
  *
  * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
  */
 class AlternativeLongOptionSpec extends ArgumentAcceptingOptionSpec<String> {
     AlternativeLongOptionSpec() {
-        super( singletonList( RESERVED_FOR_EXTENSIONS ), true, "Alternative form of long options" );
+        super( singletonList( RESERVED_FOR_EXTENSIONS ),
+            true,
+            Messages.message(
+                Locale.getDefault(),
+                "jdk.internal.joptsimple.HelpFormatterMessages",
+                AlternativeLongOptionSpec.class,
+                "description" ) );
 
-        describedAs( "opt=value" );
+        describedAs( Messages.message(
+            Locale.getDefault(),
+            "jdk.internal.joptsimple.HelpFormatterMessages",
+            AlternativeLongOptionSpec.class,
+            "arg.description" ) );
     }
 
     @Override
     protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) {
         if ( !arguments.hasMore() )
-            throw new OptionMissingRequiredArgumentException( options() );
+            throw new OptionMissingRequiredArgumentException( this );
 
         arguments.treatNextAsLongOption();
     }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentAcceptingOptionSpec.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentAcceptingOptionSpec.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -56,13 +56,12 @@
 package jdk.internal.joptsimple;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 import java.util.StringTokenizer;
 
 import static java.util.Collections.*;
+import static java.util.Objects.*;
 
-import static jdk.internal.joptsimple.internal.Objects.*;
 import static jdk.internal.joptsimple.internal.Reflection.*;
 import static jdk.internal.joptsimple.internal.Strings.*;
 
@@ -88,12 +87,13 @@
 public abstract class ArgumentAcceptingOptionSpec<V> extends AbstractOptionSpec<V> {
     private static final char NIL_VALUE_SEPARATOR = '\u0000';
 
+    private final boolean argumentRequired;
+    private final List<V> defaultValues = new ArrayList<>();
+
     private boolean optionRequired;
-    private final boolean argumentRequired;
     private ValueConverter<V> converter;
     private String argumentDescription = "";
     private String valueSeparator = String.valueOf( NIL_VALUE_SEPARATOR );
-    private final List<V> defaultValues = new ArrayList<V>();
 
     ArgumentAcceptingOptionSpec( String option, boolean argumentRequired ) {
         super( option );
@@ -101,7 +101,7 @@
         this.argumentRequired = argumentRequired;
     }
 
-    ArgumentAcceptingOptionSpec( Collection<String> options, boolean argumentRequired, String description ) {
+    ArgumentAcceptingOptionSpec( List<String> options, boolean argumentRequired, String description ) {
         super( options, description );
 
         this.argumentRequired = argumentRequired;
@@ -182,7 +182,7 @@
      *   </code>
      * </pre>
      *
-     * <p>Then {@code options.valuesOf( "z" )} would yield the list {@code [foo, bar, baz, fizz, buzz]}.</p>
+     * <p>Then <code>options.valuesOf( "z" )</code> would yield the list {@code [foo, bar, baz, fizz, buzz]}.</p>
      *
      * <p>You cannot use Unicode U+0000 as the separator.</p>
      *
@@ -211,7 +211,7 @@
      *   </code>
      * </pre>
      *
-     * <p>Then {@code options.valuesOf( "z" )} would yield the list {@code [foo, bar, baz, fizz, buzz]}.</p>
+     * <p>Then <code>options.valuesOf( "z" )</code> would yield the list {@code [foo, bar, baz, fizz, buzz]}.</p>
      *
      * <p>You cannot use Unicode U+0000 in the separator.</p>
      *
@@ -236,8 +236,9 @@
      * @throws NullPointerException if {@code value}, {@code values}, or any elements of {@code values} are
      * {@code null}
      */
-    @SuppressWarnings("unchecked")
-    public ArgumentAcceptingOptionSpec<V> defaultsTo( V value, V... values ) {
+    @SafeVarargs
+    @SuppressWarnings("varargs")
+    public final ArgumentAcceptingOptionSpec<V> defaultsTo( V value, V... values ) {
         addDefaultValue( value );
         defaultsTo( values );
 
@@ -275,7 +276,7 @@
     }
 
     private void addDefaultValue( V value ) {
-        ensureNotNull( value );
+        requireNonNull( value );
         defaultValues.add( value );
     }
 
@@ -283,7 +284,7 @@
     final void handleOption( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions,
         String detectedArgument ) {
 
-        if ( isNullOrEmpty( detectedArgument ) )
+        if ( detectedArgument == null )
             detectOptionArgument( parser, arguments, detectedOptions );
         else
             addArguments( detectedOptions, detectedArgument );
@@ -314,8 +315,7 @@
             while ( lexer.hasMoreTokens() )
                 convert( lexer.nextToken() );
             return true;
-        }
-        catch ( OptionException ignored ) {
+        } catch ( OptionException ignored ) {
             return false;
         }
     }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentList.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ArgumentList.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/BuiltinHelpFormatter.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/BuiltinHelpFormatter.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,14 +55,9 @@
 
 package jdk.internal.joptsimple;
 
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeSet;
+import java.util.*;
 
+import jdk.internal.joptsimple.internal.Messages;
 import jdk.internal.joptsimple.internal.Rows;
 import jdk.internal.joptsimple.internal.Strings;
 
@@ -73,10 +68,17 @@
 /**
  * <p>A help formatter that allows configuration of overall row width and column separator width.</p>
  *
- * <p>The formatter produces a two-column output. The left column is for the options, and the right column for their
+ * <p>The formatter produces output in two sections: one for the options, and one for non-option arguments.</p>
+ *
+ * <p>The options section has two columns: the left column for the options, and the right column for their
  * descriptions. The formatter will allow as much space as possible for the descriptions, by minimizing the option
  * column's width, no greater than slightly less than half the overall desired width.</p>
  *
+ * <p>The non-option arguments section is one column, occupying as much width as it can.</p>
+ *
+ * <p>Subclasses are free to override bits of this implementation as they see fit. Inspect the code
+ * carefully to understand the flow of control that this implementation guarantees.</p>
+ *
  * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
  */
 public class BuiltinHelpFormatter implements HelpFormatter {
@@ -102,7 +104,20 @@
         optionRows = new Rows( desiredOverallWidth, desiredColumnSeparatorWidth );
     }
 
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation:</p>
+     * <ul>
+     *     <li>Sorts the given descriptors by their first elements of {@link OptionDescriptor#options()}</li>
+     *     <li>Passes the resulting sorted set to {@link #addRows(java.util.Collection)}</li>
+     *     <li>Returns the result of {@link #formattedHelpOutput()}</li>
+     * </ul>
+     */
     public String format( Map<String, ? extends OptionDescriptor> options ) {
+        optionRows.reset();
+        nonOptionRows.reset();
+
         Comparator<OptionDescriptor> comparator =
             new Comparator<OptionDescriptor>() {
                 public int compare( OptionDescriptor first, OptionDescriptor second ) {
@@ -110,7 +125,7 @@
                 }
             };
 
-        Set<OptionDescriptor> sorted = new TreeSet<OptionDescriptor>( comparator );
+        Set<OptionDescriptor> sorted = new TreeSet<>( comparator );
         sorted.addAll( options.values() );
 
         addRows( sorted );
@@ -118,21 +133,102 @@
         return formattedHelpOutput();
     }
 
-    private String formattedHelpOutput() {
+    /**
+     * Adds a row of option help output in the left column, with empty space in the right column.
+     *
+     * @param single text to put in the left column
+     */
+    protected void addOptionRow( String single ) {
+        addOptionRow( single, "" );
+    }
+
+    /**
+     * Adds a row of option help output in the left and right columns.
+     *
+     * @param left text to put in the left column
+     * @param right text to put in the right column
+     */
+    protected void addOptionRow( String left, String right ) {
+        optionRows.add( left, right );
+    }
+
+    /**
+     * Adds a single row of non-option argument help.
+     *
+     * @param single single row of non-option argument help text
+     */
+    protected void addNonOptionRow( String single ) {
+        nonOptionRows.add( single, "" );
+    }
+
+    /**
+     * Resizes the columns of all the rows to be no wider than the widest element in that column.
+     */
+    protected void fitRowsToWidth() {
+        nonOptionRows.fitToWidth();
+        optionRows.fitToWidth();
+    }
+
+    /**
+     * Produces non-option argument help.
+     *
+     * @return non-option argument help
+     */
+    protected String nonOptionOutput() {
+        return nonOptionRows.render();
+    }
+
+    /**
+     * Produces help for options and their descriptions.
+     *
+     * @return option help
+     */
+    protected String optionOutput() {
+        return optionRows.render();
+    }
+
+    /**
+     * <p>Produces help output for an entire set of options and non-option arguments.</p>
+     *
+     * <p>This implementation concatenates:</p>
+     * <ul>
+     *     <li>the result of {@link #nonOptionOutput()}</li>
+     *     <li>if there is non-option output, a line separator</li>
+     *     <li>the result of {@link #optionOutput()}</li>
+     * </ul>
+     *
+     * @return help output for entire set of options and non-option arguments
+     */
+    protected String formattedHelpOutput() {
         StringBuilder formatted = new StringBuilder();
-        String nonOptionDisplay = nonOptionRows.render();
+        String nonOptionDisplay = nonOptionOutput();
         if ( !Strings.isNullOrEmpty( nonOptionDisplay ) )
             formatted.append( nonOptionDisplay ).append( LINE_SEPARATOR );
-        formatted.append( optionRows.render() );
+        formatted.append( optionOutput() );
 
         return formatted.toString();
     }
 
-    private void addRows( Collection<? extends OptionDescriptor> options ) {
+    /**
+     * <p>Adds rows of help output for the given options.</p>
+     *
+     * <p>This implementation:</p>
+     * <ul>
+     *     <li>Calls {@link #addNonOptionsDescription(java.util.Collection)} with the options as the argument</li>
+ *         <li>If there are no options, calls {@link #addOptionRow(String)} with an argument that indicates
+ *         that no options are specified.</li>
+ *         <li>Otherwise, calls {@link #addHeaders(java.util.Collection)} with the options as the argument,
+ *         followed by {@link #addOptions(java.util.Collection)} with the options as the argument.</li>
+     *     <li>Calls {@link #fitRowsToWidth()}.</li>
+     * </ul>
+     *
+     * @param options descriptors for the configured options of a parser
+     */
+    protected void addRows( Collection<? extends OptionDescriptor> options ) {
         addNonOptionsDescription( options );
 
         if ( options.isEmpty() )
-            optionRows.add( "No options specified", "" );
+            addOptionRow( message( "no.options.specified" ) );
         else {
             addHeaders( options );
             addOptions( options );
@@ -141,34 +237,87 @@
         fitRowsToWidth();
     }
 
-    private void addNonOptionsDescription( Collection<? extends OptionDescriptor> options ) {
+    /**
+     * <p>Adds non-option arguments descriptions to the help output.</p>
+     *
+     * <p>This implementation:</p>
+     * <ul>
+     *     <li>{@linkplain #findAndRemoveNonOptionsSpec(java.util.Collection) Finds and removes the non-option
+     *     arguments descriptor}</li>
+     *     <li>{@linkplain #shouldShowNonOptionArgumentDisplay(OptionDescriptor) Decides whether there is
+     *     anything to show for non-option arguments}</li>
+     *     <li>If there is, {@linkplain #addNonOptionRow(String) adds a header row} and
+     *     {@linkplain #addNonOptionRow(String) adds a}
+     *     {@linkplain #createNonOptionArgumentsDisplay(OptionDescriptor) non-option arguments description} </li>
+     * </ul>
+     *
+     * @param options descriptors for the configured options of a parser
+     */
+    protected void addNonOptionsDescription( Collection<? extends OptionDescriptor> options ) {
         OptionDescriptor nonOptions = findAndRemoveNonOptionsSpec( options );
         if ( shouldShowNonOptionArgumentDisplay( nonOptions ) ) {
-            nonOptionRows.add( "Non-option arguments:", "" );
-            nonOptionRows.add(createNonOptionArgumentsDisplay(nonOptions), "");
+            addNonOptionRow( message( "non.option.arguments.header" ) );
+            addNonOptionRow( createNonOptionArgumentsDisplay( nonOptions ) );
         }
     }
 
-    private boolean shouldShowNonOptionArgumentDisplay( OptionDescriptor nonOptions ) {
-        return !Strings.isNullOrEmpty( nonOptions.description() )
-            || !Strings.isNullOrEmpty( nonOptions.argumentTypeIndicator() )
-            || !Strings.isNullOrEmpty( nonOptions.argumentDescription() );
+    /**
+     * <p>Decides whether or not to show a non-option arguments help.</p>
+     *
+     * <p>This implementation responds with {@code true} if the non-option descriptor has a non-{@code null},
+     * non-empty value for any of {@link OptionDescriptor#description()},
+     * {@link OptionDescriptor#argumentTypeIndicator()}, or {@link OptionDescriptor#argumentDescription()}.</p>
+     *
+     * @param nonOptionDescriptor non-option argument descriptor
+     * @return {@code true} if non-options argument help should be shown
+     */
+    protected boolean shouldShowNonOptionArgumentDisplay( OptionDescriptor nonOptionDescriptor ) {
+        return !Strings.isNullOrEmpty( nonOptionDescriptor.description() )
+            || !Strings.isNullOrEmpty( nonOptionDescriptor.argumentTypeIndicator() )
+            || !Strings.isNullOrEmpty( nonOptionDescriptor.argumentDescription() );
     }
 
-    private String createNonOptionArgumentsDisplay(OptionDescriptor nonOptions) {
+    /**
+     * <p>Creates a non-options argument help string.</p>
+     *
+     * <p>This implementation creates an empty string buffer and calls
+     * {@link #maybeAppendOptionInfo(StringBuilder, OptionDescriptor)}
+     * and {@link #maybeAppendNonOptionsDescription(StringBuilder, OptionDescriptor)}, passing them the
+     * buffer and the non-option arguments descriptor.</p>
+     *
+     * @param nonOptionDescriptor non-option argument descriptor
+     * @return help string for non-options
+     */
+    protected String createNonOptionArgumentsDisplay( OptionDescriptor nonOptionDescriptor ) {
         StringBuilder buffer = new StringBuilder();
-        maybeAppendOptionInfo( buffer, nonOptions );
-        maybeAppendNonOptionsDescription( buffer, nonOptions );
+        maybeAppendOptionInfo( buffer, nonOptionDescriptor );
+        maybeAppendNonOptionsDescription( buffer, nonOptionDescriptor );
 
         return buffer.toString();
     }
 
-    private void maybeAppendNonOptionsDescription( StringBuilder buffer, OptionDescriptor nonOptions ) {
+    /**
+     * <p>Appends help for the given non-option arguments descriptor to the given buffer.</p>
+     *
+     * <p>This implementation appends {@code " -- "} if the buffer has text in it and the non-option arguments
+     * descriptor has a {@link OptionDescriptor#description()}; followed by the
+     * {@link OptionDescriptor#description()}.</p>
+     *
+     * @param buffer string buffer
+     * @param nonOptions non-option arguments descriptor
+     */
+    protected void maybeAppendNonOptionsDescription( StringBuilder buffer, OptionDescriptor nonOptions ) {
         buffer.append( buffer.length() > 0 && !Strings.isNullOrEmpty( nonOptions.description() ) ? " -- " : "" )
             .append( nonOptions.description() );
     }
 
-    private OptionDescriptor findAndRemoveNonOptionsSpec( Collection<? extends OptionDescriptor> options ) {
+    /**
+     * Finds the non-option arguments descriptor in the given collection, removes it, and returns it.
+     *
+     * @param options descriptors for the configured options of a parser
+     * @return the non-option arguments descriptor
+     */
+    protected OptionDescriptor findAndRemoveNonOptionsSpec( Collection<? extends OptionDescriptor> options ) {
         for ( Iterator<? extends OptionDescriptor> it = options.iterator(); it.hasNext(); ) {
             OptionDescriptor next = it.next();
             if ( next.representsNonOptions() ) {
@@ -180,17 +329,32 @@
         throw new AssertionError( "no non-options argument spec" );
     }
 
-    private void addHeaders( Collection<? extends OptionDescriptor> options ) {
+    /**
+     * <p>Adds help row headers for option help columns.</p>
+     *
+     * <p>This implementation uses the headers {@code "Option"} and {@code "Description"}. If the options contain
+     * a "required" option, the {@code "Option"} header looks like {@code "Option (* = required)}. Both headers
+     * are "underlined" using {@code "-"}.</p>
+     *
+     * @param options descriptors for the configured options of a parser
+     */
+    protected void addHeaders( Collection<? extends OptionDescriptor> options ) {
         if ( hasRequiredOption( options ) ) {
-            optionRows.add("Option (* = required)", "Description");
-            optionRows.add("---------------------", "-----------");
+            addOptionRow( message( "option.header.with.required.indicator" ), message( "description.header" ) );
+            addOptionRow( message( "option.divider.with.required.indicator" ), message( "description.divider" ) );
         } else {
-            optionRows.add("Option", "Description");
-            optionRows.add("------", "-----------");
+            addOptionRow( message( "option.header" ), message( "description.header" ) );
+            addOptionRow( message( "option.divider" ), message( "description.divider" ) );
         }
     }
 
-    private boolean hasRequiredOption( Collection<? extends OptionDescriptor> options ) {
+    /**
+     * Tells whether the given option descriptors contain a "required" option.
+     *
+     * @param options descriptors for the configured options of a parser
+     * @return {@code true} if at least one of the options is "required"
+     */
+    protected final boolean hasRequiredOption( Collection<? extends OptionDescriptor> options ) {
         for ( OptionDescriptor each : options ) {
             if ( each.isRequired() )
                 return true;
@@ -199,19 +363,46 @@
         return false;
     }
 
-    private void addOptions( Collection<? extends OptionDescriptor> options ) {
+    /**
+     * <p>Adds help rows for the given options.</p>
+     *
+     * <p>This implementation loops over the given options, and for each, calls {@link #addOptionRow(String, String)}
+     * using the results of {@link #createOptionDisplay(OptionDescriptor)} and
+     * {@link #createDescriptionDisplay(OptionDescriptor)}, respectively, as arguments.</p>
+     *
+     * @param options descriptors for the configured options of a parser
+     */
+    protected void addOptions( Collection<? extends OptionDescriptor> options ) {
         for ( OptionDescriptor each : options ) {
             if ( !each.representsNonOptions() )
-                optionRows.add( createOptionDisplay( each ), createDescriptionDisplay( each ) );
+                addOptionRow( createOptionDisplay( each ), createDescriptionDisplay( each ) );
         }
     }
 
-    private String createOptionDisplay( OptionDescriptor descriptor ) {
+    /**
+     * <p>Creates a string for how the given option descriptor is to be represented in help.</p>
+     *
+     * <p>This implementation gives a string consisting of the concatenation of:</p>
+     * <ul>
+     *     <li>{@code "* "} for "required" options, otherwise {@code ""}</li>
+     *     <li>For each of the {@link OptionDescriptor#options()} of the descriptor, separated by {@code ", "}:
+     *         <ul>
+     *             <li>{@link #optionLeader(String)} of the option</li>
+     *             <li>the option</li>
+     *         </ul>
+     *     </li>
+     *     <li>the result of {@link #maybeAppendOptionInfo(StringBuilder, OptionDescriptor)}</li>
+     * </ul>
+     *
+     * @param descriptor a descriptor for a configured option of a parser
+     * @return help string
+     */
+    protected String createOptionDisplay( OptionDescriptor descriptor ) {
         StringBuilder buffer = new StringBuilder( descriptor.isRequired() ? "* " : "" );
 
         for ( Iterator<String> i = descriptor.options().iterator(); i.hasNext(); ) {
             String option = i.next();
-            buffer.append( option.length() > 1 ? DOUBLE_HYPHEN : HYPHEN );
+            buffer.append( optionLeader( option ) );
             buffer.append( option );
 
             if ( i.hasNext() )
@@ -223,31 +414,105 @@
         return buffer.toString();
     }
 
-    private void maybeAppendOptionInfo( StringBuilder buffer, OptionDescriptor descriptor ) {
+    /**
+     * <p>Gives a string that represents the given option's "option leader" in help.</p>
+     *
+     * <p>This implementation answers with {@code "--"} for options of length greater than one; otherwise answers
+     * with {@code "-"}.</p>
+     *
+     * @param option a string option
+     * @return an "option leader" string
+     */
+    protected String optionLeader( String option ) {
+        return option.length() > 1 ? DOUBLE_HYPHEN : HYPHEN;
+    }
+
+    /**
+     * <p>Appends additional info about the given option to the given buffer.</p>
+     *
+     * <p>This implementation:</p>
+     * <ul>
+     *     <li>calls {@link #extractTypeIndicator(OptionDescriptor)} for the descriptor</li>
+     *     <li>calls {@link jdk.internal.joptsimple.OptionDescriptor#argumentDescription()} for the descriptor</li>
+     *     <li>if either of the above is present, calls
+     *     {@link #appendOptionHelp(StringBuilder, String, String, boolean)}</li>
+     * </ul>
+     *
+     * @param buffer string buffer
+     * @param descriptor a descriptor for a configured option of a parser
+     */
+    protected void maybeAppendOptionInfo( StringBuilder buffer, OptionDescriptor descriptor ) {
         String indicator = extractTypeIndicator( descriptor );
         String description = descriptor.argumentDescription();
-        if ( indicator != null || !isNullOrEmpty( description ) )
+        if ( descriptor.acceptsArguments()
+            || !isNullOrEmpty( description )
+            || descriptor.representsNonOptions() ) {
+
             appendOptionHelp( buffer, indicator, description, descriptor.requiresArgument() );
+        }
     }
 
-    private String extractTypeIndicator( OptionDescriptor descriptor ) {
+    /**
+     * <p>Gives an indicator of the type of arguments of the option described by the given descriptor,
+     * for use in help.</p>
+     *
+     * <p>This implementation asks for the {@link OptionDescriptor#argumentTypeIndicator()} of the given
+     * descriptor, and if it is present and not {@code "java.lang.String"}, parses it as a fully qualified
+     * class name and returns the base name of that class; otherwise returns {@code "String"}.</p>
+     *
+     * @param descriptor a descriptor for a configured option of a parser
+     * @return type indicator text
+     */
+    protected String extractTypeIndicator( OptionDescriptor descriptor ) {
         String indicator = descriptor.argumentTypeIndicator();
 
         if ( !isNullOrEmpty( indicator ) && !String.class.getName().equals( indicator ) )
             return shortNameOf( indicator );
 
-        return null;
+        return "String";
     }
 
-    private void appendOptionHelp( StringBuilder buffer, String typeIndicator, String description, boolean required ) {
+    /**
+     * <p>Appends info about an option's argument to the given buffer.</p>
+     *
+     * <p>This implementation calls {@link #appendTypeIndicator(StringBuilder, String, String, char, char)} with
+     * the surrounding characters {@code '<'} and {@code '>'} for options with {@code required} arguments, and
+     * with the surrounding characters {@code '['} and {@code ']'} for options with optional arguments.</p>
+     *
+     * @param buffer string buffer
+     * @param typeIndicator type indicator
+     * @param description type description
+     * @param required indicator of "required"-ness of the argument of the option
+     */
+    protected void appendOptionHelp( StringBuilder buffer, String typeIndicator, String description,
+                                     boolean required ) {
         if ( required )
             appendTypeIndicator( buffer, typeIndicator, description, '<', '>' );
         else
             appendTypeIndicator( buffer, typeIndicator, description, '[', ']' );
     }
 
-    private void appendTypeIndicator( StringBuilder buffer, String typeIndicator, String description,
-                                      char start, char end ) {
+    /**
+     * <p>Appends a type indicator for an option's argument to the given buffer.</p>
+     *
+     * <p>This implementation appends, in order:</p>
+     * <ul>
+     *     <li>{@code ' '}</li>
+     *     <li>{@code start}</li>
+     *     <li>the type indicator, if not {@code null}</li>
+     *     <li>if the description is present, then {@code ": "} plus the description if the type indicator is
+     *     present; otherwise the description only</li>
+     *     <li>{@code end}</li>
+     * </ul>
+     *
+     * @param buffer string buffer
+     * @param typeIndicator type indicator
+     * @param description type description
+     * @param start starting character
+     * @param end ending character
+     */
+    protected void appendTypeIndicator( StringBuilder buffer, String typeIndicator, String description,
+                                        char start, char end ) {
         buffer.append( ' ' ).append( start );
         if ( typeIndicator != null )
             buffer.append( typeIndicator );
@@ -262,21 +527,69 @@
         buffer.append( end );
     }
 
-    private String createDescriptionDisplay( OptionDescriptor descriptor ) {
+    /**
+     * <p>Gives a string representing a description of the option with the given descriptor.</p>
+     *
+     * <p>This implementation:</p>
+     * <ul>
+     *     <li>Asks for the descriptor's {@link OptionDescriptor#defaultValues()}</li>
+     *     <li>If they're not present, answers the descriptor's {@link OptionDescriptor#description()}.</li>
+     *     <li>If they are present, concatenates and returns:
+     *         <ul>
+     *             <li>the descriptor's {@link OptionDescriptor#description()}</li>
+     *             <li>{@code ' '}</li>
+     *             <li>{@code "default: "} plus the result of {@link #createDefaultValuesDisplay(java.util.List)},
+     *             surrounded by parentheses</li>
+     *         </ul>
+     *     </li>
+     * </ul>
+     *
+     * @param descriptor a descriptor for a configured option of a parser
+     * @return display text for the option's description
+     */
+    protected String createDescriptionDisplay( OptionDescriptor descriptor ) {
         List<?> defaultValues = descriptor.defaultValues();
         if ( defaultValues.isEmpty() )
             return descriptor.description();
 
         String defaultValuesDisplay = createDefaultValuesDisplay( defaultValues );
-        return ( descriptor.description() + ' ' + surround( "default: " + defaultValuesDisplay, '(', ')' ) ).trim();
+        return ( descriptor.description()
+            + ' '
+            + surround( message( "default.value.header" ) + ' ' + defaultValuesDisplay, '(', ')' )
+        ).trim();
     }
 
-    private String createDefaultValuesDisplay( List<?> defaultValues ) {
+    /**
+     * <p>Gives a display string for the default values of an option's argument.</p>
+     *
+     * <p>This implementation gives the {@link Object#toString()} of the first value if there is only one value,
+     * otherwise gives the {@link Object#toString()} of the whole list.</p>
+     *
+     * @param defaultValues some default values for a given option's argument
+     * @return a display string for those default values
+     */
+    protected String createDefaultValuesDisplay( List<?> defaultValues ) {
         return defaultValues.size() == 1 ? defaultValues.get( 0 ).toString() : defaultValues.toString();
     }
 
-    private void fitRowsToWidth() {
-        nonOptionRows.fitToWidth();
-        optionRows.fitToWidth();
+    /**
+     * <p>Looks up and gives a resource bundle message.</p>
+     *
+     * <p>This implementation looks in the bundle {@code "jdk.internal.joptsimple.HelpFormatterMessages"} in the default
+     * locale, using a key that is the concatenation of this class's fully qualified name, {@code '.'},
+     * and the given key suffix, formats the corresponding value using the given arguments, and returns
+     * the result.</p>
+     *
+     * @param keySuffix suffix to use when looking up the bundle message
+     * @param args arguments to fill in the message template with
+     * @return a formatted localized message
+     */
+    protected String message( String keySuffix, Object... args ) {
+        return Messages.message(
+            Locale.getDefault(),
+            "jdk.internal.joptsimple.HelpFormatterMessages",
+            BuiltinHelpFormatter.class,
+            keySuffix,
+            args );
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ExceptionMessages.properties	Wed Jun 06 15:36:29 2018 +0200
@@ -0,0 +1,44 @@
+#
+# Copyright (c) 2018, 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.
+#
+
+jdk.internal.joptsimple.IllegalOptionSpecificationException.message = {0} is not a legal option character
+jdk.internal.joptsimple.MissingRequiredOptionsException.message = Missing required option(s) {0}
+jdk.internal.joptsimple.MultipleArgumentsForOptionException.message = Found multiple arguments for option {0}, but you asked for only one
+jdk.internal.joptsimple.OptionArgumentConversionException.message = Cannot parse argument ''{0}'' of option {1}
+jdk.internal.joptsimple.OptionMissingRequiredArgumentException.message = Option {0} requires an argument
+jdk.internal.joptsimple.UnavailableOptionException.message = Option(s) {0} are unavailable given other options on the command line
+jdk.internal.joptsimple.UnconfiguredOptionException.message = Option(s) {0} not configured on this parser
+jdk.internal.joptsimple.UnrecognizedOptionException.message = {0} is not a recognized option
+jdk.internal.joptsimple.util.DateConverter.without.pattern.message = Value [{0}] does not match date/time pattern
+jdk.internal.joptsimple.util.DateConverter.with.pattern.message = Value [{0}] does not match date/time pattern [{1}]
+jdk.internal.joptsimple.util.RegexMatcher.message = Value [{0}] did not match regex [{1}]
+jdk.internal.joptsimple.util.EnumConverter.message = Value [{0}] is not one of [{1}]
+jdk.internal.joptsimple.util.PathConverter.file.existing.message = File [{0}] does not exist
+jdk.internal.joptsimple.util.PathConverter.directory.existing.message = Directory [{0}] does not exist
+jdk.internal.joptsimple.util.PathConverter.file.not.existing.message = File [{0}] does already exist
+jdk.internal.joptsimple.util.PathConverter.file.overwritable.message = File [{0}] is not overwritable
+jdk.internal.joptsimple.util.PathConverter.file.readable.message = File [{0}] is not readable
+jdk.internal.joptsimple.util.PathConverter.file.writable.message = File [{0}] is not writable
+jdk.internal.joptsimple.util.InetAddressConverter.message = Cannot convert value [{0}] into an InetAddress
\ No newline at end of file
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatter.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatter.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/HelpFormatterMessages.properties	Wed Jun 06 15:36:29 2018 +0200
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2018, 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.
+#
+
+jdk.internal.joptsimple.BuiltinHelpFormatter.no.options.specified = No options specified
+jdk.internal.joptsimple.BuiltinHelpFormatter.non.option.arguments.header = Non-option arguments:
+jdk.internal.joptsimple.BuiltinHelpFormatter.option.header.with.required.indicator = Option (* = required)
+jdk.internal.joptsimple.BuiltinHelpFormatter.option.divider.with.required.indicator = ---------------------
+jdk.internal.joptsimple.BuiltinHelpFormatter.option.header = Option
+jdk.internal.joptsimple.BuiltinHelpFormatter.option.divider = ------
+jdk.internal.joptsimple.BuiltinHelpFormatter.description.header = Description
+jdk.internal.joptsimple.BuiltinHelpFormatter.description.divider = -----------
+jdk.internal.joptsimple.BuiltinHelpFormatter.default.value.header = default:
+jdk.internal.joptsimple.AlternativeLongOptionSpec.description = Alternative form of long options
+jdk.internal.joptsimple.AlternativeLongOptionSpec.arg.description = opt=value
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/IllegalOptionSpecificationException.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/IllegalOptionSpecificationException.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -70,7 +70,7 @@
     }
 
     @Override
-    public String getMessage() {
-        return singleOptionMessage() + " is not a legal option character";
+    Object[] messageArguments() {
+        return new Object[] { singleOptionString() };
     }
 }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MissingRequiredOptionException.java	Wed Jun 06 13:06:21 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2009, 2015, 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.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * The MIT License
- *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-package jdk.internal.joptsimple;
-
-import java.util.Collection;
-
-/**
- * Thrown when an option is marked as required, but not specified on the command line.
- *
- * @author <a href="https://github.com/TC1">Emils Solmanis</a>
- */
-class MissingRequiredOptionException extends OptionException {
-    private static final long serialVersionUID = -1L;
-
-    protected MissingRequiredOptionException( Collection<String> options ) {
-        super( options );
-    }
-
-    @Override
-    public String getMessage() {
-        return "Missing required option(s) " + multipleOptionMessage();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MissingRequiredOptionsException.java	Wed Jun 06 15:36:29 2018 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * The MIT License
+ *
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package jdk.internal.joptsimple;
+
+import java.util.List;
+
+/**
+ * Thrown when options marked as required are not specified on the command line.
+ *
+ * @author <a href="https://github.com/TC1">Emils Solmanis</a>
+ */
+class MissingRequiredOptionsException extends OptionException {
+    private static final long serialVersionUID = -1L;
+
+    protected MissingRequiredOptionsException( List<? extends OptionSpec<?>> missingRequiredOptions ) {
+        super( missingRequiredOptions );
+    }
+
+    @Override
+    Object[] messageArguments() {
+        return new Object[] { multipleOptionString() };
+    }
+}
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MultipleArgumentsForOptionException.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/MultipleArgumentsForOptionException.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,7 +55,7 @@
 
 package jdk.internal.joptsimple;
 
-import java.util.Collection;
+import static java.util.Collections.*;
 
 /**
  * Thrown when asking an {@link OptionSet} for a single argument of an option when many have been specified.
@@ -65,12 +65,12 @@
 class MultipleArgumentsForOptionException extends OptionException {
     private static final long serialVersionUID = -1L;
 
-    MultipleArgumentsForOptionException( Collection<String> options ) {
-        super( options );
+    MultipleArgumentsForOptionException( OptionSpec<?> options ) {
+        super( singleton( options ) );
     }
 
     @Override
-    public String getMessage() {
-        return "Found multiple arguments for option " + multipleOptionMessage() + ", but you asked for only one";
+    Object[] messageArguments() {
+        return new Object[] { singleOptionString() };
     }
 }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NoArgumentOptionSpec.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NoArgumentOptionSpec.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,7 +55,6 @@
 
 package jdk.internal.joptsimple;
 
-import java.util.Collection;
 import java.util.List;
 
 import static java.util.Collections.*;
@@ -70,7 +69,7 @@
         this( singletonList( option ), "" );
     }
 
-    NoArgumentOptionSpec( Collection<String> options, String description ) {
+    NoArgumentOptionSpec( List<String> options, String description ) {
         super( options, description );
     }
 
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NonOptionArgumentSpec.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/NonOptionArgumentSpec.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -87,7 +87,7 @@
     private String argumentDescription = "";
 
     NonOptionArgumentSpec() {
-        this("");
+        this( "" );
     }
 
     NonOptionArgumentSpec( String description ) {
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionArgumentConversionException.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionArgumentConversionException.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,7 +55,7 @@
 
 package jdk.internal.joptsimple;
 
-import java.util.Collection;
+import static java.util.Collections.*;
 
 /**
  * Thrown when a problem occurs converting an argument of an option from {@link String} to another type.
@@ -67,14 +67,14 @@
 
     private final String argument;
 
-    OptionArgumentConversionException( Collection<String> options, String argument, Throwable cause ) {
-        super( options, cause );
+    OptionArgumentConversionException( OptionSpec<?> options, String argument, Throwable cause ) {
+        super( singleton( options ), cause );
 
         this.argument = argument;
     }
 
     @Override
-    public String getMessage() {
-        return "Cannot parse argument '" + argument + "' of option " + multipleOptionMessage();
+    Object[] messageArguments() {
+        return new Object[] { argument, singleOptionString() };
     }
 }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDeclarer.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDeclarer.java	Wed Jun 06 15:36:29 2018 +0200
@@ -25,14 +25,20 @@
 
 package jdk.internal.joptsimple;
 
-import java.util.Collection;
+import java.util.List;
 
 /**
- * Trains the option parser. This interface aids integration with other code which may expose declaration of options but
- * not actual command-line parsing.
+ * Trains the option parser. This interface aids integration that disposes declaration of options but not actual
+ * command-line parsing.
+ *
+ * Typical use is for another class to implement {@code OptionDeclarer} as a facade, forwarding calls to an
+ * {@code OptionParser} instance.
+ *
+ * Note that although this is an interface, the returned values of calls are concrete jopt-simple classes.
  *
  * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
  * @see OptionParser
+ * @since 4.6
  */
 public interface OptionDeclarer {
     /**
@@ -78,12 +84,12 @@
      * @throws OptionException if any of the options contain illegal characters
      * @throws NullPointerException if the option list or any of its elements are {@code null}
      */
-    OptionSpecBuilder acceptsAll( Collection<String> options );
+    OptionSpecBuilder acceptsAll( List<String> options );
 
     /**
      * Tells the parser to recognize the given options, and treat them as synonymous.
      *
-     * @see #acceptsAll(Collection)
+     * @see #acceptsAll(List)
      * @param options the options to recognize and treat as synonymous
      * @param description a string that describes the purpose of the option.  This is used when generating help
      * information about the parser.
@@ -92,7 +98,7 @@
      * @throws NullPointerException if the option list or any of its elements are {@code null}
      * @throws IllegalArgumentException if the option list is empty
      */
-    OptionSpecBuilder acceptsAll( Collection<String> options, String description );
+    OptionSpecBuilder acceptsAll( List<String> options, String description );
 
     /**
      * Gives an object that represents an access point for non-option arguments on a command line.
@@ -127,7 +133,7 @@
     void allowsUnrecognizedOptions();
 
     /**
-     * Tells the parser either to recognize or ignore <kbd>"-W"</kbd>-style long options.
+     * Tells the parser either to recognize or ignore {@code -W}-style long options.
      *
      * @param recognize {@code true} if the parser is to recognize the special style of long options
      */
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDescriptor.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionDescriptor.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,7 +55,6 @@
 
 package jdk.internal.joptsimple;
 
-import java.util.Collection;
 import java.util.List;
 
 /**
@@ -70,7 +69,7 @@
      *
      * @return synonymous options
      */
-    Collection<String> options();
+    List<String> options();
 
     /**
      * Description of this option's purpose.
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionException.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionException.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -58,11 +58,15 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import jdk.internal.joptsimple.internal.Strings;
 
 import static java.util.Collections.*;
-
-import static jdk.internal.joptsimple.internal.Strings.*;
+import static jdk.internal.joptsimple.internal.Messages.*;
 
 /**
  * Thrown when a problem occurs during option parsing.
@@ -72,16 +76,30 @@
 public abstract class OptionException extends RuntimeException {
     private static final long serialVersionUID = -1L;
 
-    private final List<String> options = new ArrayList<String>();
+    private final List<String> options = new ArrayList<>();
 
-    protected OptionException( Collection<String> options ) {
+    protected OptionException( List<String> options ) {
         this.options.addAll( options );
     }
 
-    protected OptionException( Collection<String> options, Throwable cause ) {
+    protected OptionException( Collection<? extends OptionSpec<?>> options ) {
+        this.options.addAll( specsToStrings( options ) );
+    }
+
+    protected OptionException( Collection<? extends OptionSpec<?>> options, Throwable cause ) {
         super( cause );
+        this.options.addAll( specsToStrings( options ) );
+    }
 
-        this.options.addAll( options );
+    private List<String> specsToStrings( Collection<? extends OptionSpec<?>> options ) {
+        List<String> strings = new ArrayList<>();
+        for ( OptionSpec<?> each : options )
+            strings.add( specToString( each ) );
+        return strings;
+    }
+
+    private String specToString( OptionSpec<?> option ) {
+        return Strings.join( new ArrayList<>( option.options() ), "/" );
     }
 
     /**
@@ -89,23 +107,24 @@
      *
      * @return the option being considered when the exception was created
      */
-    public Collection<String> options() {
-        return unmodifiableCollection( options );
+    public List<String> options() {
+        return unmodifiableList( options );
     }
 
-    protected final String singleOptionMessage() {
-        return singleOptionMessage( options.get( 0 ) );
+    protected final String singleOptionString() {
+        return singleOptionString( options.get( 0 ) );
     }
 
-    protected final String singleOptionMessage( String option ) {
-        return SINGLE_QUOTE + option + SINGLE_QUOTE;
+    protected final String singleOptionString( String option ) {
+        return option;
     }
 
-    protected final String multipleOptionMessage() {
+    protected final String multipleOptionString() {
         StringBuilder buffer = new StringBuilder( "[" );
 
-        for ( Iterator<String> iter = options.iterator(); iter.hasNext(); ) {
-            buffer.append( singleOptionMessage( iter.next() ) );
+        Set<String> asSet = new LinkedHashSet<String>( options );
+        for ( Iterator<String> iter = asSet.iterator(); iter.hasNext(); ) {
+            buffer.append( singleOptionString(iter.next()) );
             if ( iter.hasNext() )
                 buffer.append( ", " );
         }
@@ -118,4 +137,19 @@
     static OptionException unrecognizedOption( String option ) {
         return new UnrecognizedOptionException( option );
     }
+
+    @Override
+    public final String getMessage() {
+        return localizedMessage( Locale.getDefault() );
+    }
+
+    final String localizedMessage( Locale locale ) {
+        return formattedMessage( locale );
+    }
+
+    private String formattedMessage( Locale locale ) {
+        return message( locale, "jdk.internal.joptsimple.ExceptionMessages", getClass(), "message", messageArguments() );
+    }
+
+    abstract Object[] messageArguments();
 }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionMissingRequiredArgumentException.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionMissingRequiredArgumentException.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,22 +55,22 @@
 
 package jdk.internal.joptsimple;
 
-import java.util.Collection;
+import static java.util.Arrays.*;
 
 /**
- * Thrown when the option parser discovers an option that requires an argument, but that argument is missing.
+ * Thrown when the option parser discovers options that require an argument, but are missing an argument.
  *
  * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
  */
 class OptionMissingRequiredArgumentException extends OptionException {
     private static final long serialVersionUID = -1L;
 
-    OptionMissingRequiredArgumentException( Collection<String> options ) {
-        super( options );
+    OptionMissingRequiredArgumentException( OptionSpec<?> option ) {
+        super( asList( option ) );
     }
 
     @Override
-    public String getMessage() {
-        return "Option " + multipleOptionMessage() + " requires an argument";
+    Object[] messageArguments() {
+        return new Object[] { singleOptionString() };
     }
 }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParser.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParser.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,18 +55,16 @@
 
 package jdk.internal.joptsimple;
 
-import jdk.internal.joptsimple.internal.AbbreviationMap;
-import jdk.internal.joptsimple.util.KeyValuePair;
-
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
+import java.util.*;
+
+import jdk.internal.joptsimple.internal.AbbreviationMap;
+import jdk.internal.joptsimple.internal.SimpleOptionNameMap;
+import jdk.internal.joptsimple.internal.OptionNameMap;
+import jdk.internal.joptsimple.util.KeyValuePair;
 
 import static java.util.Collections.*;
 import static jdk.internal.joptsimple.OptionException.*;
@@ -80,57 +78,58 @@
  * <p>This parser supports short options and long options.</p>
  *
  * <ul>
- *   <li><dfn>Short options</dfn> begin with a single hyphen ("<kbd>-</kbd>") followed by a single letter or digit,
- *   or question mark ("<kbd>?</kbd>"), or dot ("<kbd>.</kbd>").</li>
+ *   <li><dfn>Short options</dfn> begin with a single hyphen ("{@code -}") followed by a single letter or digit,
+ *   or question mark ("{@code ?}"), or dot ("{@code .}"), or underscore ("{@code _}").</li>
  *
  *   <li>Short options can accept single arguments. The argument can be made required or optional. The option's
  *   argument can occur:
  *     <ul>
- *       <li>in the slot after the option, as in <kbd>-d /tmp</kbd></li>
- *       <li>right up against the option, as in <kbd>-d/tmp</kbd></li>
- *       <li>right up against the option separated by an equals sign (<kbd>"="</kbd>), as in <kbd>-d=/tmp</kbd></li>
+ *       <li>in the slot after the option, as in {@code -d /tmp}</li>
+ *       <li>right up against the option, as in {@code -d/tmp}</li>
+ *       <li>right up against the option separated by an equals sign ({@code "="}), as in {@code -d=/tmp}</li>
  *     </ul>
  *   To specify <em>n</em> arguments for an option, specify the option <em>n</em> times, once for each argument,
- *   as in <kbd>-d /tmp -d /var -d /opt</kbd>; or, when using the
+ *   as in {@code -d /tmp -d /var -d /opt}; or, when using the
  *   {@linkplain ArgumentAcceptingOptionSpec#withValuesSeparatedBy(char) "separated values"} clause of the "fluent
  *   interface" (see below), give multiple values separated by a given character as a single argument to the
  *   option.</li>
  *
- *   <li>Short options can be clustered, so that <kbd>-abc</kbd> is treated as <kbd>-a -b -c</kbd>. If a short option
+ *   <li>Short options can be clustered, so that {@code -abc} is treated as {@code -a -b -c}. If a short option
  *   in the cluster can accept an argument, the remaining characters are interpreted as the argument for that
  *   option.</li>
  *
- *   <li>An argument consisting only of two hyphens (<kbd>"--"</kbd>) signals that the remaining arguments are to be
+ *   <li>An argument consisting only of two hyphens ({@code "--"}) signals that the remaining arguments are to be
  *   treated as non-options.</li>
  *
  *   <li>An argument consisting only of a single hyphen is considered a non-option argument (though it can be an
  *   argument of an option). Many Unix programs treat single hyphens as stand-ins for the standard input or standard
  *   output streams.</li>
  *
- *   <li><dfn>Long options</dfn> begin with two hyphens (<kbd>"--"</kbd>), followed by multiple letters, digits,
+ *   <li><dfn>Long options</dfn> begin with two hyphens ({@code "--"}), followed by multiple letters, digits,
  *   hyphens, question marks, or dots. A hyphen cannot be the first character of a long option specification when
  *   configuring the parser.</li>
  *
- *   <li>You can abbreviate long options, so long as the abbreviation is unique.</li>
+ *   <li>You can abbreviate long options, so long as the abbreviation is unique. Suppress this behavior if
+ *   you wish using {@linkplain OptionParser#OptionParser(boolean) this constructor}.</li>
  *
  *   <li>Long options can accept single arguments.  The argument can be made required or optional.  The option's
  *   argument can occur:
  *     <ul>
- *       <li>in the slot after the option, as in <kbd>--directory /tmp</kbd></li>
- *       <li>right up against the option separated by an equals sign (<kbd>"="</kbd>), as in
- *       <kbd>--directory=/tmp</kbd>
+ *       <li>in the slot after the option, as in {@code --directory /tmp}</li>
+ *       <li>right up against the option separated by an equals sign ({@code "="}), as in
+ *       {@code --directory=/tmp}
  *     </ul>
  *   Specify multiple arguments for a long option in the same manner as for short options (see above).</li>
  *
- *   <li>You can use a single hyphen (<kbd>"-"</kbd>) instead of a double hyphen (<kbd>"--"</kbd>) for a long
+ *   <li>You can use a single hyphen ({@code "-"}) instead of a double hyphen ({@code "--"}) for a long
  *   option.</li>
  *
- *   <li>The option <kbd>-W</kbd> is reserved.  If you tell the parser to {@linkplain
+ *   <li>The option {@code -W} is reserved.  If you tell the parser to {@linkplain
  *   #recognizeAlternativeLongOptions(boolean) recognize alternative long options}, then it will treat, for example,
- *   <kbd>-W foo=bar</kbd> as the long option <kbd>foo</kbd> with argument <kbd>bar</kbd>, as though you had written
- *   <kbd>--foo=bar</kbd>.</li>
+ *   {@code -W foo=bar} as the long option {@code foo} with argument {@code bar}, as though you had written
+ *   {@code --foo=bar}.</li>
  *
- *   <li>You can specify <kbd>-W</kbd> as a valid short option, or use it as an abbreviation for a long option, but
+ *   <li>You can specify {@code -W} as a valid short option, or use it as an abbreviation for a long option, but
  *   {@linkplain #recognizeAlternativeLongOptions(boolean) recognizing alternative long options} will always supersede
  *   this behavior.</li>
  *
@@ -148,15 +147,15 @@
  *     parser.accepts( "2" );
  *     OptionSet options = parser.parse( "-a", "-2" );
  *   </code></pre>
- *   In this case, the option set contains <kbd>"a"</kbd> with argument <kbd>-2</kbd>, not both <kbd>"a"</kbd> and
- *   <kbd>"2"</kbd>. Swapping the elements in the <em>args</em> array gives the latter.</li>
+ *   In this case, the option set contains {@code "a"} with argument {@code -2}, not both {@code "a"} and
+ *   {@code "2"}. Swapping the elements in the <em>args</em> array gives the latter.</li>
  * </ul>
  *
  * <p>There are two ways to tell the parser what options to recognize:</p>
  *
  * <ol>
  *   <li>A "fluent interface"-style API for specifying options, available since version 2. Sentences in this fluent
- *   interface language begin with a call to {@link #accepts(String) accepts} or {@link #acceptsAll(Collection)
+ *   interface language begin with a call to {@link #accepts(String) accepts} or {@link #acceptsAll(List)
  *   acceptsAll} methods; calls on the ensuing chain of objects describe whether the options can take an argument,
  *   whether the argument is required or optional, to what type arguments of the options should be converted if any,
  *   etc. Since version 3, these calls return an instance of {@link OptionSpec}, which can subsequently be used to
@@ -169,28 +168,28 @@
  *     <ul>
  *       <li>Any letter or digit is treated as an option character.</li>
  *
- *       <li>An option character can be immediately followed by an asterisk (*) to indicate that the option is a
- *       "help" option.</li>
+ *       <li>An option character can be immediately followed by an asterisk ({@code *)} to indicate that
+ *       the option is a "help" option.</li>
  *
- *       <li>If an option character (with possible trailing asterisk) is followed by a single colon (<kbd>":"</kbd>),
+ *       <li>If an option character (with possible trailing asterisk) is followed by a single colon ({@code ":"}),
  *       then the option requires an argument.</li>
  *
- *       <li>If an option character (with possible trailing asterisk) is followed by two colons (<kbd>"::"</kbd>),
+ *       <li>If an option character (with possible trailing asterisk) is followed by two colons ({@code "::"}),
  *       then the option accepts an optional argument.</li>
  *
  *       <li>Otherwise, the option character accepts no argument.</li>
  *
- *       <li>If the option specification string begins with a plus sign (<kbd>"+"</kbd>), the parser will behave
+ *       <li>If the option specification string begins with a plus sign ({@code "+" }), the parser will behave
  *       "POSIX-ly correct".</li>
  *
- *       <li>If the option specification string contains the sequence <kbd>"W;"</kbd> (capital W followed by a
+ *       <li>If the option specification string contains the sequence {@code "W;"} (capital W followed by a
  *       semicolon), the parser will recognize the alternative form of long options.</li>
  *     </ul>
  *   </li>
  * </ol>
  *
- * <p>Each of the options in a list of options given to {@link #acceptsAll(Collection) acceptsAll} is treated as a
- * synonym of the others.  For example:
+ * <p>Each of the options in a list of options given to {@link #acceptsAll(List) acceptsAll} is treated as a
+ * synonym of the others.  For example:</p>
  *   <pre>
  *     <code>
  *     OptionParser parser = new OptionParser();
@@ -198,14 +197,14 @@
  *     OptionSet options = parser.parse( "-w" );
  *     </code>
  *   </pre>
- * In this case, <code>options.{@link OptionSet#has(String) has}</code> would answer {@code true} when given arguments
- * <kbd>"w"</kbd>, <kbd>"interactive"</kbd>, and <kbd>"confirmation"</kbd>. The {@link OptionSet} would give the same
+ * <p>In this case, <code>options.{@link OptionSet#has(String) has}</code> would answer {@code true} when given arguments
+ * {@code "w"}, {@code "interactive"}, and {@code "confirmation"}. The {@link OptionSet} would give the same
  * responses to these arguments for its other methods as well.</p>
  *
  * <p>By default, as with GNU {@code getopt()}, the parser allows intermixing of options and non-options. If, however,
  * the parser has been created to be "POSIX-ly correct", then the first argument that does not look lexically like an
  * option, and is not a required argument of a preceding option, signals the end of options. You can still bind
- * optional arguments to their options using the abutting (for short options) or <kbd>=</kbd> syntax.</p>
+ * optional arguments to their options using the abutting (for short options) or {@code =} syntax.</p>
  *
  * <p>Unlike GNU {@code getopt()}, this parser does not honor the environment variable {@code POSIXLY_CORRECT}.
  * "POSIX-ly correct" parsers are configured by either:</p>
@@ -214,16 +213,20 @@
  *   <li>using the method {@link #posixlyCorrect(boolean)}, or</li>
  *
  *   <li>using the {@linkplain #OptionParser(String) constructor} with an argument whose first character is a plus sign
- *   (<kbd>"+"</kbd>)</li>
+ *   ({@code "+"})</li>
  * </ol>
  *
  * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
  * @see <a href="http://www.gnu.org/software/libc/manual">The GNU C Library</a>
  */
 public class OptionParser implements OptionDeclarer {
-    private final AbbreviationMap<AbstractOptionSpec<?>> recognizedOptions;
-    private final Map<Collection<String>, Set<OptionSpec<?>>> requiredIf;
-    private final Map<Collection<String>, Set<OptionSpec<?>>> requiredUnless;
+    private final OptionNameMap<AbstractOptionSpec<?>> recognizedOptions;
+    private final ArrayList<AbstractOptionSpec<?>> trainingOrder;
+    private final Map<List<String>, Set<OptionSpec<?>>> requiredIf;
+    private final Map<List<String>, Set<OptionSpec<?>>> requiredUnless;
+    private final Map<List<String>, Set<OptionSpec<?>>> availableIf;
+    private final Map<List<String>, Set<OptionSpec<?>>> availableUnless;
+
     private OptionParserState state;
     private boolean posixlyCorrect;
     private boolean allowsUnrecognizedOptions;
@@ -234,11 +237,28 @@
      * behavior.
      */
     public OptionParser() {
-        recognizedOptions = new AbbreviationMap<AbstractOptionSpec<?>>();
-        requiredIf = new HashMap<Collection<String>, Set<OptionSpec<?>>>();
-        requiredUnless = new HashMap<Collection<String>, Set<OptionSpec<?>>>();
+        this(true);
+    }
+
+    /**
+     * Creates an option parser that initially recognizes no options, and does not exhibit "POSIX-ly correct"
+     * behavior.
+     *
+     * @param allowAbbreviations whether unambiguous abbreviations of long options should be recognized
+     * by the parser
+     */
+    public OptionParser( boolean allowAbbreviations ) {
+        trainingOrder = new ArrayList<>();
+        requiredIf = new HashMap<>();
+        requiredUnless = new HashMap<>();
+        availableIf = new HashMap<>();
+        availableUnless = new HashMap<>();
         state = moreOptions( false );
 
+        recognizedOptions = allowAbbreviations
+            ? new AbbreviationMap<AbstractOptionSpec<?>>()
+            : new SimpleOptionNameMap<AbstractOptionSpec<?>>();
+
         recognize( new NonOptionArgumentSpec<String>() );
     }
 
@@ -266,11 +286,11 @@
         return acceptsAll( singletonList( option ), description );
     }
 
-    public OptionSpecBuilder acceptsAll( Collection<String> options ) {
+    public OptionSpecBuilder acceptsAll( List<String> options ) {
         return acceptsAll( options, "" );
     }
 
-    public OptionSpecBuilder acceptsAll( Collection<String> options, String description ) {
+    public OptionSpecBuilder acceptsAll( List<String> options, String description ) {
         if ( options.isEmpty() )
             throw new IllegalArgumentException( "need at least one option" );
 
@@ -280,7 +300,7 @@
     }
 
     public NonOptionArgumentSpec<String> nonOptions() {
-        NonOptionArgumentSpec<String> spec = new NonOptionArgumentSpec<String>();
+        NonOptionArgumentSpec<String> spec = new NonOptionArgumentSpec<>();
 
         recognize( spec );
 
@@ -288,7 +308,7 @@
     }
 
     public NonOptionArgumentSpec<String> nonOptions( String description ) {
-        NonOptionArgumentSpec<String> spec = new NonOptionArgumentSpec<String>( description );
+        NonOptionArgumentSpec<String> spec = new NonOptionArgumentSpec<>( description );
 
         recognize( spec );
 
@@ -321,6 +341,7 @@
 
     void recognize( AbstractOptionSpec<?> spec ) {
         recognizedOptions.putAll( spec.options(), spec );
+        trainingOrder.add( spec );
     }
 
     /**
@@ -348,7 +369,7 @@
      * @see #printHelpOn(OutputStream)
      */
     public void printHelpOn( Writer sink ) throws IOException {
-        sink.write( helpFormatter.format( recognizedOptions.toJavaUtilMap() ) );
+        sink.write( helpFormatter.format( _recognizedOptions() ) );
         sink.flush();
     }
 
@@ -366,15 +387,29 @@
     }
 
     /**
-     * Retrieves all the options which have been configured for the parser.
+     * Retrieves all options-spec pairings which have been configured for the parser in the same order as declared
+     * during training. Option flags for specs are alphabetized by {@link OptionSpec#options()}; only the order of the
+     * specs is preserved.
      *
-     * @return a {@link Map} containing all the configured options and their corresponding {@link OptionSpec}
+     * (Note: prior to 4.7 the order was alphabetical across all options regardless of spec.)
+     *
+     * @return a map containing all the configured options and their corresponding {@link OptionSpec}
+     * @since 4.6
      */
     public Map<String, OptionSpec<?>> recognizedOptions() {
-        return new HashMap<String, OptionSpec<?>>( recognizedOptions.toJavaUtilMap() );
+        return new LinkedHashMap<String, OptionSpec<?>>( _recognizedOptions() );
     }
 
-    /**
+    private Map<String, AbstractOptionSpec<?>> _recognizedOptions() {
+        Map<String, AbstractOptionSpec<?>> options = new LinkedHashMap<>();
+        for ( AbstractOptionSpec<?> spec : trainingOrder ) {
+            for ( String option : spec.options() )
+                options.put( option, spec );
+        }
+        return options;
+    }
+
+   /**
      * Parses the given command line arguments according to the option specifications given to the parser.
      *
      * @param arguments arguments to parse
@@ -393,43 +428,87 @@
         reset();
 
         ensureRequiredOptions( detected );
+        ensureAllowedOptions( detected );
 
         return detected;
     }
 
+    /**
+     * Mandates mutual exclusiveness for the options built by the specified builders.
+     *
+     * @param specs descriptors for options that should be mutually exclusive on a command line.
+     * @throws NullPointerException if {@code specs} is {@code null}
+     */
+    public void mutuallyExclusive( OptionSpecBuilder... specs ) {
+        for ( int i = 0; i < specs.length; i++ ) {
+            for ( int j = 0; j < specs.length; j++ ) {
+                if ( i != j )
+                    specs[i].availableUnless( specs[j] );
+            }
+        }
+    }
+
     private void ensureRequiredOptions( OptionSet options ) {
-        Collection<String> missingRequiredOptions = missingRequiredOptions( options );
+        List<AbstractOptionSpec<?>> missingRequiredOptions = missingRequiredOptions(options);
         boolean helpOptionPresent = isHelpOptionPresent( options );
 
         if ( !missingRequiredOptions.isEmpty() && !helpOptionPresent )
-            throw new MissingRequiredOptionException( missingRequiredOptions );
+            throw new MissingRequiredOptionsException( missingRequiredOptions );
     }
 
-    private Collection<String> missingRequiredOptions( OptionSet options ) {
-        Collection<String> missingRequiredOptions = new HashSet<String>();
+    private void ensureAllowedOptions( OptionSet options ) {
+        List<AbstractOptionSpec<?>> forbiddenOptions = unavailableOptions( options );
+        boolean helpOptionPresent = isHelpOptionPresent( options );
+
+        if ( !forbiddenOptions.isEmpty() && !helpOptionPresent )
+            throw new UnavailableOptionException( forbiddenOptions );
+    }
+
+    private List<AbstractOptionSpec<?>> missingRequiredOptions( OptionSet options ) {
+        List<AbstractOptionSpec<?>> missingRequiredOptions = new ArrayList<>();
 
         for ( AbstractOptionSpec<?> each : recognizedOptions.toJavaUtilMap().values() ) {
             if ( each.isRequired() && !options.has( each ) )
-                missingRequiredOptions.addAll( each.options() );
+                missingRequiredOptions.add(each);
         }
 
-        for ( Map.Entry<Collection<String>, Set<OptionSpec<?>>> eachEntry : requiredIf.entrySet() ) {
-            AbstractOptionSpec<?> required = specFor( eachEntry.getKey().iterator().next() );
+        for ( Map.Entry<List<String>, Set<OptionSpec<?>>> each : requiredIf.entrySet() ) {
+            AbstractOptionSpec<?> required = specFor( each.getKey().iterator().next() );
 
-            if ( optionsHasAnyOf( options, eachEntry.getValue() ) && !options.has( required ) ) {
-                missingRequiredOptions.addAll( required.options() );
+            if ( optionsHasAnyOf( options, each.getValue() ) && !options.has( required ) )
+                missingRequiredOptions.add( required );
+        }
+
+        for ( Map.Entry<List<String>, Set<OptionSpec<?>>> each : requiredUnless.entrySet() ) {
+            AbstractOptionSpec<?> required = specFor(each.getKey().iterator().next());
+
+            if ( !optionsHasAnyOf( options, each.getValue() ) && !options.has( required ) )
+                missingRequiredOptions.add( required );
+        }
+
+        return missingRequiredOptions;
+    }
+
+    private List<AbstractOptionSpec<?>> unavailableOptions(OptionSet options) {
+        List<AbstractOptionSpec<?>> unavailableOptions = new ArrayList<>();
+
+        for ( Map.Entry<List<String>, Set<OptionSpec<?>>> eachEntry : availableIf.entrySet() ) {
+            AbstractOptionSpec<?> forbidden = specFor( eachEntry.getKey().iterator().next() );
+
+            if ( !optionsHasAnyOf( options, eachEntry.getValue() ) && options.has( forbidden ) ) {
+                unavailableOptions.add(forbidden);
             }
         }
 
-        for ( Map.Entry<Collection<String>, Set<OptionSpec<?>>> eachEntry : requiredUnless.entrySet() ) {
-            AbstractOptionSpec<?> required = specFor( eachEntry.getKey().iterator().next() );
+        for ( Map.Entry<List<String>, Set<OptionSpec<?>>> eachEntry : availableUnless.entrySet() ) {
+            AbstractOptionSpec<?> forbidden = specFor( eachEntry.getKey().iterator().next() );
 
-            if ( !optionsHasAnyOf( options, eachEntry.getValue() ) && !options.has( required ) ) {
-                missingRequiredOptions.addAll( required.options() );
+            if ( optionsHasAnyOf( options, eachEntry.getValue() ) && options.has( forbidden ) ) {
+                unavailableOptions.add(forbidden);
             }
         }
 
-        return missingRequiredOptions;
+        return unavailableOptions;
     }
 
     private boolean optionsHasAnyOf( OptionSet options, Collection<OptionSpec<?>> specs ) {
@@ -443,12 +522,14 @@
 
     private boolean isHelpOptionPresent( OptionSet options ) {
         boolean helpOptionPresent = false;
+
         for ( AbstractOptionSpec<?> each : recognizedOptions.toJavaUtilMap().values() ) {
             if ( each.isForHelp() && options.has( each ) ) {
                 helpOptionPresent = true;
                 break;
             }
         }
+
         return helpOptionPresent;
     }
 
@@ -505,24 +586,40 @@
         return recognizedOptions.contains( option );
     }
 
-    void requiredIf( Collection<String> precedentSynonyms, String required ) {
+    void requiredIf( List<String> precedentSynonyms, String required ) {
         requiredIf( precedentSynonyms, specFor( required ) );
     }
 
-    void requiredIf( Collection<String> precedentSynonyms, OptionSpec<?> required ) {
-        putRequiredOption( precedentSynonyms, required, requiredIf );
+    void requiredIf( List<String> precedentSynonyms, OptionSpec<?> required ) {
+        putDependentOption( precedentSynonyms, required, requiredIf );
     }
 
-    void requiredUnless( Collection<String> precedentSynonyms, String required ) {
+    void requiredUnless( List<String> precedentSynonyms, String required ) {
         requiredUnless( precedentSynonyms, specFor( required ) );
     }
 
-    void requiredUnless( Collection<String> precedentSynonyms, OptionSpec<?> required ) {
-        putRequiredOption( precedentSynonyms, required, requiredUnless );
+    void requiredUnless( List<String> precedentSynonyms, OptionSpec<?> required ) {
+        putDependentOption( precedentSynonyms, required, requiredUnless );
     }
 
-    private void putRequiredOption( Collection<String> precedentSynonyms, OptionSpec<?> required,
-        Map<Collection<String>, Set<OptionSpec<?>>> target ) {
+    void availableIf( List<String> precedentSynonyms, String available ) {
+        availableIf( precedentSynonyms, specFor( available ) );
+    }
+
+    void availableIf( List<String> precedentSynonyms, OptionSpec<?> available) {
+        putDependentOption( precedentSynonyms, available, availableIf );
+    }
+
+    void availableUnless( List<String> precedentSynonyms, String available ) {
+        availableUnless( precedentSynonyms, specFor( available ) );
+    }
+
+    void availableUnless( List<String> precedentSynonyms, OptionSpec<?> available ) {
+        putDependentOption( precedentSynonyms, available, availableUnless );
+    }
+
+    private void putDependentOption( List<String> precedentSynonyms, OptionSpec<?> required,
+        Map<List<String>, Set<OptionSpec<?>>> target ) {
 
         for ( String each : precedentSynonyms ) {
             AbstractOptionSpec<?> spec = specFor( each );
@@ -532,7 +629,7 @@
 
         Set<OptionSpec<?>> associated = target.get( precedentSynonyms );
         if ( associated == null ) {
-            associated = new HashSet<OptionSpec<?>>();
+            associated = new HashSet<>();
             target.put( precedentSynonyms, associated );
         }
 
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParserState.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionParserState.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSet.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSet.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,11 +55,14 @@
 
 package jdk.internal.joptsimple;
 
-import java.util.*;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
 
 import static java.util.Collections.*;
-
-import static jdk.internal.joptsimple.internal.Objects.*;
+import static java.util.Objects.*;
 
 /**
  * Representation of a group of detected command line options, their arguments, and non-option arguments.
@@ -77,9 +80,9 @@
      * Package-private because clients don't create these.
      */
     OptionSet( Map<String, AbstractOptionSpec<?>> recognizedSpecs ) {
-        detectedSpecs = new ArrayList<OptionSpec<?>>();
-        detectedOptions = new HashMap<String, AbstractOptionSpec<?>>();
-        optionsToArguments = new IdentityHashMap<AbstractOptionSpec<?>, List<String>>();
+        detectedSpecs = new ArrayList<>();
+        detectedOptions = new HashMap<>();
+        optionsToArguments = new IdentityHashMap<>();
         defaultValues = defaultValues( recognizedSpecs );
         this.recognizedSpecs = recognizedSpecs;
     }
@@ -90,7 +93,7 @@
      * @return {@code true} if any options were detected
      */
     public boolean hasOptions() {
-        return !detectedOptions.isEmpty();
+        return !( detectedOptions.size() == 1 && detectedOptions.values().iterator().next().representsNonOptions() );
     }
 
     /**
@@ -148,7 +151,7 @@
      * @see #hasArgument(String)
      */
     public boolean hasArgument( OptionSpec<?> option ) {
-        ensureNotNull( option );
+        requireNonNull( option );
 
         List<String> values = optionsToArguments.get( option );
         return values != null && !values.isEmpty();
@@ -169,7 +172,7 @@
      * @throws OptionException if more than one argument was detected for the option
      */
     public Object valueOf( String option ) {
-        ensureNotNull( option );
+        requireNonNull( option );
 
         AbstractOptionSpec<?> spec = detectedOptions.get( option );
         if ( spec == null ) {
@@ -194,7 +197,7 @@
      * @throws ClassCastException if the arguments of this option are not of the expected type
      */
     public <V> V valueOf( OptionSpec<V> option ) {
-        ensureNotNull( option );
+        requireNonNull( option );
 
         List<V> values = valuesOf( option );
         switch ( values.size() ) {
@@ -203,7 +206,7 @@
             case 1:
                 return values.get( 0 );
             default:
-                throw new MultipleArgumentsForOptionException( option.options() );
+                throw new MultipleArgumentsForOptionException( option );
         }
     }
 
@@ -217,7 +220,7 @@
      * @throws NullPointerException if {@code option} is {@code null}
      */
     public List<?> valuesOf( String option ) {
-        ensureNotNull( option );
+        requireNonNull( option );
 
         AbstractOptionSpec<?> spec = detectedOptions.get( option );
         return spec == null ? defaultValuesFor( option ) : valuesOf( spec );
@@ -238,14 +241,14 @@
      * example, if the type does not implement a correct conversion constructor or method
      */
     public <V> List<V> valuesOf( OptionSpec<V> option ) {
-        ensureNotNull( option );
+        requireNonNull( option );
 
         List<String> values = optionsToArguments.get( option );
         if ( values == null || values.isEmpty() )
             return defaultValueFor( option );
 
         AbstractOptionSpec<V> spec = (AbstractOptionSpec<V>) option;
-        List<V> convertedValues = new ArrayList<V>();
+        List<V> convertedValues = new ArrayList<>();
         for ( String each : values )
             convertedValues.add( spec.convert( each ) );
 
@@ -260,7 +263,7 @@
      */
     public List<OptionSpec<?>> specs() {
         List<OptionSpec<?>> specs = detectedSpecs;
-        specs.remove( detectedOptions.get( NonOptionArgumentSpec.NAME ) );
+        specs.removeAll( singletonList( detectedOptions.get( NonOptionArgumentSpec.NAME ) ) );
 
         return unmodifiableList( specs );
     }
@@ -271,10 +274,13 @@
      * @return the declared options as a map
      */
     public Map<OptionSpec<?>, List<?>> asMap() {
-        Map<OptionSpec<?>, List<?>> map = new HashMap<OptionSpec<?>, List<?>>();
-        for ( AbstractOptionSpec<?> spec : recognizedSpecs.values() )
+        Map<OptionSpec<?>, List<?>> map = new HashMap<>();
+
+        for ( AbstractOptionSpec<?> spec : recognizedSpecs.values() ) {
             if ( !spec.representsNonOptions() )
                 map.put( spec, valuesOf( spec ) );
+        }
+
         return unmodifiableMap( map );
     }
 
@@ -282,7 +288,8 @@
      * @return the detected non-option arguments
      */
     public List<?> nonOptionArguments() {
-        return unmodifiableList( valuesOf( detectedOptions.get( NonOptionArgumentSpec.NAME ) ) );
+        AbstractOptionSpec<?> spec = detectedOptions.get( NonOptionArgumentSpec.NAME );
+        return valuesOf( spec );
     }
 
     void add( AbstractOptionSpec<?> spec ) {
@@ -298,7 +305,7 @@
         List<String> optionArguments = optionsToArguments.get( spec );
 
         if ( optionArguments == null ) {
-            optionArguments = new ArrayList<String>();
+            optionArguments = new ArrayList<>();
             optionsToArguments.put( spec, optionArguments );
         }
 
@@ -315,25 +322,22 @@
             return false;
 
         OptionSet other = (OptionSet) that;
-        Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments =
-            new HashMap<AbstractOptionSpec<?>, List<String>>( optionsToArguments );
-        Map<AbstractOptionSpec<?>, List<String>> otherOptionsToArguments =
-            new HashMap<AbstractOptionSpec<?>, List<String>>( other.optionsToArguments );
+        Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments = new HashMap<>( optionsToArguments );
+        Map<AbstractOptionSpec<?>, List<String>> otherOptionsToArguments = new HashMap<>( other.optionsToArguments );
         return detectedOptions.equals( other.detectedOptions )
             && thisOptionsToArguments.equals( otherOptionsToArguments );
     }
 
     @Override
     public int hashCode() {
-        Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments =
-            new HashMap<AbstractOptionSpec<?>, List<String>>( optionsToArguments );
+        Map<AbstractOptionSpec<?>, List<String>> thisOptionsToArguments = new HashMap<>( optionsToArguments );
         return detectedOptions.hashCode() ^ thisOptionsToArguments.hashCode();
     }
 
     @SuppressWarnings( "unchecked" )
     private <V> List<V> defaultValuesFor( String option ) {
         if ( defaultValues.containsKey( option ) )
-            return (List<V>) defaultValues.get( option );
+            return unmodifiableList( (List<V>) defaultValues.get( option ) );
 
         return emptyList();
     }
@@ -343,7 +347,7 @@
     }
 
     private static Map<String, List<?>> defaultValues( Map<String, AbstractOptionSpec<?>> recognizedSpecs ) {
-        Map<String, List<?>> defaults = new HashMap<String, List<?>>();
+        Map<String, List<?>> defaults = new HashMap<>();
         for ( Map.Entry<String, AbstractOptionSpec<?>> each : recognizedSpecs.entrySet() )
             defaults.put( each.getKey(), each.getValue().defaultValues() );
         return defaults;
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpec.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpec.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,7 +55,6 @@
 
 package jdk.internal.joptsimple;
 
-import java.util.Collection;
 import java.util.List;
 
 /**
@@ -116,7 +115,7 @@
     /**
      * @return the string representations of this option
      */
-    Collection<String> options();
+    List<String> options();
 
     /**
      * Tells whether this option is designated as a "help" option. The presence of a "help" option on a command line
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecBuilder.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecBuilder.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -56,7 +56,6 @@
 package jdk.internal.joptsimple;
 
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.List;
 
@@ -90,7 +89,7 @@
 public class OptionSpecBuilder extends NoArgumentOptionSpec {
     private final OptionParser parser;
 
-    OptionSpecBuilder( OptionParser parser, Collection<String> options, String description ) {
+    OptionSpecBuilder( OptionParser parser, List<String> options, String description ) {
         super( options, description );
 
         this.parser = parser;
@@ -107,8 +106,7 @@
      * @return a specification for the option
      */
     public ArgumentAcceptingOptionSpec<String> withRequiredArg() {
-        ArgumentAcceptingOptionSpec<String> newSpec =
-            new RequiredArgumentOptionSpec<String>( options(), description() );
+        ArgumentAcceptingOptionSpec<String> newSpec = new RequiredArgumentOptionSpec<>( options(), description() );
         parser.recognize( newSpec );
 
         return newSpec;
@@ -121,7 +119,7 @@
      */
     public ArgumentAcceptingOptionSpec<String> withOptionalArg() {
         ArgumentAcceptingOptionSpec<String> newSpec =
-            new OptionalArgumentOptionSpec<String>( options(), description() );
+            new OptionalArgumentOptionSpec<>( options(), description() );
         parser.recognize( newSpec );
 
         return newSpec;
@@ -141,9 +139,8 @@
      */
     public OptionSpecBuilder requiredIf( String dependent, String... otherDependents ) {
         List<String> dependents = validatedDependents( dependent, otherDependents );
-        for ( String each : dependents ) {
+        for ( String each : dependents )
             parser.requiredIf( options(), each );
-        }
 
         return this;
     }
@@ -210,8 +207,91 @@
         return this;
     }
 
+    /**
+     * <p>Informs an option parser that this builder's option is allowed if the given option is present on the command
+     * line.</p>
+     *
+     * <p>For a given option, you <em>should not</em> mix this with {@link #availableUnless(String, String...)
+     * availableUnless} to avoid conflicts.</p>
+     *
+     * @param dependent an option whose presence on a command line makes this builder's option allowed
+     * @param otherDependents other options whose presence on a command line makes this builder's option allowed
+     * @return self, so that the caller can add clauses to the fluent interface sentence
+     * @throws OptionException if any of the dependent options haven't been configured in the parser yet
+     */
+    public OptionSpecBuilder availableIf( String dependent, String... otherDependents ) {
+        List<String> dependents = validatedDependents( dependent, otherDependents );
+        for ( String each : dependents )
+            parser.availableIf( options(), each );
+
+        return this;
+    }
+
+    /**
+     * <p>Informs an option parser that this builder's option is allowed if the given option is present on the command
+     * line.</p>
+     *
+     * <p>For a given option, you <em>should not</em> mix this with {@link #availableUnless(OptionSpec, OptionSpec[])
+     * requiredUnless} to avoid conflicts.</p>
+     *
+     * <p>This method recognizes only instances of options returned from the fluent interface methods.</p>
+     *
+     * @param dependent the option whose presence on a command line makes this builder's option allowed
+     * @param otherDependents other options whose presence on a command line makes this builder's option allowed
+     * @return self, so that the caller can add clauses to the fluent interface sentence
+     */
+    public OptionSpecBuilder availableIf( OptionSpec<?> dependent, OptionSpec<?>... otherDependents ) {
+        parser.availableIf( options(), dependent );
+
+        for ( OptionSpec<?> each : otherDependents )
+            parser.availableIf( options(), each );
+
+        return this;
+    }
+
+    /**
+     * <p>Informs an option parser that this builder's option is allowed if the given option is absent on the command
+     * line.</p>
+     *
+     * <p>For a given option, you <em>should not</em> mix this with {@link #availableIf(OptionSpec, OptionSpec[])
+     * requiredIf} to avoid conflicts.</p>
+     *
+     * @param dependent an option whose absence on a command line makes this builder's option allowed
+     * @param otherDependents other options whose absence on a command line makes this builder's option allowed
+     * @return self, so that the caller can add clauses to the fluent interface sentence
+     * @throws OptionException if any of the dependent options haven't been configured in the parser yet
+     */
+    public OptionSpecBuilder availableUnless( String dependent, String... otherDependents ) {
+        List<String> dependents = validatedDependents( dependent, otherDependents );
+        for ( String each : dependents )
+            parser.availableUnless( options(), each );
+
+        return this;
+    }
+
+    /**
+     * <p>Informs an option parser that this builder's option is allowed if the given option is absent on the command
+     * line.</p>
+     *
+     * <p>For a given option, you <em>should not</em> mix this with {@link #availableIf(OptionSpec, OptionSpec[])
+     * requiredIf} to avoid conflicts.</p>
+     *
+     * <p>This method recognizes only instances of options returned from the fluent interface methods.</p>
+     *
+     * @param dependent the option whose absence on a command line makes this builder's option allowed
+     * @param otherDependents other options whose absence on a command line makes this builder's option allowed
+     * @return self, so that the caller can add clauses to the fluent interface sentence
+     */
+    public OptionSpecBuilder availableUnless( OptionSpec<?> dependent, OptionSpec<?>... otherDependents ) {
+        parser.availableUnless( options(), dependent );
+        for ( OptionSpec<?> each : otherDependents )
+            parser.availableUnless(options(), each);
+
+        return this;
+    }
+
     private List<String> validatedDependents( String dependent, String... otherDependents ) {
-        List<String> dependents = new ArrayList<String>();
+        List<String> dependents = new ArrayList<>();
         dependents.add( dependent );
         Collections.addAll( dependents, otherDependents );
 
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecTokenizer.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionSpecTokenizer.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionalArgumentOptionSpec.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/OptionalArgumentOptionSpec.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,7 +55,7 @@
 
 package jdk.internal.joptsimple;
 
-import java.util.Collection;
+import java.util.List;
 
 /**
  * Specification of an option that accepts an optional argument.
@@ -68,7 +68,7 @@
         super( option, false );
     }
 
-    OptionalArgumentOptionSpec( Collection<String> options, String description ) {
+    OptionalArgumentOptionSpec( List<String> options, String description ) {
         super( options, false, description );
     }
 
@@ -77,7 +77,7 @@
         if ( arguments.hasMore() ) {
             String nextArgument = arguments.peek();
 
-            if ( !parser.looksLikeAnOption( nextArgument ) )
+            if ( !parser.looksLikeAnOption( nextArgument ) && canConvertArgument( nextArgument ) )
                 handleOptionArgument( parser, detectedOptions, arguments );
             else if ( isArgumentOfNumberType() && canConvertArgument( nextArgument ) )
                 addArguments( detectedOptions, arguments.next() );
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ParserRules.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ParserRules.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,7 +55,7 @@
 
 package jdk.internal.joptsimple;
 
-import java.util.Collection;
+import java.util.List;
 
 import static java.lang.Character.*;
 
@@ -97,7 +97,7 @@
             ensureLegalOptionCharacter( option.charAt( i ) );
     }
 
-    static void ensureLegalOptions( Collection<String> options ) {
+    static void ensureLegalOptions( List<String> options ) {
         for ( String each : options )
             ensureLegalOption( each );
     }
@@ -108,7 +108,7 @@
     }
 
     private static boolean isAllowedPunctuation( char option ) {
-        String allowedPunctuation = "?." + HYPHEN_CHAR;
+        String allowedPunctuation = "?._" + HYPHEN_CHAR;
         return allowedPunctuation.indexOf( option ) != -1;
     }
 }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/README	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/README	Wed Jun 06 15:36:29 2018 +0200
@@ -1,3 +1,3 @@
-JOpt Simple, Version 4.6
+JOpt Simple, Version 5.0.4
 https://pholser.github.io/jopt-simple/
 
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/RequiredArgumentOptionSpec.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/RequiredArgumentOptionSpec.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,7 +55,7 @@
 
 package jdk.internal.joptsimple;
 
-import java.util.Collection;
+import java.util.List;
 
 /**
  * Specification of an option that accepts a required argument.
@@ -68,14 +68,14 @@
         super( option, true );
     }
 
-    RequiredArgumentOptionSpec( Collection<String> options, String description ) {
+    RequiredArgumentOptionSpec( List<String> options, String description ) {
         super( options, true, description );
     }
 
     @Override
     protected void detectOptionArgument( OptionParser parser, ArgumentList arguments, OptionSet detectedOptions ) {
         if ( !arguments.hasMore() )
-            throw new OptionMissingRequiredArgumentException( options() );
+            throw new OptionMissingRequiredArgumentException( this );
 
         addArguments( detectedOptions, arguments.next() );
     }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnacceptableNumberOfNonOptionsException.java	Wed Jun 06 13:06:21 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,84 +0,0 @@
-/*
- * Copyright (c) 2009, 2015, 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.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * The MIT License
- *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-package jdk.internal.joptsimple;
-
-import static java.util.Collections.*;
-
-/**
- * Thrown when the option parser detects an unacceptable number of {@code linkplain NonOptionArgumentSpec
- * non-option arguments}.
- *
- * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
- */
-class UnacceptableNumberOfNonOptionsException extends OptionException {
-    private static final long serialVersionUID = -1L;
-    private final int minimum;
-    private final int maximum;
-    private final int actual;
-
-    UnacceptableNumberOfNonOptionsException( int minimum, int maximum, int actual ) {
-        super( singletonList( NonOptionArgumentSpec.NAME ) );
-
-        this.minimum = minimum;
-        this.maximum = maximum;
-        this.actual = actual;
-    }
-
-    @Override
-    public String getMessage() {
-        return String.format( "actual = %d, minimum = %d, maximum = %d", actual, minimum, maximum );
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnavailableOptionException.java	Wed Jun 06 15:36:29 2018 +0200
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * The MIT License
+ *
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package jdk.internal.joptsimple;
+
+import java.util.List;
+
+/**
+ * Thrown when options marked as allowed are specified on the command line, but the options they depend upon are
+ * present/not present.
+ */
+class UnavailableOptionException extends OptionException {
+    private static final long serialVersionUID = -1L;
+
+    UnavailableOptionException( List<? extends OptionSpec<?>> forbiddenOptions ) {
+        super( forbiddenOptions );
+    }
+
+    @Override
+    Object[] messageArguments() {
+        return new Object[] { multipleOptionString() };
+    }
+}
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnconfiguredOptionException.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnconfiguredOptionException.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,7 +55,7 @@
 
 package jdk.internal.joptsimple;
 
-import java.util.Collection;
+import java.util.List;
 
 import static java.util.Collections.*;
 
@@ -71,12 +71,12 @@
         this( singletonList( option ) );
     }
 
-    UnconfiguredOptionException( Collection<String> options ) {
+    UnconfiguredOptionException( List<String> options ) {
         super( options );
     }
 
     @Override
-    public String getMessage() {
-        return "Option " + multipleOptionMessage() + " has not been configured on this parser";
+    Object[] messageArguments() {
+        return new Object[] { multipleOptionString() };
     }
 }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnrecognizedOptionException.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/UnrecognizedOptionException.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -70,7 +70,7 @@
     }
 
     @Override
-    public String getMessage() {
-        return singleOptionMessage() + " is not a recognized option";
+    Object[] messageArguments() {
+        return new Object[] { singleOptionString() };
     }
 }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConversionException.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConversionException.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConverter.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/ValueConverter.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -76,7 +76,7 @@
      *
      * @return the target class for conversion
      */
-    Class<V> valueType();
+    Class<? extends V> valueType();
 
     /**
      * Gives a string that describes the pattern of the values this converter expects, if any.  For example, a date
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/AbbreviationMap.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/AbbreviationMap.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -84,37 +84,41 @@
  *
  * @param <V> a constraint on the types of the values in the map
  * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
- * @see <a href="http://www.perldoc.com/perl5.8.0/lib/Text/Abbrev.html">Perl's Text::Abbrev module</a>
+ * @see <a href="http://perldoc.perl.org/Text/Abbrev.html">Perl's Text::Abbrev module</a>
+ * @see <a href="https://en.wikipedia.org/wiki/Radix_tree">Radix tree</a>
  */
-public class AbbreviationMap<V> {
+public class AbbreviationMap<V> implements OptionNameMap<V> {
+    private final Map<Character, AbbreviationMap<V>> children = new TreeMap<>();
+
     private String key;
     private V value;
-    private final Map<Character, AbbreviationMap<V>> children = new TreeMap<Character, AbbreviationMap<V>>();
     private int keysBeyond;
 
     /**
      * <p>Tells whether the given key is in the map, or whether the given key is a unique
      * abbreviation of a key that is in the map.</p>
      *
-     * @param aKey key to look up
+     * @param key key to look up
      * @return {@code true} if {@code key} is present in the map
      * @throws NullPointerException if {@code key} is {@code null}
      */
-    public boolean contains( String aKey ) {
-        return get( aKey ) != null;
+    @Override
+    public boolean contains(String key) {
+        return get(key) != null;
     }
 
     /**
      * <p>Answers the value associated with the given key.  The key can be a unique
      * abbreviation of a key that is in the map. </p>
      *
-     * @param aKey key to look up
+     * @param key key to look up
      * @return the value associated with {@code aKey}; or {@code null} if there is no
      * such value or {@code aKey} is not a unique abbreviation of a key in the map
      * @throws NullPointerException if {@code aKey} is {@code null}
      */
-    public V get( String aKey ) {
-        char[] chars = charsOf( aKey );
+    @Override
+    public V get( String key ) {
+        char[] chars = charsOf( key );
 
         AbbreviationMap<V> child = this;
         for ( char each : chars ) {
@@ -130,18 +134,19 @@
      * <p>Associates a given value with a given key.  If there was a previous
      * association, the old value is replaced with the new one.</p>
      *
-     * @param aKey key to create in the map
+     * @param key key to create in the map
      * @param newValue value to associate with the key
      * @throws NullPointerException if {@code aKey} or {@code newValue} is {@code null}
      * @throws IllegalArgumentException if {@code aKey} is a zero-length string
      */
-    public void put( String aKey, V newValue ) {
+    @Override
+    public void put( String key, V newValue ) {
         if ( newValue == null )
             throw new NullPointerException();
-        if ( aKey.length() == 0 )
+        if ( key.length() == 0 )
             throw new IllegalArgumentException();
 
-        char[] chars = charsOf( aKey );
+        char[] chars = charsOf(key);
         add( chars, newValue, 0, chars.length );
     }
 
@@ -154,6 +159,7 @@
      * @throws NullPointerException if {@code keys} or {@code newValue} is {@code null}
      * @throws IllegalArgumentException if any of {@code keys} is a zero-length string
      */
+    @Override
     public void putAll( Iterable<String> keys, V newValue ) {
         for ( String each : keys )
             put( each, newValue );
@@ -170,7 +176,7 @@
         char nextChar = chars[ offset ];
         AbbreviationMap<V> child = children.get( nextChar );
         if ( child == null ) {
-            child = new AbbreviationMap<V>();
+            child = new AbbreviationMap<>();
             children.put( nextChar, child );
         }
 
@@ -188,15 +194,16 @@
     /**
      * <p>If the map contains the given key, dissociates the key from its value.</p>
      *
-     * @param aKey key to remove
+     * @param key key to remove
      * @throws NullPointerException if {@code aKey} is {@code null}
      * @throws IllegalArgumentException if {@code aKey} is a zero-length string
      */
-    public void remove( String aKey ) {
-        if ( aKey.length() == 0 )
+    @Override
+    public void remove( String key ) {
+        if ( key.length() == 0 )
             throw new IllegalArgumentException();
 
-        char[] keyChars = charsOf( aKey );
+        char[] keyChars = charsOf(key);
         remove( keyChars, 0, keyChars.length );
     }
 
@@ -242,8 +249,9 @@
      *
      * @return a Java map corresponding to this abbreviation map
      */
+    @Override
     public Map<String, V> toJavaUtilMap() {
-        Map<String, V> mappings = new TreeMap<String, V>();
+        Map<String, V> mappings = new TreeMap<>();
         addToMappings( mappings );
         return mappings;
     }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Classes.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Classes.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -62,7 +62,7 @@
  * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
  */
 public final class Classes {
-    private static final Map<Class<?>, Class<?>> WRAPPERS = new HashMap<Class<?>, Class<?>>( 13 );
+    private static final Map<Class<?>, Class<?>> WRAPPERS = new HashMap<>( 13 );
 
     static {
         WRAPPERS.put( boolean.class, Boolean.class );
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Columns.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Columns.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -58,7 +58,6 @@
 import java.text.BreakIterator;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Locale;
 
 import static java.text.BreakIterator.*;
 
@@ -82,7 +81,7 @@
         List<String> options = piecesOf( row.option, optionWidth );
         List<String> descriptions = piecesOf( row.description, descriptionWidth );
 
-        List<Row> rows = new ArrayList<Row>();
+        List<Row> rows = new ArrayList<>();
         for ( int i = 0; i < Math.max( options.size(), descriptions.size() ); ++i )
             rows.add( new Row( itemOrEmpty( options, i ), itemOrEmpty( descriptions, i ) ) );
 
@@ -94,7 +93,7 @@
     }
 
     private List<String> piecesOf( String raw, int width ) {
-        List<String> pieces = new ArrayList<String>();
+        List<String> pieces = new ArrayList<>();
 
         for ( String each : raw.trim().split( LINE_SEPARATOR ) )
             pieces.addAll( piecesOfEmbeddedLine( each, width ) );
@@ -103,9 +102,9 @@
     }
 
     private List<String> piecesOfEmbeddedLine( String line, int width ) {
-        List<String> pieces = new ArrayList<String>();
+        List<String> pieces = new ArrayList<>();
 
-        BreakIterator words = BreakIterator.getLineInstance( Locale.US );
+        BreakIterator words = BreakIterator.getLineInstance();
         words.setText( line );
 
         StringBuilder nextPiece = new StringBuilder();
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ConstructorInvokingValueConverter.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ConstructorInvokingValueConverter.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Messages.java	Wed Jun 06 15:36:29 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * The MIT License
+ *
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package jdk.internal.joptsimple.internal;
+
+import java.text.MessageFormat;
+import java.util.Locale;
+import java.util.ResourceBundle;
+
+/**
+ * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
+ */
+public class Messages {
+    private Messages() {
+        throw new UnsupportedOperationException();
+    }
+
+    public static String message( Locale locale, String bundleName, Class<?> type, String key, Object... args ) {
+        ResourceBundle bundle = ResourceBundle.getBundle( bundleName, locale );
+        String template = bundle.getString( type.getName() + '.' + key );
+        MessageFormat format = new MessageFormat( template );
+        format.setLocale( locale );
+        return format.format( args );
+    }
+}
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/MethodInvokingValueConverter.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/MethodInvokingValueConverter.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Objects.java	Wed Jun 06 13:06:21 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,76 +0,0 @@
-/*
- * Copyright (c) 2015, 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.
- */
-
-/*
- * This file is available under and governed by the GNU General Public
- * License version 2 only, as published by the Free Software Foundation.
- * However, the following notice accompanied the original version of this
- * file:
- *
- * The MIT License
- *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
-
-package jdk.internal.joptsimple.internal;
-
-/**
- * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
- */
-public final class Objects {
-    private Objects() {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * Rejects {@code null} references.
-     *
-     * @param target reference to check
-     * @throws NullPointerException if {@code target} is {@code null}
-     */
-    public static void ensureNotNull( Object target ) {
-        if ( target == null )
-            throw new NullPointerException();
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/OptionNameMap.java	Wed Jun 06 15:36:29 2018 +0200
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * The MIT License
+ *
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package jdk.internal.joptsimple.internal;
+
+import java.util.Map;
+
+/**
+ * Map-like interface for storing String-value pairs.
+ *
+ * @param <V> type of values stored in the map
+ */
+public interface OptionNameMap<V> {
+    boolean contains( String key );
+
+    V get( String key );
+
+    void put( String key, V newValue );
+
+    void putAll( Iterable<String> keys, V newValue );
+
+    void remove( String key );
+
+    Map<String, V> toJavaUtilMap();
+}
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Reflection.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Reflection.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -98,22 +98,20 @@
 
     private static <V> ValueConverter<V> valueOfConverter( Class<V> clazz ) {
         try {
-            Method valueOf = clazz.getDeclaredMethod( "valueOf", String.class );
+            Method valueOf = clazz.getMethod( "valueOf", String.class );
             if ( meetsConverterRequirements( valueOf, clazz ) )
-                return new MethodInvokingValueConverter<V>( valueOf, clazz );
+                return new MethodInvokingValueConverter<>( valueOf, clazz );
 
             return null;
-        }
-        catch ( NoSuchMethodException ignored ) {
+        } catch ( NoSuchMethodException ignored ) {
             return null;
         }
     }
 
     private static <V> ValueConverter<V> constructorConverter( Class<V> clazz ) {
         try {
-            return new ConstructorInvokingValueConverter<V>( clazz.getConstructor( String.class ) );
-        }
-        catch ( NoSuchMethodException ignored ) {
+            return new ConstructorInvokingValueConverter<>( clazz.getConstructor( String.class ) );
+        } catch ( NoSuchMethodException ignored ) {
             return null;
         }
     }
@@ -130,8 +128,7 @@
     public static <T> T instantiate( Constructor<T> constructor, Object... args ) {
         try {
             return constructor.newInstance( args );
-        }
-        catch ( Exception ex ) {
+        } catch ( Exception ex ) {
             throw reflectionException( ex );
         }
     }
@@ -147,8 +144,7 @@
     public static Object invoke( Method method, Object... args ) {
         try {
             return method.invoke( null, args );
-        }
-        catch ( Exception ex ) {
+        } catch ( Exception ex ) {
             throw reflectionException( ex );
         }
     }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ReflectionException.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/ReflectionException.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Row.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Row.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Rows.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Rows.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,8 +55,8 @@
 
 package jdk.internal.joptsimple.internal;
 
-import java.util.LinkedHashSet;
-import java.util.Set;
+import java.util.ArrayList;
+import java.util.List;
 
 import static java.lang.Math.*;
 
@@ -68,7 +68,8 @@
 public class Rows {
     private final int overallWidth;
     private final int columnSeparatorWidth;
-    private final Set<Row> rows = new LinkedHashSet<Row>();
+    private final List<Row> rows = new ArrayList<>();
+
     private int widthOfWidestOption;
     private int widthOfWidestDescription;
 
@@ -87,7 +88,7 @@
         widthOfWidestDescription = max( widthOfWidestDescription, row.description.length() );
     }
 
-    private void reset() {
+    public void reset() {
         rows.clear();
         widthOfWidestOption = 0;
         widthOfWidestDescription = 0;
@@ -96,7 +97,7 @@
     public void fitToWidth() {
         Columns columns = new Columns( optionWidth(), descriptionWidth() );
 
-        Set<Row> fitted = new LinkedHashSet<Row>();
+        List<Row> fitted = new ArrayList<>();
         for ( Row each : rows )
             fitted.addAll( columns.fit( each ) );
 
@@ -122,7 +123,7 @@
     }
 
     private int descriptionWidth() {
-        return min( ( overallWidth - columnSeparatorWidth ) / 2, widthOfWidestDescription );
+        return min( overallWidth - optionWidth() - columnSeparatorWidth, widthOfWidestDescription );
     }
 
     private StringBuilder pad( StringBuilder buffer, String s, int length ) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/SimpleOptionNameMap.java	Wed Jun 06 15:36:29 2018 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * The MIT License
+ *
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package jdk.internal.joptsimple.internal;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * <p>An {@code OptionNameMap} which wraps and behaves like {@code HashMap}.</p>
+ */
+public class SimpleOptionNameMap<V> implements OptionNameMap<V> {
+    private final Map<String, V> map = new HashMap<>();
+
+    @Override
+    public boolean contains( String key ) {
+        return map.containsKey( key );
+    }
+
+    @Override
+    public V get( String key ) {
+        return map.get( key );
+    }
+
+    @Override
+    public void put( String key, V newValue ) {
+        map.put( key, newValue );
+    }
+
+    @Override
+    public void putAll( Iterable<String> keys, V newValue ) {
+        for ( String each : keys )
+            map.put( each, newValue );
+    }
+
+    @Override
+    public void remove( String key ) {
+        map.remove( key );
+    }
+
+    @Override
+    public Map<String, V> toJavaUtilMap() {
+        return new HashMap<>( map );
+    }
+}
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Strings.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/internal/Strings.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -56,7 +56,6 @@
 package jdk.internal.joptsimple.internal;
 
 import java.util.Iterator;
-import java.util.List;
 
 import static java.lang.System.*;
 import static java.util.Arrays.*;
@@ -66,7 +65,6 @@
  */
 public final class Strings {
     public static final String EMPTY = "";
-    public static final String SINGLE_QUOTE = "'";
     public static final String LINE_SEPARATOR = getProperty( "line.separator" );
 
     private Strings() {
@@ -96,7 +94,7 @@
      * @return {@code true} if the target string is null or empty
      */
     public static boolean isNullOrEmpty( String target ) {
-        return target == null || EMPTY.equals( target );
+        return target == null || target.isEmpty();
     }
 
 
@@ -132,7 +130,7 @@
      * @param separator the separator
      * @return the joined string
      */
-    public static String join( List<String> pieces, String separator ) {
+    public static String join( Iterable<String> pieces, String separator ) {
         StringBuilder buffer = new StringBuilder();
 
         for ( Iterator<String> iter = pieces.iterator(); iter.hasNext(); ) {
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/DateConverter.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/DateConverter.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -59,9 +59,11 @@
 import java.text.ParsePosition;
 import java.text.SimpleDateFormat;
 import java.util.Date;
+import java.util.Locale;
 
 import jdk.internal.joptsimple.ValueConversionException;
 import jdk.internal.joptsimple.ValueConverter;
+import jdk.internal.joptsimple.internal.Messages;
 
 /**
  * Converts values to {@link Date}s using a {@link DateFormat} object.
@@ -121,10 +123,22 @@
     }
 
     private String message( String value ) {
-        String message = "Value [" + value + "] does not match date/time pattern";
-        if ( formatter instanceof SimpleDateFormat )
-            message += " [" + ( (SimpleDateFormat) formatter ).toPattern() + ']';
+        String key;
+        Object[] arguments;
 
-        return message;
+        if ( formatter instanceof SimpleDateFormat ) {
+            key = "with.pattern.message";
+            arguments = new Object[] { value, ( (SimpleDateFormat) formatter ).toPattern() };
+        } else {
+            key = "without.pattern.message";
+            arguments = new Object[] { value };
+        }
+
+        return Messages.message(
+            Locale.getDefault(),
+            "jdk.internal.joptsimple.ExceptionMessages",
+            DateConverter.class,
+            key,
+            arguments );
     }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/EnumConverter.java	Wed Jun 06 15:36:29 2018 +0200
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+/*
+ * This file is available under and governed by the GNU General Public
+ * License version 2 only, as published by the Free Software Foundation.
+ * However, the following notice accompanied the original version of this
+ * file:
+ *
+ * The MIT License
+ *
+ * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+package jdk.internal.joptsimple.util;
+
+import java.text.MessageFormat;
+import java.util.EnumSet;
+import java.util.Iterator;
+import java.util.ResourceBundle;
+
+import jdk.internal.joptsimple.ValueConversionException;
+import jdk.internal.joptsimple.ValueConverter;
+
+/**
+ * Converts values to {@link java.lang.Enum}s.
+ *
+ * @author <a href="mailto:christian.ohr@gmail.com">Christian Ohr</a>
+ */
+public abstract class EnumConverter<E extends Enum<E>> implements ValueConverter<E> {
+    private final Class<E> clazz;
+
+    private String delimiters = "[,]";
+
+    /**
+     * This constructor must be called by subclasses, providing the enum class as the parameter.
+     *
+     * @param clazz enum class
+     */
+    protected EnumConverter( Class<E> clazz ) {
+        this.clazz = clazz;
+    }
+
+    @Override
+    public E convert( String value ) {
+        for ( E each : valueType().getEnumConstants() ) {
+            if ( each.name().equalsIgnoreCase( value ) ) {
+                return each;
+            }
+        }
+
+        throw new ValueConversionException( message( value ) );
+    }
+
+    @Override
+    public Class<E> valueType() {
+        return clazz;
+    }
+
+    /**
+     * Sets the delimiters for the message string. Must be a 3-letter string,
+     * where the first character is the prefix, the second character is the
+     * delimiter between the values, and the 3rd character is the suffix.
+     *
+     * @param delimiters delimiters for message string. Default is [,]
+     */
+    public void setDelimiters( String delimiters ) {
+        this.delimiters = delimiters;
+    }
+
+    @Override
+    public String valuePattern() {
+        EnumSet<E> values = EnumSet.allOf( valueType() );
+
+        StringBuilder builder = new StringBuilder();
+        builder.append( delimiters.charAt(0) );
+        for ( Iterator<E> i = values.iterator(); i.hasNext(); ) {
+            builder.append( i.next().toString() );
+            if ( i.hasNext() )
+                builder.append( delimiters.charAt( 1 ) );
+        }
+        builder.append( delimiters.charAt( 2 ) );
+
+        return builder.toString();
+    }
+
+    private String message( String value ) {
+        ResourceBundle bundle = ResourceBundle.getBundle( "jdk.internal.joptsimple.ExceptionMessages" );
+        Object[] arguments = new Object[] { value, valuePattern() };
+        String template = bundle.getString( EnumConverter.class.getName() + ".message" );
+        return new MessageFormat( template ).format( arguments );
+    }
+}
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/InetAddressConverter.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/InetAddressConverter.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -57,9 +57,11 @@
 
 import java.net.InetAddress;
 import java.net.UnknownHostException;
+import java.util.Locale;
 
 import jdk.internal.joptsimple.ValueConversionException;
 import jdk.internal.joptsimple.ValueConverter;
+import jdk.internal.joptsimple.internal.Messages;
 
 /**
  * Converts values to {@link java.net.InetAddress} using {@link InetAddress#getByName(String) getByName}.
@@ -70,8 +72,9 @@
     public InetAddress convert( String value ) {
         try {
             return InetAddress.getByName( value );
-        } catch ( UnknownHostException e ) {
-            throw new ValueConversionException( "Cannot convert value [" + value + " into an InetAddress", e );
+        }
+        catch ( UnknownHostException e ) {
+            throw new ValueConversionException( message( value ) );
         }
     }
 
@@ -82,4 +85,13 @@
     public String valuePattern() {
         return null;
     }
+
+    private String message( String value ) {
+        return Messages.message(
+            Locale.getDefault(),
+            "jdk.internal.joptsimple.ExceptionMessages",
+            InetAddressConverter.class,
+            "message",
+            value );
+    }
 }
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/KeyValuePair.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/KeyValuePair.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -60,7 +60,7 @@
 /**
  * <p>A simple string key/string value pair.</p>
  *
- * <p>This is useful as an argument type for options whose values take on the form <kbd>key=value</kbd>, such as JVM
+ * <p>This is useful as an argument type for options whose values take on the form {@code key=value}, such as JVM
  * command line system properties.</p>
  *
  * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
@@ -75,7 +75,7 @@
     }
 
     /**
-     * Parses a string assumed to be of the form <kbd>key=value</kbd> into its parts.
+     * Parses a string assumed to be of the form {@code key=value} into its parts.
      *
      * @param asString key-value string
      * @return a key-value pair
@@ -84,7 +84,7 @@
     public static KeyValuePair valueOf( String asString ) {
         int equalsIndex = asString.indexOf( '=' );
         if ( equalsIndex == -1 )
-            return new KeyValuePair( asString, EMPTY );
+            return new KeyValuePair( asString, null );
 
         String aKey = asString.substring( 0, equalsIndex );
         String aValue = equalsIndex == asString.length() - 1 ? EMPTY : asString.substring( equalsIndex + 1 );
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/PathConverter.java	Wed Jun 06 15:36:29 2018 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018, 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 jdk.internal.joptsimple.util;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.MessageFormat;
+import java.util.ResourceBundle;
+
+import jdk.internal.joptsimple.ValueConversionException;
+import jdk.internal.joptsimple.ValueConverter;
+
+/**
+ * Converts command line options to {@link Path} objects and checks the status of the underlying file.
+ */
+public class PathConverter implements ValueConverter<Path> {
+    private final PathProperties[] pathProperties;
+
+    public PathConverter( PathProperties... pathProperties ) {
+        this.pathProperties = pathProperties;
+    }
+
+    @Override
+    public Path convert( String value ) {
+        Path path = Paths.get(value);
+
+        if ( pathProperties != null ) {
+            for ( PathProperties each : pathProperties ) {
+                if ( !each.accept( path ) )
+                    throw new ValueConversionException( message( each.getMessageKey(), path.toString() ) );
+            }
+        }
+
+        return path;
+    }
+
+    @Override
+    public Class<Path> valueType() {
+        return Path.class;
+    }
+
+    @Override
+    public String valuePattern() {
+        return null;
+    }
+
+    private String message( String errorKey, String value ) {
+        ResourceBundle bundle = ResourceBundle.getBundle( "jdk.internal.joptsimple.ExceptionMessages" );
+        Object[] arguments = new Object[] { value, valuePattern() };
+        String template = bundle.getString( PathConverter.class.getName() + "." + errorKey + ".message" );
+        return new MessageFormat( template ).format( arguments );
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/PathProperties.java	Wed Jun 06 15:36:29 2018 +0200
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018, 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 jdk.internal.joptsimple.util;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+/**
+ * Enum for checking common conditions of files and directories.
+ *
+ * @see jdk.internal.joptsimple.util.PathConverter
+ */
+public enum PathProperties {
+    FILE_EXISTING( "file.existing" ) {
+        @Override
+        boolean accept( Path path ) {
+            return Files.isRegularFile( path );
+        }
+    },
+    DIRECTORY_EXISTING( "directory.existing" ) {
+        @Override
+        boolean accept( Path path ) {
+            return Files.isDirectory( path );
+        }
+    },
+    NOT_EXISTING( "file.not.existing" ) {
+        @Override
+        boolean accept( Path path ) {
+            return Files.notExists( path );
+        }
+    },
+    FILE_OVERWRITABLE( "file.overwritable" ) {
+        @Override
+        boolean accept( Path path ) {
+            return FILE_EXISTING.accept( path ) && WRITABLE.accept( path );
+        }
+    },
+    READABLE( "file.readable" ) {
+        @Override
+        boolean accept( Path path ) {
+            return Files.isReadable( path );
+        }
+    },
+    WRITABLE( "file.writable" ) {
+        @Override
+        boolean accept( Path path ) {
+            return Files.isWritable( path );
+        }
+    };
+
+    private final String messageKey;
+
+    private PathProperties( String messageKey ) {
+        this.messageKey = messageKey;
+    }
+
+    abstract boolean accept( Path path );
+
+    String getMessageKey() {
+        return messageKey;
+    }
+}
--- a/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/RegexMatcher.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/classes/jdk/internal/joptsimple/util/RegexMatcher.java	Wed Jun 06 15:36:29 2018 +0200
@@ -31,7 +31,7 @@
  *
  * The MIT License
  *
- * Copyright (c) 2004-2014 Paul R. Holser, Jr.
+ * Copyright (c) 2004-2015 Paul R. Holser, Jr.
  *
  * Permission is hereby granted, free of charge, to any person obtaining
  * a copy of this software and associated documentation files (the
@@ -55,9 +55,11 @@
 
 package jdk.internal.joptsimple.util;
 
+import java.util.Locale;
 import java.util.regex.Pattern;
 
 import static java.util.regex.Pattern.*;
+import static jdk.internal.joptsimple.internal.Messages.message;
 
 import jdk.internal.joptsimple.ValueConversionException;
 import jdk.internal.joptsimple.ValueConverter;
@@ -96,8 +98,7 @@
 
     public String convert( String value ) {
         if ( !pattern.matcher( value ).matches() ) {
-            throw new ValueConversionException(
-                "Value [" + value + "] did not match regex [" + pattern.pattern() + ']' );
+            raiseValueConversionFailure( value );
         }
 
         return value;
@@ -110,4 +111,15 @@
     public String valuePattern() {
         return pattern.pattern();
     }
+
+    private void raiseValueConversionFailure( String value ) {
+        String message = message(
+            Locale.getDefault(),
+            "jdk.internal.joptsimple.ExceptionMessages",
+            RegexMatcher.class,
+            "message",
+            value,
+            pattern.pattern() );
+        throw new ValueConversionException( message );
+    }
 }
--- a/src/jdk.internal.opt/share/legal/jopt-simple.md	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.internal.opt/share/legal/jopt-simple.md	Wed Jun 06 15:36:29 2018 +0200
@@ -1,4 +1,4 @@
-## jopt-simple v4.6
+## jopt-simple v5.0.4
 
 ### MIT License
 <pre>
--- a/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/src/jdk.jlink/share/classes/jdk/tools/jmod/JmodTask.java	Wed Jun 06 15:36:29 2018 +0200
@@ -1224,7 +1224,7 @@
 
             all.put(CMD_FILENAME, new OptionDescriptor() {
                 @Override
-                public Collection<String> options() {
+                public List<String> options() {
                     List<String> ret = new ArrayList<>();
                     ret.add(CMD_FILENAME);
                     return ret;
@@ -1314,7 +1314,7 @@
                         .withValuesConvertedBy(new PatternConverter());
 
         OptionSpec<Void> help
-                = parser.acceptsAll(Set.of("h", "help", "?"), getMessage("main.opt.help"))
+                = parser.acceptsAll(List.of("h", "help", "?"), getMessage("main.opt.help"))
                         .forHelp();
 
         OptionSpec<Void> helpExtra
@@ -1347,7 +1347,7 @@
                         .withValuesConvertedBy(DirPathConverter.INSTANCE);
 
         OptionSpec<List<Path>> modulePath
-                = parser.acceptsAll(Set.of("p", "module-path"),
+                = parser.acceptsAll(List.of("p", "module-path"),
                                     getMessage("main.opt.module-path"))
                         .withRequiredArg()
                         .withValuesConvertedBy(DirPathConverter.INSTANCE);
--- a/test/jdk/tools/jmod/JmodNegativeTest.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/test/jdk/tools/jmod/JmodNegativeTest.java	Wed Jun 06 15:36:29 2018 +0200
@@ -100,7 +100,7 @@
         jmod("--badOption")
             .assertFailure()
             .resultChecker(r ->
-                assertContains(r.output, "Error: 'badOption' is not a recognized option")
+                assertContains(r.output, "Error: badOption is not a recognized option")
             );
     }
 
--- a/test/jdk/tools/jmod/JmodTest.java	Wed Jun 06 13:06:21 2018 +0100
+++ b/test/jdk/tools/jmod/JmodTest.java	Wed Jun 06 15:36:29 2018 +0200
@@ -111,7 +111,7 @@
 
         Path jmod = MODS_DIR.resolve("apa.jmod");
         jmod("create",
-             "--libs=", libDir.toString(),
+             "--libs=" + libDir.toString(),
              "--class-path", classesDir.toString(),
              jmod.toString())
             .assertSuccess();
@@ -310,7 +310,7 @@
         Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
 
         jmod("create",
-             "--libs=", lp.toString(),
+             "--libs=" + lp.toString(),
              "--class-path", cp.toString(),
              jmod.toString())
             .assertSuccess()
@@ -335,8 +335,8 @@
 
         jmod("create",
              "--conf", cf.toString(),
-             "--cmds=", bp.toString(),
-             "--libs=", lp.toString(),
+             "--cmds=" + bp.toString(),
+             "--libs=" + lp.toString(),
              "--class-path", cp.toString(),
              jmod.toString())
             .assertSuccess()
@@ -361,7 +361,7 @@
         Path lp = EXPLODED_DIR.resolve("foo").resolve("lib");
 
         jmod("create",
-             "--libs=", lp.toString(),
+             "--libs=" + lp.toString(),
              "--class-path", cp.toString(),
              "--exclude", "**internal**",
              "--exclude", "first.so",