From 5808f37abf2de8b3752692c43a197af481b18945 Mon Sep 17 00:00:00 2001 From: Andrea Cosentino Date: Wed, 28 Oct 2026 13:32:09 +0100 Subject: [PATCH 1/3] Javadoc: Fix swapped '@' and '+' descriptions in PatternOptionBuilder The table in the PatternOptionBuilder Javadoc had '@' and '+' the wrong way round. '@' is the code that creates an object through the no-arg constructor of the named class, while '+' only loads the class; the existing tests already check it that way. While at it, note in Converter.OBJECT, Converter.CLASS, TypeHandler.createObject() and TypeHandler.createClass() that they load whatever class the value names, so they shouldn't be used on values from an untrusted source. Co-Authored-By: Claude Opus 5.5 --- src/main/java/org/apache/commons/cli/Converter.java | 8 ++++++++ .../org/apache/commons/cli/PatternOptionBuilder.java | 9 +++++++-- src/main/java/org/apache/commons/cli/TypeHandler.java | 7 +++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/cli/Converter.java b/src/main/java/org/apache/commons/cli/Converter.java index d655205ea..a5e9c9b8f 100644 --- a/src/main/java/org/apache/commons/cli/Converter.java +++ b/src/main/java/org/apache/commons/cli/Converter.java @@ -46,6 +46,10 @@ public interface Converter { /** * Converts a String to a {@link Class}. Calls {@link Class#forName(String, boolean, ClassLoader)} with {@code initialize} set to {@code false} so that * resolving the name does not by itself trigger the class's static initializer. + *

+ * The value can name any class visible to the class loader of this library. Do not apply this converter, the default for options of type {@link Class}, + * to values from an untrusted source. + *

*/ Converter, ClassNotFoundException> CLASS = s -> Class.forName(s, false, Converter.class.getClassLoader()); @@ -66,6 +70,10 @@ public interface Converter { /** * Converts a class name to an instance of the class. Uses the Class converter to find the class and then call the default constructor. + *

+ * Creating the instance initializes the named class and runs its public no-argument constructor, so the value decides which code runs. Do not apply this + * converter, the default for options of type {@link Object}, to values from an untrusted source. + *

* * @see #CLASS */ diff --git a/src/main/java/org/apache/commons/cli/PatternOptionBuilder.java b/src/main/java/org/apache/commons/cli/PatternOptionBuilder.java index f68cfaeac..3e4587f1a 100644 --- a/src/main/java/org/apache/commons/cli/PatternOptionBuilder.java +++ b/src/main/java/org/apache/commons/cli/PatternOptionBuilder.java @@ -35,7 +35,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more * * * b@ - * -b [class name] + * -b [class name] (creates object via empty constructor) * * * c> @@ -43,7 +43,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more * * * d+ - * -d [class name] (creates object via empty constructor) + * -d [class name] * * * e% @@ -69,6 +69,11 @@ Licensed to the Apache Software Foundation (ASF) under one or more * * *

+ * The {@code @} and {@code +} codes load the class named by the option value, and {@code @} also creates an instance by calling its public no-argument + * constructor. Do not use these codes for values from an untrusted source. + *

+ * + *

* TODO These need to break out to OptionType and also to be pluggable. *

*/ diff --git a/src/main/java/org/apache/commons/cli/TypeHandler.java b/src/main/java/org/apache/commons/cli/TypeHandler.java index 4709c7811..8fe815b26 100644 --- a/src/main/java/org/apache/commons/cli/TypeHandler.java +++ b/src/main/java/org/apache/commons/cli/TypeHandler.java @@ -49,6 +49,9 @@ public class TypeHandler { /** * Returns the class whose name is {@code className}. + *

+ * Do not pass a class name from an untrusted source, see {@link Converter#CLASS}. + *

* * @param className The class name. * @return The class if it is found. @@ -124,6 +127,10 @@ public static Number createNumber(final String string) throws ParseException { /** * Creates an Object from the class name and empty constructor. + *

+ * This initializes the named class and runs its public no-argument constructor. Do not pass a class name from an untrusted source, see + * {@link Converter#OBJECT}. + *

* * @param className The argument value. * @return The initialized object. From e94719015d3992a4bc265673819a31e636fc5709 Mon Sep 17 00:00:00 2001 From: Andrea Cosentino Date: Thu, 29 Oct 2026 06:28:44 +0100 Subject: [PATCH 2/3] Update src/main/java/org/apache/commons/cli/PatternOptionBuilder.java Co-authored-by: Gary Gregory --- src/main/java/org/apache/commons/cli/PatternOptionBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/org/apache/commons/cli/PatternOptionBuilder.java b/src/main/java/org/apache/commons/cli/PatternOptionBuilder.java index 3e4587f1a..6b96962ed 100644 --- a/src/main/java/org/apache/commons/cli/PatternOptionBuilder.java +++ b/src/main/java/org/apache/commons/cli/PatternOptionBuilder.java @@ -35,7 +35,7 @@ Licensed to the Apache Software Foundation (ASF) under one or more * * * b@ - * -b [class name] (creates object via empty constructor) + * -b [class name] (creates object via public no-argument constructor) * * * c> From c207534766a7266cd134083460febf482379bc46 Mon Sep 17 00:00:00 2001 From: Andrea Cosentino Date: Thu, 29 Oct 2026 06:29:14 +0100 Subject: [PATCH 3/3] Update src/main/java/org/apache/commons/cli/PatternOptionBuilder.java Co-authored-by: Gary Gregory --- .../java/org/apache/commons/cli/PatternOptionBuilder.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/apache/commons/cli/PatternOptionBuilder.java b/src/main/java/org/apache/commons/cli/PatternOptionBuilder.java index 6b96962ed..1cecc68b3 100644 --- a/src/main/java/org/apache/commons/cli/PatternOptionBuilder.java +++ b/src/main/java/org/apache/commons/cli/PatternOptionBuilder.java @@ -69,8 +69,9 @@ Licensed to the Apache Software Foundation (ASF) under one or more * * *

- * The {@code @} and {@code +} codes load the class named by the option value, and {@code @} also creates an instance by calling its public no-argument - * constructor. Do not use these codes for values from an untrusted source. + * When a converted option value is retrieved, for example through {@link CommandLine#getParsedOptionValue(String)}, the {@code @} and {@code +} codes + * load the class named by the option value, and {@code @} also creates an instance by calling its public no-argument constructor. Do not use these codes + * for values from an untrusted source. *

* *