diff --git a/airline-core/src/main/java/com/github/rvesse/airline/parser/errors/ParseArgumentsMissingException.java b/airline-core/src/main/java/com/github/rvesse/airline/parser/errors/ParseArgumentsMissingException.java index bc5933ddb..f17587e0c 100644 --- a/airline-core/src/main/java/com/github/rvesse/airline/parser/errors/ParseArgumentsMissingException.java +++ b/airline-core/src/main/java/com/github/rvesse/airline/parser/errors/ParseArgumentsMissingException.java @@ -15,10 +15,13 @@ */ package com.github.rvesse.airline.parser.errors; +import java.util.Collections; import java.util.List; import org.apache.commons.lang3.StringUtils; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; + /** * Exception thrown when required arguments are missing * @@ -27,6 +30,11 @@ public class ParseArgumentsMissingException extends ParseRestrictionViolatedExce private static final long serialVersionUID = 6220909299960264997L; private final List argumentTitles; + + public ParseArgumentsMissingException(PositionalArgumentMetadata posArg) { + super("Required positional argument %d ('%s') is missing", posArg.getZeroBasedPosition(), posArg.getTitle()); + this.argumentTitles = Collections.singletonList(posArg.getTitle()); + } public ParseArgumentsMissingException(List argumentTitles) { super("Required arguments are missing: '%s'", StringUtils.join(argumentTitles, ',')); diff --git a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AbstractStringRestriction.java b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AbstractStringRestriction.java index 8a93bdf3c..6a2f3191a 100644 --- a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AbstractStringRestriction.java +++ b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AbstractStringRestriction.java @@ -17,6 +17,7 @@ import com.github.rvesse.airline.model.ArgumentsMetadata; import com.github.rvesse.airline.model.OptionMetadata; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; import com.github.rvesse.airline.parser.ParseState; import com.github.rvesse.airline.parser.errors.ParseRestrictionViolatedException; import com.github.rvesse.airline.restrictions.AbstractCommonRestriction; @@ -41,6 +42,12 @@ public final void preValidate(ParseState state, ArgumentsMetadata argumen throw violated(state, arguments, value); } + @Override + public final void preValidate(ParseState state, PositionalArgumentMetadata arguments, String value) { + if (!isValid(value)) + throw violated(state, arguments, value); + } + /** * Method that derived classes must implement to check whether a value is * valid @@ -59,7 +66,7 @@ public final void preValidate(ParseState state, ArgumentsMetadata argumen * @param state * Parser state * @param option - * Option metadata for the option whose value is being checked + * Option meta-data for the option whose value is being checked * @param value * Value which has been deemed invalid * @return Exception @@ -75,11 +82,27 @@ protected abstract ParseRestrictionViolatedException violated(ParseState * @param state * Parser state * @param arguments - * Arguments metadata + * Arguments meta-data * @param value * Value which has been deemed invalid * @return Exception */ protected abstract ParseRestrictionViolatedException violated(ParseState state, ArgumentsMetadata arguments, String value); + + /** + * Method that derived classes must implement to provide an exception for + * the case of an invalid argument value, this will be called if + * {@link #isValid(String)} returns {@code false} + * + * @param state + * Parser state + * @param arguments + * Argument meta-data + * @param value + * Value which has been deemed invalid + * @return Exception + */ + protected abstract ParseRestrictionViolatedException violated(ParseState state, PositionalArgumentMetadata arguments, + String value); } diff --git a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AllowedEnumValuesRestriction.java b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AllowedEnumValuesRestriction.java index 061900c94..d7f2d1122 100644 --- a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AllowedEnumValuesRestriction.java +++ b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AllowedEnumValuesRestriction.java @@ -21,6 +21,7 @@ import java.util.List; import com.github.rvesse.airline.model.ArgumentsMetadata; import com.github.rvesse.airline.model.OptionMetadata; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; import com.github.rvesse.airline.parser.ParseState; import com.github.rvesse.airline.parser.errors.ParseArgumentsIllegalValueException; import com.github.rvesse.airline.parser.errors.ParseOptionIllegalValueException; @@ -66,4 +67,16 @@ public void preValidate(ParseState state, ArgumentsMetadata arguments, St throw new ParseArgumentsIllegalValueException(AbstractCommonRestriction.getArgumentTitle(state, arguments), value, asObjects(rawValues)); } } + + @Override + public void preValidate(ParseState state, PositionalArgumentMetadata arguments, String value) { + // Not enforced if no values specified + if (rawValues.isEmpty()) + return; + + // Check in list of values + if (!this.rawValues.contains(value)) { + throw new ParseArgumentsIllegalValueException(arguments.getTitle(), value, asObjects(rawValues)); + } + } } diff --git a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AllowedRawValuesRestriction.java b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AllowedRawValuesRestriction.java index d377905b7..6004423ed 100644 --- a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AllowedRawValuesRestriction.java +++ b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AllowedRawValuesRestriction.java @@ -21,6 +21,7 @@ import com.github.rvesse.airline.model.ArgumentsMetadata; import com.github.rvesse.airline.model.OptionMetadata; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; import com.github.rvesse.airline.parser.ParseState; import com.github.rvesse.airline.parser.errors.ParseArgumentsIllegalValueException; import com.github.rvesse.airline.parser.errors.ParseOptionIllegalValueException; @@ -65,4 +66,16 @@ public void preValidate(ParseState state, ArgumentsMetadata arguments, St throw new ParseArgumentsIllegalValueException(AbstractCommonRestriction.getArgumentTitle(state, arguments), value, asObjects(rawValues)); } } + + @Override + public void preValidate(ParseState state, PositionalArgumentMetadata arguments, String value) { + // Not enforced if no values specified + if (rawValues.isEmpty()) + return; + + // Check in list of values + if (!this.rawValues.contains(value)) { + throw new ParseArgumentsIllegalValueException(arguments.getTitle(), value, asObjects(rawValues)); + } + } } diff --git a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AllowedValuesRestriction.java b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AllowedValuesRestriction.java index 941a05147..f56577a10 100644 --- a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AllowedValuesRestriction.java +++ b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/AllowedValuesRestriction.java @@ -21,6 +21,7 @@ import com.github.rvesse.airline.model.ArgumentsMetadata; import com.github.rvesse.airline.model.OptionMetadata; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; import com.github.rvesse.airline.parser.ParseState; import com.github.rvesse.airline.parser.errors.ParseArgumentsIllegalValueException; import com.github.rvesse.airline.parser.errors.ParseInvalidRestrictionException; @@ -92,4 +93,18 @@ public void postValidate(ParseState state, ArgumentsMetadata arguments, O } } + @Override + public void postValidate(ParseState state, PositionalArgumentMetadata arguments, Object value) { + // Not enforced if no values specified + if (this.rawValues.isEmpty()) + return; + + String title = arguments.getTitle(); + Set allowedValues = createAllowedValues(state, title, arguments.getJavaType(), + arguments.getTypeConverterProvider().getTypeConverter(arguments, state)); + if (!allowedValues.contains(value)) { + throw new ParseArgumentsIllegalValueException(title, value, allowedValues); + } + } + } diff --git a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/EndsWithRestriction.java b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/EndsWithRestriction.java index 448574547..5a490eb89 100644 --- a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/EndsWithRestriction.java +++ b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/EndsWithRestriction.java @@ -23,6 +23,7 @@ import com.github.rvesse.airline.help.sections.HelpHint; import com.github.rvesse.airline.model.ArgumentsMetadata; import com.github.rvesse.airline.model.OptionMetadata; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; import com.github.rvesse.airline.parser.ParseState; import com.github.rvesse.airline.parser.errors.ParseRestrictionViolatedException; import com.github.rvesse.airline.restrictions.AbstractCommonRestriction; @@ -66,6 +67,14 @@ protected ParseRestrictionViolatedException violated(ParseState state, Ar StringUtils.join(this.suffixes, ", ")); } + @Override + protected ParseRestrictionViolatedException violated(ParseState state, PositionalArgumentMetadata arguments, + String value) { + throw new ParseRestrictionViolatedException( + "Positional argument %d ('%s') has value '%s' which does not end with one of the permitted suffixes: %s", + arguments.getZeroBasedPosition(), arguments.getTitle(), value, StringUtils.join(this.suffixes, ", ")); + } + @Override public String getPreamble() { return String.format("This options value must end with one of the following %s suffixes:", diff --git a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/IsRequiredRestriction.java b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/IsRequiredRestriction.java index 1c26560a3..ee04a413d 100644 --- a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/IsRequiredRestriction.java +++ b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/IsRequiredRestriction.java @@ -19,12 +19,14 @@ import com.github.rvesse.airline.model.ArgumentsMetadata; import com.github.rvesse.airline.model.OptionMetadata; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; import com.github.rvesse.airline.parser.ParseState; import com.github.rvesse.airline.parser.errors.ParseArgumentsMissingException; import com.github.rvesse.airline.parser.errors.ParseOptionMissingException; import com.github.rvesse.airline.restrictions.AbstractCommonRestriction; import com.github.rvesse.airline.utils.AirlineUtils; import com.github.rvesse.airline.utils.predicates.parser.ParsedOptionFinder; +import com.github.rvesse.airline.utils.predicates.parser.ParsedPositionalArgumentFinder; /** * A restriction that options/arguments are required @@ -43,4 +45,11 @@ public void finalValidate(ParseState state, ArgumentsMetadata arguments) throw new ParseArgumentsMissingException(arguments.getTitle()); } + @Override + public void finalValidate(ParseState state, PositionalArgumentMetadata arguments) { + if (IterableUtils.find(state.getParsedPositionalArguments(), + new ParsedPositionalArgumentFinder(arguments)) == null) + throw new ParseArgumentsMissingException(arguments); + } + } diff --git a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/LengthRestriction.java b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/LengthRestriction.java index e7f60cc11..9729f8235 100644 --- a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/LengthRestriction.java +++ b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/LengthRestriction.java @@ -19,6 +19,7 @@ import com.github.rvesse.airline.help.sections.HelpHint; import com.github.rvesse.airline.model.ArgumentsMetadata; import com.github.rvesse.airline.model.OptionMetadata; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; import com.github.rvesse.airline.parser.ParseState; import com.github.rvesse.airline.parser.errors.ParseInvalidRestrictionException; import com.github.rvesse.airline.parser.errors.ParseRestrictionViolatedException; @@ -127,6 +128,31 @@ protected ParseRestrictionViolatedException violated(ParseState state, Ar } } + @Override + protected ParseRestrictionViolatedException violated(ParseState state, PositionalArgumentMetadata arguments, + String value) { + if (this.maximum) { + return new ParseRestrictionViolatedException( + "Positional Argument %d ('%s') was given value '%s' that has length %d which exceeds the maximum permitted length of %d", + arguments.getZeroBasedPosition(), arguments.getTitle(), value, value.length(), this.max); + } else if (this.range) { + if (this.min == this.max) { + return new ParseRestrictionViolatedException( + "Positional Argument %d ('%s') was given value '%s' that has length %d which exceeds the maximum permitted length of %d", + arguments.getZeroBasedPosition(), arguments.getTitle(), value, value.length(), this.max); + } else { + return new ParseRestrictionViolatedException( + "Positional Argument %d ('%s') was given value '%s' that has length %d which is not in the accepted length range of %d to %d characters", + arguments.getZeroBasedPosition(), arguments.getTitle(), value, value.length(), this.min, + this.max); + } + } else { + return new ParseRestrictionViolatedException( + "Positional Argument %d ('%s') was given value '%s' that has length %d which is below the minimum required length of %d", + arguments.getZeroBasedPosition(), arguments.getTitle(), value, value.length(), this.min); + } + } + @Override public String getPreamble() { return null; diff --git a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/NotBlankRestriction.java b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/NotBlankRestriction.java index a87095423..9ad2fd797 100644 --- a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/NotBlankRestriction.java +++ b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/NotBlankRestriction.java @@ -21,6 +21,7 @@ import com.github.rvesse.airline.help.sections.HelpHint; import com.github.rvesse.airline.model.ArgumentsMetadata; import com.github.rvesse.airline.model.OptionMetadata; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; import com.github.rvesse.airline.parser.ParseState; import com.github.rvesse.airline.parser.errors.ParseRestrictionViolatedException; import com.github.rvesse.airline.restrictions.AbstractCommonRestriction; @@ -44,6 +45,13 @@ protected ParseRestrictionViolatedException violated(ParseState state, Ar return new ParseRestrictionViolatedException("Arguments '%s' requires a non-blank value but got value '%s'", AbstractCommonRestriction.getArgumentTitle(state, arguments), value); } + + @Override + protected ParseRestrictionViolatedException violated(ParseState state, PositionalArgumentMetadata arguments, + String value) { + return new ParseRestrictionViolatedException("Positional argument %d ('%s') requires a non-blank value but got value '%s'", + arguments.getZeroBasedPosition(), arguments.getTitle(), value); + } @Override public String getPreamble() { diff --git a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/NotEmptyRestriction.java b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/NotEmptyRestriction.java index 8ae377a38..df0289c3f 100644 --- a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/NotEmptyRestriction.java +++ b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/NotEmptyRestriction.java @@ -21,6 +21,7 @@ import com.github.rvesse.airline.help.sections.HelpHint; import com.github.rvesse.airline.model.ArgumentsMetadata; import com.github.rvesse.airline.model.OptionMetadata; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; import com.github.rvesse.airline.parser.ParseState; import com.github.rvesse.airline.parser.errors.ParseRestrictionViolatedException; import com.github.rvesse.airline.restrictions.AbstractCommonRestriction; @@ -43,6 +44,13 @@ protected ParseRestrictionViolatedException violated(ParseState state, Ar return new ParseRestrictionViolatedException("Arguments '%s' requires a non-empty value", AbstractCommonRestriction.getArgumentTitle(state, arguments)); } + + @Override + protected ParseRestrictionViolatedException violated(ParseState state, PositionalArgumentMetadata arguments, + String value) { + return new ParseRestrictionViolatedException("Positional argument %d ('%s') requires a non-empty value", + arguments.getZeroBasedPosition(), arguments.getTitle()); + } @Override public String getPreamble() { diff --git a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/OccurrencesRestriction.java b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/OccurrencesRestriction.java index 4c73937f2..08dde9bee 100644 --- a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/OccurrencesRestriction.java +++ b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/OccurrencesRestriction.java @@ -26,6 +26,7 @@ import com.github.rvesse.airline.help.sections.HelpHint; import com.github.rvesse.airline.model.ArgumentsMetadata; import com.github.rvesse.airline.model.OptionMetadata; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; import com.github.rvesse.airline.parser.ParseState; import com.github.rvesse.airline.parser.errors.ParseArgumentsMissingException; import com.github.rvesse.airline.parser.errors.ParseRestrictionViolatedException; @@ -76,6 +77,23 @@ public void finalValidate(ParseState state, ArgumentsMetadata arguments) } } + @Override + public void finalValidate(ParseState state, PositionalArgumentMetadata arguments) { + if (occurrences <= 0) + return; + + // NB - Since a positional argument can only ever receive a single value + // setting occurrences to any value other than 1 makes no sense + + if (maximum && state.getParsedArguments().size() > this.occurrences) { + throw new ParseTooManyArgumentsException("At most %d positional arguments may be specified but %d were found", + occurrences, state.getParsedArguments().size()); + } else if (!maximum && state.getParsedArguments().size() < this.occurrences) { + throw new ParseArgumentsMissingException("At least %d positional arguments must be specified but only %d were found", + Collections.singletonList(arguments.getTitle()), this.occurrences, state.getParsedArguments().size()); + } + } + private List titles(ParseState state, ArgumentsMetadata arguments) { if (state.getParsedArguments().size() >= arguments.getTitle().size()) return Collections.emptyList(); diff --git a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/StartsWithRestriction.java b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/StartsWithRestriction.java index 5d614f55b..bfe77a3f3 100644 --- a/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/StartsWithRestriction.java +++ b/airline-core/src/main/java/com/github/rvesse/airline/restrictions/common/StartsWithRestriction.java @@ -23,6 +23,7 @@ import com.github.rvesse.airline.help.sections.HelpHint; import com.github.rvesse.airline.model.ArgumentsMetadata; import com.github.rvesse.airline.model.OptionMetadata; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; import com.github.rvesse.airline.parser.ParseState; import com.github.rvesse.airline.parser.errors.ParseRestrictionViolatedException; import com.github.rvesse.airline.restrictions.AbstractCommonRestriction; @@ -65,6 +66,15 @@ protected ParseRestrictionViolatedException violated(ParseState state, Ar AbstractCommonRestriction.getArgumentTitle(state, arguments), value, StringUtils.join(this.prefixes, ", ")); } + + @Override + protected ParseRestrictionViolatedException violated(ParseState state, PositionalArgumentMetadata arguments, + String value) { + throw new ParseRestrictionViolatedException( + "Positional argument %d ('%s') has value '%s' which does not end with one of the permitted prefixes: %s", + arguments.getZeroBasedPosition(), arguments.getTitle(), value, + StringUtils.join(this.prefixes, ", ")); + } @Override public String getPreamble() { diff --git a/airline-core/src/main/java/com/github/rvesse/airline/utils/predicates/parser/ParsedPositionalArgumentFinder.java b/airline-core/src/main/java/com/github/rvesse/airline/utils/predicates/parser/ParsedPositionalArgumentFinder.java new file mode 100644 index 000000000..67b8653b3 --- /dev/null +++ b/airline-core/src/main/java/com/github/rvesse/airline/utils/predicates/parser/ParsedPositionalArgumentFinder.java @@ -0,0 +1,39 @@ +/** + * Copyright (C) 2010-16 the original author or authors. + * + * Licensed 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 com.github.rvesse.airline.utils.predicates.parser; + +import org.apache.commons.collections4.Predicate; +import org.apache.commons.lang3.tuple.Pair; + +import com.github.rvesse.airline.model.PositionalArgumentMetadata; + +public class ParsedPositionalArgumentFinder implements Predicate> { + + private final PositionalArgumentMetadata posArg; + + public ParsedPositionalArgumentFinder(PositionalArgumentMetadata posArg) { + this.posArg = posArg; + } + + @Override + public boolean evaluate(Pair parsedPosArg) { + if (parsedPosArg == null) return false; + if (this.posArg == null) return false; + + return this.posArg.equals(parsedPosArg.getLeft()); + } + +} diff --git a/airline-examples/src/main/java/com/github/rvesse/airline/examples/userguide/restrictions/custom/MultipleOfRestriction.java b/airline-examples/src/main/java/com/github/rvesse/airline/examples/userguide/restrictions/custom/MultipleOfRestriction.java index 776b9c93f..07dda73fa 100644 --- a/airline-examples/src/main/java/com/github/rvesse/airline/examples/userguide/restrictions/custom/MultipleOfRestriction.java +++ b/airline-examples/src/main/java/com/github/rvesse/airline/examples/userguide/restrictions/custom/MultipleOfRestriction.java @@ -19,6 +19,7 @@ import com.github.rvesse.airline.help.sections.HelpHint; import com.github.rvesse.airline.model.ArgumentsMetadata; import com.github.rvesse.airline.model.OptionMetadata; +import com.github.rvesse.airline.model.PositionalArgumentMetadata; import com.github.rvesse.airline.parser.ParseState; import com.github.rvesse.airline.parser.errors.ParseRestrictionViolatedException; import com.github.rvesse.airline.restrictions.AbstractCommonRestriction; @@ -31,29 +32,35 @@ public MultipleOfRestriction(int multipleOf) { this.multipleOf = multipleOf; } - private void validate(ParseState state, String optionTitle, Object value) { + private void validate(ParseState state, String optionType, String optionTitle, Object value) { if (value instanceof Number) { Number n = (Number) value; if (n.longValue() % this.multipleOf != 0) { throw new ParseRestrictionViolatedException( - "Option '%s' must be an integer multiple of %d but got value '%s'", optionTitle, + "%s '%s' must be an integer multiple of %d but got value '%s'", optionType, optionTitle, this.multipleOf, value); } } else { throw new ParseRestrictionViolatedException( - "Option '%s' must be an integer multiple of %d which requires a numeric value but got value '%s'", - optionTitle, this.multipleOf, value); + "%s '%s' must be an integer multiple of %d which requires a numeric value but got value '%s'", + optionType, optionTitle, this.multipleOf, value); } } @Override public void postValidate(ParseState state, OptionMetadata option, Object value) { - validate(state, option.getTitle(), value); + validate(state, "Option", option.getTitle(), value); } @Override public void postValidate(ParseState state, ArgumentsMetadata arguments, Object value) { - validate(state, getArgumentTitle(state, arguments), value); + validate(state, "Argument", getArgumentTitle(state, arguments), value); + } + + @Override + public void postValidate(ParseState state, PositionalArgumentMetadata arguments, Object value) { + validate(state, String.format("Positional argument %d", arguments.getZeroBasedPosition()), arguments.getTitle(), + value); } @Override