diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 486ec8f34..94e2d4982 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -26,6 +26,7 @@ No features have been promoted in this picocli release.
## Fixed issues
+- [#283] Enhancement and API Change: Provide `getMissing` method on MissingParameterException to get a reference to the problematic options and positional parameters. Thanks to [jcapsule](https://github.com/jcapsule) for the suggestion.
- [#323] Enhancement: Remove dependency on java.sql package: picocli should only require the java.base module when running in Java 9.
- [#325] Enhancement: Allow custom type converter to map empty String to custom default value for empty options. Thanks to [jesselong](https://github.com/jesselong) for the suggestion.
- [#303] Enhancement: Improve validation to prevent common mistakes.
diff --git a/src/main/java/picocli/CommandLine.java b/src/main/java/picocli/CommandLine.java
index 6640fbeeb..d63da94a1 100644
--- a/src/main/java/picocli/CommandLine.java
+++ b/src/main/java/picocli/CommandLine.java
@@ -5191,7 +5191,7 @@ private void assertNoMissingParameters(ArgSpec argSpec, int arity, Stack
if (arity > args.size()) {
if (arity == 1) {
if (argSpec.isOption()) {
- throw new MissingParameterException(CommandLine.this, "Missing required parameter for " +
+ throw new MissingParameterException(CommandLine.this, argSpec, "Missing required parameter for " +
optionDescription("", argSpec, 0));
}
Range indexRange = ((PositionalParamSpec) argSpec).index();
@@ -5213,13 +5213,13 @@ private void assertNoMissingParameters(ArgSpec argSpec, int arity, Stack
} else {
msg += (count > 1 ? "s: " : ": ");
}
- throw new MissingParameterException(CommandLine.this, msg + names);
+ throw new MissingParameterException(CommandLine.this, argSpec, msg + names);
}
if (args.isEmpty()) {
- throw new MissingParameterException(CommandLine.this, optionDescription("", argSpec, 0) +
+ throw new MissingParameterException(CommandLine.this, argSpec, optionDescription("", argSpec, 0) +
" requires at least " + arity + " values, but none were specified.");
}
- throw new MissingParameterException(CommandLine.this, optionDescription("", argSpec, 0) +
+ throw new MissingParameterException(CommandLine.this, argSpec, optionDescription("", argSpec, 0) +
" requires at least " + arity + " values, but only " + args.size() + " were specified: " + reverse(args));
}
}
@@ -7371,20 +7371,23 @@ private static ParameterException create(CommandLine cmd, Exception ex, String a
*/
public static class MissingParameterException extends ParameterException {
private static final long serialVersionUID = 5075678535706338753L;
- public MissingParameterException(CommandLine commandLine, String msg) {
+ private final List missing;
+ public MissingParameterException(CommandLine commandLine, ArgSpec missing, String msg) { this(commandLine, Arrays.asList(missing), msg); }
+ public MissingParameterException(CommandLine commandLine, Collection missing, String msg) {
super(commandLine, msg);
+ this.missing = Collections.unmodifiableList(new ArrayList(missing));
}
-
+ public List getMissing() { return missing; }
private static MissingParameterException create(CommandLine cmd, Collection missing, String separator) {
if (missing.size() == 1) {
- return new MissingParameterException(cmd, "Missing required option '"
+ return new MissingParameterException(cmd, missing, "Missing required option '"
+ describe(missing.iterator().next(), separator) + "'");
}
List names = new ArrayList(missing.size());
for (ArgSpec argSpec : missing) {
names.add(describe(argSpec, separator));
}
- return new MissingParameterException(cmd, "Missing required options " + names.toString());
+ return new MissingParameterException(cmd, missing, "Missing required options " + names.toString());
}
private static String describe(ArgSpec argSpec, String separator) {
String prefix = (argSpec.isOption())
diff --git a/src/test/java/picocli/CommandLineArityTest.java b/src/test/java/picocli/CommandLineArityTest.java
index e1019d4d5..5a8f276dc 100644
--- a/src/test/java/picocli/CommandLineArityTest.java
+++ b/src/test/java/picocli/CommandLineArityTest.java
@@ -272,6 +272,8 @@ class Example {
fail("Should not accept missing mandatory parameter");
} catch (MissingParameterException ex) {
assertEquals("Missing required parameter: ", ex.getMessage());
+ assertEquals(1, ex.getMissing().size());
+ assertEquals("", ex.getMissing().get(0).paramLabel());
}
}
@Test
@@ -662,6 +664,8 @@ class OptionsNoArityAndParameters {
fail("expected MissingParameterException");
} catch (MissingParameterException ok) {
assertEquals("Missing required parameter for option '-chars' ()", ok.getMessage());
+ assertEquals(1, ok.getMissing().size());
+ assertTrue(ok.getMissing().get(0).toString(), ok.getMissing().get(0) instanceof Model.OptionSpec);
}
}
@@ -917,6 +921,8 @@ class Arg {
fail("Expected MissingParameterException");
} catch (MissingParameterException ex) {
assertEquals("positional parameter at index 0..* () requires at least 2 values, but only 1 were specified: [p3]", ex.getMessage());
+ assertEquals(1, ex.getMissing().size());
+ assertTrue(ex.getMissing().get(0).toString(), ex.getMissing().get(0) instanceof Model.PositionalParamSpec);
}
}
diff --git a/src/test/java/picocli/CommandLineModelTest.java b/src/test/java/picocli/CommandLineModelTest.java
index 50457edf4..e22b8e0cf 100644
--- a/src/test/java/picocli/CommandLineModelTest.java
+++ b/src/test/java/picocli/CommandLineModelTest.java
@@ -261,6 +261,8 @@ public void testVersionHelp_helpCommand() {
commandLine.parse();
} catch (MissingParameterException ex) {
assertEquals("Missing required option '-x=PARAM'", ex.getMessage());
+ assertEquals(1, ex.getMissing().size());
+ assertSame(ex.getMissing().get(0).toString(), parent.posixOptionsMap().get('x'), ex.getMissing().get(0));
}
}
diff --git a/src/test/java/picocli/CommandLineTest.java b/src/test/java/picocli/CommandLineTest.java
index 68a7528a3..940196e88 100644
--- a/src/test/java/picocli/CommandLineTest.java
+++ b/src/test/java/picocli/CommandLineTest.java
@@ -1681,6 +1681,8 @@ class Args {
fail("MissingParameterException expected");
} catch (MissingParameterException ex) {
assertEquals("positional parameter at index 0..* () requires at least 2 values, but only 1 were specified: [a,b,c,d,e]", ex.getMessage());
+ assertEquals(1, ex.getMissing().size());
+ assertTrue(ex.getMissing().get(0).toString(), ex.getMissing().get(0) instanceof Model.PositionalParamSpec);
}
try {
CommandLine.populateCommand(new Args()); // 0 arg: should fail