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}