Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
a7426a4
Fixes for CLI-321
Claudenw Dec 29, 2023
7ae9b1c
Fixed issues with date parsing
Claudenw Dec 29, 2023
ad8466c
Switched to ConvertUtilsBean2 for conversions.
Claudenw Dec 29, 2023
e02c36c
Implementation with tests
Claudenw Jan 3, 2024
9ae4c99
fixed checkstyle issues
Claudenw Jan 3, 2024
b5d2212
fixed spotbugs error & some javadoc
Claudenw Jan 3, 2024
e36f282
Updated spotbugs to 4.8.2.0
Claudenw Jan 3, 2024
1787859
added javadocs and tests
Claudenw Jan 4, 2024
037550d
fixed breaking changes and javadoc
Claudenw Jan 5, 2024
e081e56
added since annotation to Converter and Verifier
Claudenw Jan 5, 2024
942364a
Added an Enum Validator implementation
Claudenw Jan 5, 2024
f365872
fixed formatting issues
Claudenw Jan 5, 2024
3ec932d
fixed checkstyle error
Claudenw Jan 5, 2024
6d5a916
Converted Verifier to Predicate<String>
Claudenw Jan 11, 2024
9b93936
Moved Converter, Verifier and their respective tests to base cli pack…
Claudenw Jan 11, 2024
2ec9d4d
Merge branch 'apache:master' into Functional_Converters
Claudenw Jan 11, 2024
a8d7c89
Removed verifier management and rebased to master
Claudenw Jan 11, 2024
d588a86
moved param <T> tags
Claudenw Jan 11, 2024
0eee294
updated numberic tests
Claudenw Jan 15, 2024
658aa2b
Updated documentation, added Supplier<String> as a default provider f…
Claudenw Jan 22, 2024
b68633a
fixed checkstyle issues
Claudenw Jan 22, 2024
1ca90bb
Added Path to TypeHandler and updated documentation
Claudenw Jan 22, 2024
4d4f52c
removed verifier
Claudenw Jan 26, 2024
30d26f5
removed verifier
Claudenw Jan 26, 2024
2d6ff50
updated javadoc and site documentation
Claudenw Jan 29, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@
<artifactId>junit-vintage-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<properties>
Expand Down Expand Up @@ -246,6 +251,7 @@
<configuration>
<excludeFilterFile>${basedir}/src/conf/spotbugs-exclude-filter.xml</excludeFilterFile>
</configuration>
<version>4.8.2.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand Down
109 changes: 99 additions & 10 deletions src/main/java/org/apache/commons/cli/CommandLine.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.function.Supplier;

/**
* Represents list of arguments parsed against a {@link Options} descriptor.
Expand Down Expand Up @@ -254,6 +255,18 @@ public String getOptionValue(final char opt) {
* @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
*/
public String getOptionValue(final char opt, final String defaultValue) {
return getOptionValue(String.valueOf(opt), () -> defaultValue);
}

/**
* Gets the argument, if any, of an option.
*
* @param opt character name of the option
* @param defaultValue is a supplier for the default value to be returned if the option is not specified.
* @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
* @since 1.7.0
*/
public String getOptionValue(final char opt, final Supplier<String> defaultValue) {
return getOptionValue(String.valueOf(opt), defaultValue);
}

