    001/*
    002  Licensed to the Apache Software Foundation (ASF) under one or more
    003  contributor license agreements.  See the NOTICE file distributed with
    004  this work for additional information regarding copyright ownership.
    005  The ASF licenses this file to You under the Apache License, Version 2.0
    006  (the "License"); you may not use this file except in compliance with
    007  the License.  You may obtain a copy of the License at
    008
    009      https://www.apache.org/licenses/LICENSE-2.0
    010
    011  Unless required by applicable law or agreed to in writing, software
    012  distributed under the License is distributed on an "AS IS" BASIS,
    013  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    014  See the License for the specific language governing permissions and
    015  limitations under the License.
    016 */
    017
    018package org.apache.commons.cli;
    019
    020import java.io.Serializable;
    021import java.lang.reflect.Array;
    022import java.util.ArrayList;
    023import java.util.Iterator;
    024import java.util.LinkedList;
    025import java.util.List;
    026import java.util.Objects;
    027import java.util.Properties;
    028import java.util.function.Consumer;
    029import java.util.function.Supplier;
    030
    031/**
    032 * Represents list of arguments parsed against a {@link Options} descriptor.
    033 * <p>
    034 * It allows querying of a boolean {@link #hasOption(String optionName)}, in addition to retrieving the
    035 * {@link #getOptionValue(String optionName)} for options requiring arguments.
    036 * </p>
    037 * <p>
    038 * Additionally, any left-over or unrecognized arguments, are available for further processing.
    039 * </p>
    040 */
    041public class CommandLine implements Serializable {
    042
    043    /**
    044     * A nested builder class to create {@code CommandLine} instance using descriptive methods.
    045     *
    046     * @since 1.4
    047     */
    048    public static final class Builder implements Supplier<CommandLine> {
    049
    050        /**
    051         * Prints an Option to {@link System#out}.
    052         */
    053        static final Consumer<Option> DEPRECATED_HANDLER = o -> System.out.println(o.toDeprecatedString());
    054
    055        /** The unrecognized options/arguments */
    056        private final List<String> args = new LinkedList<>();
    057
    058        /** The processed options */
    059        private final List<Option> options = new ArrayList<>();
    060
    061        /**
    062         * Deprecated Option handler.
    063         */
    064        private Consumer<Option> deprecatedHandler = DEPRECATED_HANDLER;
    065
    066        /**
    067         * Constructs a new instance.
    068         *
    069         * @deprecated Use {@link #builder()}.
    070         */
    071        @Deprecated
    072        public Builder() {
    073            // empty
    074        }
    075
    076        /**
    077         * Adds left-over unrecognized option/argument.
    078         *
    079         * @param arg the unrecognized option/argument.
    080         * @return this Builder instance for method chaining.
    081         */
    082        public Builder addArg(final String arg) {
    083            if (arg != null) {
    084                args.add(arg);
    085            }
    086            return this;
    087        }
    088
    089        /**
    090         * Adds an option to the command line. The values of the option are stored.
    091         *
    092         * @param option the processed option.
    093         * @return this Builder instance for method chaining.
    094         */
    095        public Builder addOption(final Option option) {
    096            if (option != null) {
    097                options.add(option);
    098            }
    099            return this;
    100        }
    101
    102        /**
    103         * Creates a new instance.
    104         *
    105         * @return a new instance.
    106         * @deprecated Use {@link #get()}.
    107         */
    108        @Deprecated
    109        public CommandLine build() {
    110            return get();
    111        }
    112
    113        /**
    114         * Creates a new instance.
    115         *
    116         * @return a new instance.
    117         * @since 1.10.0
    118         */
    119        @Override
    120        public CommandLine get() {
    121            return new CommandLine(args, options, deprecatedHandler);
    122        }
    123
    124        /**
    125         * Sets the deprecated option handler.
    126         *
    127         * @param deprecatedHandler the deprecated option handler.
    128         * @return {@code this} instance.
    129         * @since 1.7.0
    130         */
    131        public Builder setDeprecatedHandler(final Consumer<Option> deprecatedHandler) {
    132            this.deprecatedHandler = deprecatedHandler;
    133            return this;
    134        }
    135    }
    136
    137    /** The serial version UID. */
    138    private static final long serialVersionUID = 1L;
    139
    140    /**
    141     * Creates a new builder.
    142     *
    143     * @return a new builder.
    144     * @since 1.7.0
    145     */
    146    public static Builder builder() {
    147        return new Builder();
    148    }
    149
    150    /** The unrecognized options/arguments */
    151    private final List<String> args;
    152
    153    /** The processed options */
    154    private final List<Option> options;
    155
    156    /**
    157     * The deprecated option handler.
    158     * <p>
    159     * If you want to serialize this field, use a serialization proxy.
    160     * </p>
    161     */
    162    private final transient Consumer<Option> deprecatedHandler;
    163
    164    /**
    165     * Creates a command line.
    166     */
    167    protected CommandLine() {
    168        this(new LinkedList<>(), new ArrayList<>(), Builder.DEPRECATED_HANDLER);
    169    }
    170
    171    /**
    172     * Creates a command line.
    173     */
    174    private CommandLine(final List<String> args, final List<Option> options, final Consumer<Option> deprecatedHandler) {
    175        this.args = Objects.requireNonNull(args, "args");
    176        this.options = Objects.requireNonNull(options, "options");
    177        this.deprecatedHandler = deprecatedHandler;
    178    }
    179
    180    /**
    181     * Adds left-over unrecognized option/argument.
    182     *
    183     * @param arg the unrecognized option/argument.
    184     */
    185    protected void addArg(final String arg) {
    186        if (arg != null) {
    187            args.add(arg);
    188        }
    189    }
    190
    191    /**
    192     * Adds an option to the command line. The values of the option are stored.
    193     *
    194     * @param option the processed option.
    195     */
    196    protected void addOption(final Option option) {
    197        if (option != null) {
    198            options.add(option);
    199        }
    200    }
    201
    202    /**
    203     * Gets the first element or null if values is null.
    204     *
    205     * @param values the array to query.
    206     * @return the first element or null if values is null.
    207     */
    208    private String first(final String[] values) {
    209        return values == null ? null : values[0];
    210    }
    211
    212    private <T> T get(final Supplier<T> supplier) {
    213        return supplier == null ? null : supplier.get();
    214    }
    215
    216    /**
    217     * Gets any left-over non-recognized options and arguments.
    218     *
    219     * @return remaining items passed in but not parsed as a {@code List}.
    220     */
    221    public List<String> getArgList() {
    222        return args;
    223    }
    224
    225    /**
    226     * Gets any left-over non-recognized options and arguments.
    227     *
    228     * @return remaining items passed in but not parsed as an array.
    229     */
    230    public String[] getArgs() {
    231        return args.toArray(Util.EMPTY_STRING_ARRAY);
    232    }
    233
    234    /**
    235     * Gets the number of times this option appears in the command line
    236     *
    237     * @param optionChar the character name of the option.
    238     * @return Number of times the option is present.
    239     * @since 1.11.0
    240     */
    241    public int getOptionCount(final char optionChar) {
    242        return getOptionCount(String.valueOf(optionChar));
    243    }
    244
    245    /**
    246     * Gets the number of times this option appears in the command line.
    247     *
    248     * @param option the option.
    249     * @return Number of times the option is present.
    250     * @since 1.11.0
    251     */
    252    public int getOptionCount(final Option option) {
    253        return (int) options.stream().filter(opt -> Objects.equals(opt, option)).count();
    254    }
    255
    256    /**
    257     * Gets the number of times this option appears in the command line
    258     *
    259     * @param optionName the name of the option.
    260     * @return Number of times the option is present.
    261     * @since 1.11.0
    262     */
    263    public int getOptionCount(final String optionName) {
    264        return getOptionCount(resolveOption(optionName));
    265    }
    266
    267    /**
    268     * Gets the {@code Object} type of this {@code Option}.
    269     *
    270     * @deprecated due to System.err message; use {@link #getParsedOptionValue(char)} instead.
    271     * @param optionChar the name of the option.
    272     * @return the type of opt.
    273     */
    274    @Deprecated
    275    public Object getOptionObject(final char optionChar) {
    276        return getOptionObject(String.valueOf(optionChar));
    277    }
    278
    279    /**
    280     * Gets the {@code Object} type of this {@code Option}.
    281     *
    282     * @param optionName the name of the option.
    283     * @return the type of this {@code Option}.
    284     * @deprecated due to System.err message; use {@link #getParsedOptionValue(String)} instead.
    285     */
    286    @Deprecated
    287    public Object getOptionObject(final String optionName) {
    288        try {
    289            return getParsedOptionValue(optionName);
    290        } catch (final ParseException pe) {
    291            System.err.println("Exception found converting " + optionName + " to desired type: " + pe.getMessage());
    292            return null;
    293        }
    294    }
    295
    296    /**
    297     * Gets the map of values associated to the option. This is convenient for options specifying Java properties like
    298     * <code>-Dparam1=value1
    299     * -Dparam2=value2</code>. All odd numbered values are property keys
    300     * and even numbered values are property values.  If there are an odd number of values
    301     * the last value is assumed to be a boolean flag and the value is "true".
    302     *
    303     * @param option name of the option.
    304     * @return The Properties mapped by the option, never {@code null} even if the option doesn't exists.
    305     * @since 1.5.0
    306     */
    307    public Properties getOptionProperties(final Option option) {
    308        final Properties props = new Properties();
    309        options.forEach(processedOption -> {
    310            if (processedOption.equals(option)) {
    311                processPropertiesFromValues(props, processedOption.getValuesList());
    312            }
    313        });
    314        return props;
    315    }
    316
    317    /**
    318     * Gets the map of values associated to the option. This is convenient for options specifying Java properties like
    319     * <code>-Dparam1=value1
    320     * -Dparam2=value2</code>. The first argument of the option is the key, and the 2nd argument is the value. If the option
    321     * has only one argument ({@code -Dfoo}) it is considered as a boolean flag and the value is {@code "true"}.
    322     *
    323     * @param optionName name of the option.
    324     * @return The Properties mapped by the option, never {@code null} even if the option doesn't exists.
    325     * @since 1.2
    326     */
    327    public Properties getOptionProperties(final String optionName) {
    328        final Properties props = new Properties();
    329        options.forEach(option -> {
    330            if (optionName.equals(option.getOpt()) || optionName.equals(option.getLongOpt())) {
    331                processPropertiesFromValues(props, option.getValuesList());
    332            }
    333        });
    334        return props;
    335    }
    336
    337    /**
    338     * Gets an array of the processed {@link Option}s.
    339     *
    340     * @return an array of the processed {@link Option}s.
    341     */
    342    public Option[] getOptions() {
    343        return options.toArray(Option.EMPTY_ARRAY);
    344    }
    345
    346    /**
    347     * Gets the first argument, if any, of this option.
    348     *
    349     * @param optionChar the character name of the option.
    350     * @return Value of the argument if option is set, and has an argument, otherwise null.
    351     */
    352    public String getOptionValue(final char optionChar) {
    353        return getOptionValue(String.valueOf(optionChar));
    354    }
    355
    356    /**
    357     * Gets the argument, if any, of an option.
    358     *
    359     * @param optionChar character name of the option
    360     * @param defaultValue is the default value to be returned if the option is not specified.
    361     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    362     */
    363    public String getOptionValue(final char optionChar, final String defaultValue) {
    364        return getOptionValue(String.valueOf(optionChar), () -> defaultValue);
    365    }
    366
    367    /**
    368     * Gets the argument, if any, of an option.
    369     *
    370     * @param optionChar character name of the option.
    371     * @param defaultValue is a supplier for the default value to be returned if the option is not specified.
    372     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    373     * @since 1.7.0
    374     */
    375    public String getOptionValue(final char optionChar, final Supplier<String> defaultValue) {
    376        return getOptionValue(String.valueOf(optionChar), defaultValue);
    377    }
    378
    379    /**
    380     * Gets the first argument, if any, of this option.
    381     *
    382     * @param option the option.
    383     * @return Value of the argument if option is set, and has an argument, otherwise null.
    384     * @since 1.5.0
    385     */
    386    public String getOptionValue(final Option option) {
    387        return first(getOptionValues(option));
    388    }
    389
    390    /**
    391     * Gets the first argument, if any, of an option.
    392     *
    393     * @param option the option.
    394     * @param defaultValue is the default value to be returned if the option is not specified.
    395     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    396     * @since 1.5.0
    397     */
    398    public String getOptionValue(final Option option, final String defaultValue) {
    399        return getOptionValue(option, () -> defaultValue);
    400    }
    401
    402    /**
    403     * Gets the first argument, if any, of an option.
    404     *
    405     * @param option the option.
    406     * @param defaultValue is a supplier for the default value to be returned if the option is not specified.
    407     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    408     * @since 1.7.0
    409     */
    410    public String getOptionValue(final Option option, final Supplier<String> defaultValue) {
    411        final String answer = getOptionValue(option);
    412        return answer != null ? answer : get(defaultValue);
    413    }
    414
    415    /**
    416     * Gets the first argument, if any, of this option group.
    417     *
    418     * @param optionGroup the option group.
    419     * @return Value of the argument if option group is selected, and has an argument, otherwise null.
    420     * @since 1.9.0
    421     */
    422    public String getOptionValue(final OptionGroup optionGroup) {
    423        return first(getOptionValues(optionGroup));
    424    }
    425
    426    /**
    427     * Gets the first argument, if any, of an option group.
    428     *
    429     * @param optionGroup the option group.
    430     * @param defaultValue is the default value to be returned if the option group is not selected.
    431     * @return Value of the argument if option group is selected, and has an argument, otherwise {@code defaultValue}.
    432     * @since 1.9.0
    433     */
    434    public String getOptionValue(final OptionGroup optionGroup, final String defaultValue) {
    435        return getOptionValue(optionGroup, () -> defaultValue);
    436    }
    437
    438    /**
    439     * Gets the first argument, if any, of an option group.
    440     *
    441     * @param optionGroup the option group.
    442     * @param defaultValue is a supplier for the default value to be returned if the option group is not selected.
    443     * @return Value of the argument if option group is selected, and has an argument, otherwise {@code defaultValue}.
    444     * @since 1.9.0
    445     */
    446    public String getOptionValue(final OptionGroup optionGroup, final Supplier<String> defaultValue) {
    447        final String answer = getOptionValue(optionGroup);
    448        return answer != null ? answer : get(defaultValue);
    449    }
    450
    451    /**
    452     * Gets the first argument, if any, of this option.
    453     *
    454     * @param optionName the name of the option.
    455     * @return Value of the argument if option is set, and has an argument, otherwise null.
    456     */
    457    public String getOptionValue(final String optionName) {
    458        return getOptionValue(resolveOption(optionName));
    459    }
    460
    461    /**
    462     * Gets the first argument, if any, of an option.
    463     *
    464     * @param optionName name of the option.
    465     * @param defaultValue is the default value to be returned if the option is not specified.
    466     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    467     */
    468    public String getOptionValue(final String optionName, final String defaultValue) {
    469        return getOptionValue(resolveOption(optionName), () -> defaultValue);
    470    }
    471
    472    /**
    473     * Gets the first argument, if any, of an option.
    474     *
    475     * @param optionName name of the option.
    476     * @param defaultValue is a supplier for the default value to be returned if the option is not specified.
    477     * @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
    478     * @since 1.7.0
    479     */
    480    public String getOptionValue(final String optionName, final Supplier<String> defaultValue) {
    481        return getOptionValue(resolveOption(optionName), defaultValue);
    482    }
    483
    484    /**
    485     * Gets the array of values, if any, of an option.
    486     *
    487     * @param optionChar character name of the option.
    488     * @return Values of the argument if option is set, and has an argument, otherwise null.
    489     */
    490    public String[] getOptionValues(final char optionChar) {
    491        return getOptionValues(String.valueOf(optionChar));
    492    }
    493
    494    /**
    495     * Gets the array of values, if any, of an option.
    496     *
    497     * @param option the option.
    498     * @return Values of the argument if option is set, and has an argument, otherwise null.
    499     * @since 1.5.0
    500     */
    501    public String[] getOptionValues(final Option option) {
    502        if (option == null) {
    503            return null;
    504        }
    505        final List<String> values = new ArrayList<>();
    506        options.forEach(processedOption -> {
    507            if (processedOption.equals(option)) {
    508                if (option.isDeprecated()) {
    509                    handleDeprecated(option);
    510                }
    511                values.addAll(processedOption.getValuesList());
    512            }
    513        });
    514        return values.isEmpty() ? null : values.toArray(Util.EMPTY_STRING_ARRAY);
    515    }
    516
    517    /**
    518     * Gets the array of values, if any, of an option group.
    519     *
    520     * @param optionGroup the option group.
    521     * @return Values of the argument if option group is selected, and has an argument, otherwise null.
    522     * @since 1.9.0
    523     */
    524    public String[] getOptionValues(final OptionGroup optionGroup) {
    525        if (optionGroup == null || !optionGroup.isSelected()) {
    526            return null;
    527        }
    528        return getOptionValues(optionGroup.getSelected());
    529    }
    530
    531    /**
    532     * Gets the array of values, if any, of an option.
    533     *
    534     * @param optionName string name of the option.
    535     * @return Values of the argument if option is set, and has an argument, otherwise null.
    536     */
    537    public String[] getOptionValues(final String optionName) {
    538        return getOptionValues(resolveOption(optionName));
    539    }
    540
    541    /**
    542     * Gets a version of this {@code Option} converted to a particular type.
    543     *
    544     * @param optionChar the name of the option.
    545     * @param <T> The return type for the method.
    546     * @return the value parsed into a particular object or null if the option is not set.
    547     * @throws ParseException if there are problems turning the option value into the desired type.
    548     * @see PatternOptionBuilder
    549     * @since 1.5.0
    550     */
    551    public <T> T getParsedOptionValue(final char optionChar) throws ParseException {
    552        return getParsedOptionValue(String.valueOf(optionChar));
    553    }
    554
    555    /**
    556     * Gets a version of this {@code Option} converted to a particular type.
    557     *
    558     * @param optionChar the name of the option.
    559     * @param defaultValue the default value to return if opt is not set.
    560     * @param <T> The return type for the method.
    561     * @return the value parsed into a particular object or the defaultValue if the option is not set.
    562     * @throws ParseException if there are problems turning the option value into the desired type.
    563     * @see PatternOptionBuilder
    564     * @since 1.7.0
    565     */
    566    public <T> T getParsedOptionValue(final char optionChar, final Supplier<T> defaultValue) throws ParseException {
    567        return getParsedOptionValue(String.valueOf(optionChar), defaultValue);
    568    }
    569
    570    /**
    571     * Gets a version of this {@code Option} converted to a particular type.
    572     *
    573     * @param optionChar the name of the option.
    574     * @param defaultValue the default value to return if opt is not set.
    575     * @param <T> The return type for the method.
    576     * @return the value parsed into a particular object or the defaultValue if the option is not set.
    577     * @throws ParseException if there are problems turning the option value into the desired type.
    578     * @see PatternOptionBuilder
    579     * @since 1.7.0
    580     */
    581    public <T> T getParsedOptionValue(final char optionChar, final T defaultValue) throws ParseException {
    582        return getParsedOptionValue(String.valueOf(optionChar), defaultValue);
    583    }
    584
    585    /**
    586     * Gets a version of this {@code Option} converted to a particular type.
    587     *
    588     * @param option the option.
    589     * @param <T> The return type for the method.
    590     * @return the value parsed into a particular object or null if the option is not set.
    591     * @throws ParseException if there are problems turning the option value into the desired type.
    592     * @see PatternOptionBuilder
    593     * @since 1.5.0
    594     */
    595    public <T> T getParsedOptionValue(final Option option) throws ParseException {
    596        return getParsedOptionValue(option, () -> null);
    597    }
    598
    599    /**
    600     * Gets a version of this {@code Option} converted to a particular type.
    601     *
    602     * @param option the option.
    603     * @param defaultValue the default value to return if opt is not set.
    604     * @param <T> The return type for the method.
    605     * @return the value parsed into a particular object or the defaultValue if the option is not set.
    606     * @throws ParseException if there are problems turning the option value into the desired type.
    607     * @see PatternOptionBuilder
    608     * @since 1.7.0
    609     */
    610    @SuppressWarnings("unchecked")
    611    public <T> T getParsedOptionValue(final Option option, final Supplier<T> defaultValue) throws ParseException {
    612        if (option == null) {
    613            return get(defaultValue);
    614        }
    615        final String res = getOptionValue(option);
    616        try {
    617            if (res == null) {
    618                return get(defaultValue);
    619            }
    620            return (T) option.getConverter().apply(res);
    621        } catch (final Exception e) {
    622            throw ParseException.wrap(e);
    623        }
    624    }
    625
    626    /**
    627     * Gets a version of this {@code Option} converted to a particular type.
    628     *
    629     * @param option the option.
    630     * @param defaultValue the default value to return if opt is not set.
    631     * @param <T> The return type for the method.
    632     * @return the value parsed into a particular object or the defaultValue if the option is not set.
    633     * @throws ParseException if there are problems turning the option value into the desired type.
    634     * @see PatternOptionBuilder
    635     * @since 1.7.0
    636     */
    637    public <T> T getParsedOptionValue(final Option option, final T defaultValue) throws ParseException {
    638        return getParsedOptionValue(option, () -> defaultValue);
    639    }
    640
    641    /**
    642     * Gets a version of this {@code OptionGroup} converted to a particular type.
    643     *
    644     * @param optionGroup the option group.
    645     * @param <T> The return type for the method.
    646     * @return the value parsed into a particular object or null if no option in the OptionGroup is set.
    647     * @throws ParseException if there are problems turning the selected option value into the desired type.
    648     * @see PatternOptionBuilder
    649     * @since 1.9.0
    650     */
    651    public <T> T getParsedOptionValue(final OptionGroup optionGroup) throws ParseException {
    652        return getParsedOptionValue(optionGroup, () -> null);
    653    }
    654
    655    /**
    656     * Gets a version of this {@code OptionGroup} converted to a particular type.
    657     *
    658     * @param optionGroup the option group.
    659     * @param defaultValue the default value to return if opt is not set.
    660     * @param <T> The return type for the method.
    661     * @return the value parsed into a particular object or the defaultValue if no option in the OptionGroup is set.
    662     * @throws ParseException if there are problems turning the selected option value into the desired type.
    663     * @see PatternOptionBuilder
    664     * @since 1.9.0
    665     */
    666    public <T> T getParsedOptionValue(final OptionGroup optionGroup, final Supplier<T> defaultValue) throws ParseException {
    667        if (optionGroup == null || !optionGroup.isSelected()) {
    668            return get(defaultValue);
    669        }
    670        return getParsedOptionValue(optionGroup.getSelected(), defaultValue);
    671    }
    672
    673    /**
    674     * Gets a version of this {@code OptionGroup} converted to a particular type.
    675     *
    676     * @param optionGroup the option group.
    677     * @param defaultValue the default value to return if an option is not selected.
    678     * @param <T> The return type for the method.
    679     * @return the value parsed into a particular object or the defaultValue if no option in the OptionGroup is set.
    680     * @throws ParseException if there are problems turning the option value into the desired type.
    681     * @see PatternOptionBuilder
    682     * @since 1.9.0
    683     */
    684    public <T> T getParsedOptionValue(final OptionGroup optionGroup, final T defaultValue) throws ParseException {
    685        return getParsedOptionValue(optionGroup, () -> defaultValue);
    686    }
    687
    688    /**
    689     * Gets a version of this {@code Option} converted to a particular type.
    690     *
    691     * @param optionName the name of the option.
    692     * @param <T> The return type for the method.
    693     * @return the value parsed into a particular object or null if the option is not set.
    694     * @throws ParseException if there are problems turning the option value into the desired type.
    695     * @see PatternOptionBuilder
    696     * @since 1.2
    697     */
    698    public <T> T getParsedOptionValue(final String optionName) throws ParseException {
    699        return getParsedOptionValue(resolveOption(optionName));
    700    }
    701
    702    /**
    703     * Gets a version of this {@code Option} converted to a particular type.
    704     *
    705     * @param optionName the name of the option.
    706     * @param defaultValue the default value to return if opt is not set.
    707     * @param <T> The return type for the method.
    708     * @return the value parsed into a particular object or the defaultValue if the option is not set.
    709     * @throws ParseException if there are problems turning the option value into the desired type.
    710     * @see PatternOptionBuilder
    711     * @since 1.7.0
    712     */
    713    public <T> T getParsedOptionValue(final String optionName, final Supplier<T> defaultValue) throws ParseException {
    714        return getParsedOptionValue(resolveOption(optionName), defaultValue);
    715    }
    716
    717    /**
    718     * Gets a version of this {@code Option} converted to a particular type.
    719     *
    720     * @param optionName the name of the option.
    721     * @param defaultValue the default value to return if opt is not set.
    722     * @param <T> The return type for the method.
    723     * @return the value parsed into a particular object or the defaultValue if the option is not set.
    724     * @throws ParseException if there are problems turning the option value into the desired type.
    725     * @see PatternOptionBuilder
    726     * @since 1.7.0
    727     */
    728    public <T> T getParsedOptionValue(final String optionName, final T defaultValue) throws ParseException {
    729        return getParsedOptionValue(resolveOption(optionName), defaultValue);
    730    }
    731
    732    /**
    733     * Gets a version of this {@code Option} converted to an array of a particular type.
    734     *
    735     * @param optionChar the name of the option.
    736     * @param <T> The array type for the return value.
    737     * @return the values parsed into an array of objects or null if the option is not set.
    738     * @throws ParseException if there are problems turning the option value into the desired type.
    739     * @see PatternOptionBuilder
    740     * @since 1.10.0
    741     */
    742    public <T> T[] getParsedOptionValues(final char optionChar) throws ParseException {
    743        return getParsedOptionValues(String.valueOf(optionChar));
    744    }
    745
    746    /**
    747     * Gets a version of this {@code Option} converted to an array of a particular type.
    748     *
    749     * @param optionChar the name of the option.
    750     * @param defaultValue the default value to return if opt is not set.
    751     * @param <T> The array type for the return value.
    752     * @return the values parsed into an array of objects or the defaultValue if the option is not set.
    753     * @throws ParseException if there are problems turning the option value into the desired type.
    754     * @see PatternOptionBuilder
    755     * @since 1.10.0
    756     */
    757    public <T> T[] getParsedOptionValues(final char optionChar, final Supplier<T[]> defaultValue) throws ParseException {
    758        return getParsedOptionValues(String.valueOf(optionChar), defaultValue);
    759    }
    760
    761    /**
    762     * Gets a version of this {@code Option} converted to an array of a particular type.
    763     *
    764     * @param optionChar the name of the option.
    765     * @param defaultValue the default value to return if opt is not set.
    766     * @param <T> The array type for the return value.
    767     * @return the values parsed into an array of objects or the defaultValue if the option is not set.
    768     * @throws ParseException if there are problems turning the option value into the desired type.
    769     * @see PatternOptionBuilder
    770     * @since 1.10.0
    771     */
    772    public <T> T[] getParsedOptionValues(final char optionChar, final T[] defaultValue) throws ParseException {
    773        return getParsedOptionValues(String.valueOf(optionChar), defaultValue);
    774    }
    775
    776    /**
    777     * Gets a version of this {@code Option} converted to an array of a particular type.
    778     *
    779     * @param option the option.
    780     * @param <T> The array type for the return value.
    781     * @return the values parsed into an array of objects or null if the option is not set.
    782     * @throws ParseException if there are problems turning the option value into the desired type.
    783     * @see PatternOptionBuilder
    784     * @since 1.10.0
    785     */
    786    public <T> T[] getParsedOptionValues(final Option option) throws ParseException {
    787        return getParsedOptionValues(option, () -> null);
    788    }
    789
    790    /**
    791     * Gets a version of this {@code Option} converted to an array of a particular type.
    792     *
    793     * @param option the option.
    794     * @param defaultValue the default value to return if opt is not set.
    795     * @param <T> The array type for the return value.
    796     * @return the values parsed into an array of objects or the defaultValue if the option is not set.
    797     * @throws ParseException if there are problems turning the option value into the desired type.
    798     * @see PatternOptionBuilder
    799     * @since 1.10.0
    800     */
    801    @SuppressWarnings("unchecked")
    802    public <T> T[] getParsedOptionValues(final Option option, final Supplier<T[]> defaultValue) throws ParseException {
    803        if (option == null) {
    804            return get(defaultValue);
    805        }
    806        final Class<? extends T> clazz = (Class<? extends T>) option.getType();
    807        final String[] values = getOptionValues(option);
    808        if (values == null) {
    809            return get(defaultValue);
    810        }
    811        final T[] result = (T[]) Array.newInstance(clazz, values.length);
    812        try {
    813            for (int i = 0; i < values.length; i++) {
    814                result[i] = clazz.cast(option.getConverter().apply(values[i]));
    815            }
    816            return result;
    817        } catch (final Exception t) {
    818            throw ParseException.wrap(t);
    819        }
    820    }
    821
    822    /**
    823     * Gets a version of this {@code Option} converted to an array of a particular type.
    824     *
    825     * @param option the option.
    826     * @param defaultValue the default value to return if opt is not set.
    827     * @param <T> The array type for the return value.
    828     * @return the values parsed into an array of objects or the defaultValue if the option is not set.
    829     * @throws ParseException if there are problems turning the option value into the desired type.
    830     * @see PatternOptionBuilder
    831     * @since 1.10.0
    832     */
    833    public <T> T[] getParsedOptionValues(final Option option, final T[] defaultValue) throws ParseException {
    834        return getParsedOptionValues(option, () -> defaultValue);
    835    }
    836
    837    /**
    838     * Gets a version of this {@code OptionGroup} converted to an array of a particular type.
    839     *
    840     * @param optionGroup the option group.
    841     * @param <T> The array type for the return value.
    842     * @return the values parsed into an array of objects or null if no option in the OptionGroup is set.
    843     * @throws ParseException if there are problems turning the selected option value into the desired type.
    844     * @see PatternOptionBuilder
    845     * @since 1.10.0
    846     */
    847    public <T> T[] getParsedOptionValues(final OptionGroup optionGroup) throws ParseException {
    848        return getParsedOptionValues(optionGroup, () -> null);
    849    }
    850
    851    /**
    852     * Gets a version of this {@code OptionGroup} converted to an array of a particular type.
    853     *
    854     * @param optionGroup the option group.
    855     * @param defaultValue the default value to return if opt is not set.
    856     * @param <T> The array type for the return value.
    857     * @return the values parsed into an array of objects or null if no option in the OptionGroup is set.
    858     * @throws ParseException if there are problems turning the selected option value into the desired type.
    859     * @see PatternOptionBuilder
    860     * @since 1.10.0
    861     */
    862    public <T> T[] getParsedOptionValues(final OptionGroup optionGroup, final Supplier<T[]> defaultValue) throws ParseException {
    863        if (optionGroup == null || !optionGroup.isSelected()) {
    864            return get(defaultValue);
    865        }
    866        return getParsedOptionValues(optionGroup.getSelected(), defaultValue);
    867    }
    868
    869    /**
    870     * Gets a version of this {@code OptionGroup} converted to an array of a particular type.
    871     *
    872     * @param optionGroup the option group.
    873     * @param defaultValue the default value to return if an option is not selected.
    874     * @param <T> The array type for the return value.
    875     * @return the values parsed into an array of objects or null if no option in the OptionGroup is set.
    876     * @throws ParseException if there are problems turning the option value into the desired type.
    877     * @see PatternOptionBuilder
    878     * @since 1.10.0
    879     */
    880    public <T> T[] getParsedOptionValues(final OptionGroup optionGroup, final T[] defaultValue) throws ParseException {
    881        return getParsedOptionValues(optionGroup, () -> defaultValue);
    882    }
    883
    884    /**
    885     * Gets a version of this {@code Option} converted to an array of a particular type.
    886     *
    887     * @param optionName the name of the option.
    888     * @param <T> The array type for the return value.
    889     * @return the values parsed into an array of objects or null if the option is not set.
    890     * @throws ParseException if there are problems turning the option value into the desired type.
    891     * @see PatternOptionBuilder
    892     * @since 1.10.0
    893     */
    894    public <T> T[] getParsedOptionValues(final String optionName) throws ParseException {
    895        return getParsedOptionValues(resolveOption(optionName));
    896    }
    897
    898    /**
    899     * Gets a version of this {@code Option} converted to an array of a particular type.
    900     *
    901     * @param optionName the name of the option.
    902     * @param defaultValue the default value to return if opt is not set.
    903     * @param <T> The array type for the return value.
    904     * @return the values parsed into an array of objects or defaultValues if the option is not set.
    905     * @throws ParseException if there are problems turning the option value into the desired type.
    906     * @see PatternOptionBuilder
    907     * @since 1.10.0
    908     */
    909    public <T> T[] getParsedOptionValues(final String optionName, final Supplier<T[]> defaultValue) throws ParseException {
    910        return getParsedOptionValues(resolveOption(optionName), defaultValue);
    911    }
    912
    913    /**
    914     * Gets a version of this {@code Option} converted to an array of a particular type.
    915     *
    916     * @param optionName the name of the option.
    917     * @param defaultValue the default value to return if opt is not set.
    918     * @param <T> The array type for the return value.
    919     * @return the values parsed into an array of objects or defaultValues if the option is not set.
    920     * @throws ParseException if there are problems turning the option value into the desired type.
    921     * @see PatternOptionBuilder
    922     * @since 1.10.0
    923     */
    924    public <T> T[] getParsedOptionValues(final String optionName, final T[] defaultValue) throws ParseException {
    925        return getParsedOptionValues(resolveOption(optionName), defaultValue);
    926    }
    927
    928    /**
    929     * Handles deprecated options.
    930     *
    931     * @param option a deprecated option.
    932     */
    933    private void handleDeprecated(final Option option) {
    934        if (deprecatedHandler != null) {
    935            deprecatedHandler.accept(option);
    936        }
    937    }
    938
    939    /**
    940     * jkeyes - commented out until it is implemented properly
    941     * <p>
    942     * Dump state, suitable for debugging.
    943     * </p>
    944     *
    945     * @return Stringified form of this object.
    946     */
    947
    948    /*
    949     * public String toString() { StringBuilder buf = new StringBuilder();
    950     *
    951     * buf.append("[ CommandLine: [ options: "); buf.append(options.toString()); buf.append(" ] [ args: ");
    952     * buf.append(args.toString()); buf.append(" ] ]");
    953     *
    954     * return buf.toString(); }
    955     */
    956
    957    /**
    958     * Tests to see if an option has been set.
    959     *
    960     * @param optionChar character name of the option.
    961     * @return true if set, false if not.
    962     */
    963    public boolean hasOption(final char optionChar) {
    964        return hasOption(String.valueOf(optionChar));
    965    }
    966
    967    /**
    968     * Tests to see if an option has been set.
    969     *
    970     * @param option the option to check.
    971     * @return true if set, false if not.
    972     * @since 1.5.0
    973     */
    974    public boolean hasOption(final Option option) {
    975        final boolean result = options.contains(option);
    976        if (result && option.isDeprecated()) {
    977            handleDeprecated(option);
    978        }
    979        return result;
    980    }
    981
    982    /**
    983     * Tests to see if an option has been set.
    984     *
    985     * @param optionGroup the option group to check.
    986     * @return true if set, false if not.
    987     * @since 1.9.0
    988     */
    989    public boolean hasOption(final OptionGroup optionGroup) {
    990        if (optionGroup == null || !optionGroup.isSelected()) {
    991            return false;
    992        }
    993        return hasOption(optionGroup.getSelected());
    994    }
    995
    996    /**
    997     * Tests to see if an option has been set.
    998     *
    999     * @param optionName Short name of the option.
    1000     * @return true if set, false if not.
    1001     */
    1002    public boolean hasOption(final String optionName) {
    1003        return hasOption(resolveOption(optionName));
    1004    }
    1005
    1006    /**
    1007     * Returns an iterator over the Option members of CommandLine.
    1008     *
    1009     * @return an {@code Iterator} over the processed {@link Option} members of this {@link CommandLine}.
    1010     */
    1011    public Iterator<Option> iterator() {
    1012        return options.iterator();
    1013    }
    1014
    1015    /**
    1016     * Parses a list of values as properties.  All odd numbered values are property keys
    1017     * and even numbered values are property values.  If there are an odd number of values
    1018     * the last value is assumed to be a boolean with a value of "true".
    1019     *
    1020     * @param props the properties to update.
    1021     * @param values the list of values to parse.
    1022     */
    1023    private void processPropertiesFromValues(final Properties props, final List<String> values) {
    1024        for (int i = 0; i < values.size(); i += 2) {
    1025            props.put(values.get(i), i + 1 < values.size() ? values.get(i + 1) : "true");
    1026        }
    1027    }
    1028
    1029    /**
    1030     * Retrieves the option object given the long or short option as a String
    1031     *
    1032     * @param optionName short or long name of the option, may be null.
    1033     * @return Canonicalized option.
    1034     */
    1035    private Option resolveOption(final String optionName) {
    1036        final String actual = Util.stripLeadingHyphens(optionName);
    1037        if (actual != null) {
    1038            return options.stream()
    1039                    .filter(opt -> actual.equals(opt.getOpt()) || actual.equals(opt.getLongOpt()))
    1040                    .findFirst().orElse(null);
    1041        }
    1042        return null;
    1043    }
    1044}