Expand Down Expand Up @@ -281,10 +294,22 @@ public String getOptionValue(final Option option) {
* @since 1.5.0
*/
public String getOptionValue(final Option option, final String defaultValue) {
final String answer = getOptionValue(option);
return answer != null ? answer : defaultValue;
return getOptionValue(option, () -> defaultValue);
}

/**
* Gets the first argument, if any, of an option.
*
* @param option name of the option.
* @param defaultValue is a supplier for the default value to be returned if the option is not specified.
* @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
* @since 1.7.0
*/
public String getOptionValue(final Option option, final Supplier<String> defaultValue) {
final String answer = getOptionValue(option);
return answer != null ? answer : defaultValue.get();
}

/**
* Gets the first argument, if any, of this option.
*
Expand All @@ -303,9 +328,22 @@ public String getOptionValue(final String opt) {
* @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
*/
public String getOptionValue(final String opt, final String defaultValue) {
return getOptionValue(resolveOption(opt), () -> defaultValue);
}

/**
* Gets the first argument, if any, of an option.
*
* @param opt name of the option.
* @param defaultValue is a supplier for the default value to be returned if the option is not specified.
* @return Value of the argument if option is set, and has an argument, otherwise {@code defaultValue}.
* @since 1.7.0
*/
public String getOptionValue(final String opt, final Supplier<String> defaultValue) {
return getOptionValue(resolveOption(opt), defaultValue);
}


/**
* Gets the array of values, if any, of an option.
*
Expand Down Expand Up @@ -349,46 +387,97 @@ public String[] getOptionValues(final String opt) {
* Gets a version of this {@code Option} converted to a particular type.
*
* @param opt the name of the option.
* @param <T> The return type for the method.
* @return the value parsed into a particular object.
* @throws ParseException if there are problems turning the option value into the desired type
* @see PatternOptionBuilder
* @since 1.5.0
*/
public Object getParsedOptionValue(final char opt) throws ParseException {
public <T> T getParsedOptionValue(final char opt) throws ParseException {
return getParsedOptionValue(String.valueOf(opt));
}

/**
* Gets a version of this {@code Option} converted to a particular type.
*
* @param option the name of the option.
* @param <T> The return type for the method.
* @return the value parsed into a particular object.
* @throws ParseException if there are problems turning the option value into the desired type
* @see PatternOptionBuilder
* @since 1.5.0
*/
public Object getParsedOptionValue(final Option option) throws ParseException {
public <T> T getParsedOptionValue(final Option option) throws ParseException {
return getParsedOptionValue(option, null);
}

/**
* Gets a version of this {@code Option} converted to a particular type.
*
* @param opt the name of the option.
* @param <T> The return type for the method.
* @return the value parsed into a particular object.
* @throws ParseException if there are problems turning the option value into the desired type
* @see PatternOptionBuilder
* @since 1.2
Comment thread
garydgregory marked this conversation as resolved.
*/
public <T> T getParsedOptionValue(final String opt) throws ParseException {
return getParsedOptionValue(resolveOption(opt));
}

/**
* Gets a version of this {@code Option} converted to a particular type.
*
* @param opt the name of the option.
* @param defaultValue the default value to return if opt is not set.
* @param <T> The return type for the method.
* @return the value parsed into a particular object.
* @throws ParseException if there are problems turning the option value into the desired type
* @see PatternOptionBuilder
* @since 1.7.0
*/
public <T> T getParsedOptionValue(final char opt, final T defaultValue) throws ParseException {
return getParsedOptionValue(String.valueOf(opt), defaultValue);
}

/**
* Gets a version of this {@code Option} converted to a particular type.
*
* @param option the name of the option.
* @param defaultValue the default value to return if opt is not set.
* @param <T> The return type for the method.
* @return the value parsed into a particular object.
* @throws ParseException if there are problems turning the option value into the desired type
* @see PatternOptionBuilder
* @since 1.7.0
*/
@SuppressWarnings("unchecked")
public <T> T getParsedOptionValue(final Option option, final T defaultValue) throws ParseException {
if (option == null) {
return null;
}
final String res = getOptionValue(option);
if (res == null) {
return null;

try {
return res == null ? defaultValue : (T) option.getConverter().apply(res);
} catch (Exception e) {
throw ParseException.wrap(e);
}
return TypeHandler.createValue(res, option.getType());
}

/**
* Gets a version of this {@code Option} converted to a particular type.
*
* @param opt the name of the option.
* @param defaultValue the default value to return if opt is not set.
* @param <T> The return type for the method.
* @return the value parsed into a particular object.
* @throws ParseException if there are problems turning the option value into the desired type
* @see PatternOptionBuilder
* @since 1.2
* @since 1.7.0
*/
public Object getParsedOptionValue(final String opt) throws ParseException {
return getParsedOptionValue(resolveOption(opt));
public <T> T getParsedOptionValue(final String opt, final T defaultValue) throws ParseException {
return getParsedOptionValue(resolveOption(opt), defaultValue);
}

/**
Expand Down
78 changes: 78 additions & 0 deletions src/main/java/org/apache/commons/cli/Converter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package org.apache.commons.cli;

import java.io.File;
import java.net.URL;
import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
* The definition of the functional interface to call when doing a conversion.
* Like {@code Function<String,T>} but can throw an Exception.
*
* @param <T> The return type for the function.
* @since 1.7.0
*/
@FunctionalInterface
public interface Converter<T> {

/** The default converter. Does nothing. */
Converter<?> DEFAULT = s -> s;

/** Class name converter. Calls {@code Class.forName}. */
Converter<Class<?>> CLASS = s -> Class.forName(s);

/** File name converter. Calls @{code new File(s)} */
Converter<File> FILE = s -> new File(s);

/** Path converter. Calls @{code new Path(s)} */
Converter<Path> PATH = s -> new File(s).toPath();

/**
* Number converter. Converts to a Double if a decimal point ('.') is in the
* string or a Long otherwise.
*/
Converter<Number> NUMBER = s -> {
if (s.indexOf('.') != -1) {
return Double.valueOf(s);
}
return Long.valueOf(s);
};

/**
* Converts a class name to an instance of the class. Uses the Class converter
* to find the class and then call the default constructor.
* @see #CLASS
*/
Converter<Object> OBJECT = s -> CLASS.apply(s).getConstructor().newInstance();

/** Creates a URL. Calls {@code new URL(s)}. */
Converter<URL> URL = s -> new URL(s);

/** Converts to a date using the format string Form "EEE MMM dd HH:mm:ss zzz yyyy". */
Converter<Date> DATE = s -> new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy").parse(s);

/**
* Applies the conversion function to the String argument.
* @param str the String to convert
* @return the Object from the conversion.
* @throws Exception on error.
*/
T apply(String str) throws Exception;
}
41 changes: 40 additions & 1 deletion src/main/java/org/apache/commons/cli/Option.java
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ public static final class Builder {

/** The character that is the value separator */
private char valueSeparator;

/** The converter to convert to type **/
private Converter<?> converter;

/**
* Constructs a new {@code Builder} with the minimum required parameters for an {@code Option} instance.
Expand Down Expand Up @@ -270,6 +273,19 @@ public Builder valueSeparator(final char valueSeparator) {
this.valueSeparator = valueSeparator;
return this;
}

/**
* Sets the converter for the option.
* <p>Note: see {@link TypeHandler} for serialization discussion.</p>
* @param converter the Converter to use.
* @return this builder, to allow method chaining.
* @since 1.7.0
*/
public Builder converter(final Converter<?> converter) {
this.converter = converter;
return this;
}

}

/** Specifies the number of argument values has not been specified */
Expand Down Expand Up @@ -335,6 +351,9 @@ public static Builder builder(final String option) {

/** The character that is the value separator. */
private char valuesep;

/** The explicit converter for this option. May be null */
private transient Converter<?> converter;

/**
* Private constructor used by the nested Builder class.
Expand All @@ -351,6 +370,7 @@ private Option(final Builder builder) {
this.required = builder.required;
this.type = builder.type;
this.valuesep = builder.valueSeparator;
this.converter = builder.converter;
}

/**
Expand Down Expand Up @@ -423,7 +443,6 @@ private void add(final String value) {
if (!acceptsArg()) {
throw new IllegalArgumentException("Cannot add value, list full.");
}

// store value
values.add(value);
}
Expand Down Expand Up @@ -695,6 +714,8 @@ private boolean hasNoValues() {
}

/**
* Returns whether this Option can have an optional argument.
*
* @return whether this Option can have an optional argument
*/
public boolean hasOptionalArg() {
Expand Down Expand Up @@ -865,6 +886,24 @@ public void setType(final Object type) {
public void setValueSeparator(final char sep) {
this.valuesep = sep;
}

/**
* Gets the value to type converter.
* @return the value to type converter
* @since 1.7.0
*/
public Converter<?> getConverter() {
return converter == null ? TypeHandler.getConverter(type) : converter;
}

/**
* Sets the value to type converter.
* @param converter The converter to convert the string value to the type.
* @since 1.7.0
*/
public void setConverter(final Converter<?> converter) {
this.converter = converter;
}

/**
* Dump state, suitable for debugging.
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/org/apache/commons/cli/OptionBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more
@Deprecated
public final class OptionBuilder {


/** Long option */
private static String longOption;

Expand Down Expand Up @@ -108,6 +109,7 @@ public static Option create(final String opt) throws IllegalArgumentException {
option.setOptionalArg(optionalArg);
option.setArgs(argCount);
option.setType(type);
option.setConverter(TypeHandler.getConverter(type));
option.setValueSeparator(valueSeparator);
option.setArgName(argName);
} finally {
Expand Down
Loading