jcommander icon indicating copy to clipboard operation
jcommander copied to clipboard

JCommander value validator checks only the default value of the list of arguments

Open dmitry-timofeev opened this issue 9 years ago • 3 comments

If an instance of IParameterValidator is used with an arguments list, then only non-default values are validated. It makes sense in most cases, because the defaults are supplied by the app developer.

If an instance of IValueValidator is used with it, then only the default contents of the list is validated. The list of arguments from the command line is never validated.

In the following example both are used. DirectoryNameValidator will be called only with the default value, which is ["./"]. If a user passes a list of arguments from the command line, DirectoryNameValidator won't validate them.

import com.beust.jcommander.IParameterValidator;
import com.beust.jcommander.IValueValidator;
import com.beust.jcommander.JCommander;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.ParameterException;

import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

import static java.util.Collections.singletonList;

public class Main {

    private static class CommandLineOptions {
        @Parameter(description = "A path", validateWith = DirectoryNameValidator.class,
                   validateValueWith = DirectoryListValidator.class)
        List<String> files = new ArrayList<>(singletonList("./"));
    }

    public static class DirectoryNameValidator implements IParameterValidator {
        @Override
        public void validate(String name, String value) throws ParameterException {
            System.out.println("Validating directory: " + value);
            checkIsExistingDirectory(value);
        }
    }

    public static class DirectoryListValidator implements IValueValidator<List<String>> {
        @Override
        public void validate(String name, List<String> value) throws ParameterException {
            System.out.println("Validating parameters list: " + value);
            for (String directoryName : value) {
                checkIsExistingDirectory(directoryName);
            }
        }
    }

    public static void main(String[] args) {
        CommandLineOptions options = new CommandLineOptions();
        JCommander jCommander = new JCommander(options, args);
        System.out.println("Path(s): " + options.files);
    }

    private static void checkIsExistingDirectory(String directoryName) {
        if (!Paths.get(directoryName).toFile().isDirectory()) {
            throw new ParameterException(directoryName + " is not a directory");
        }
    }
}

dmitry-timofeev avatar Apr 28 '16 08:04 dmitry-timofeev

@cbeust started work to fix this. Hope that's ok.

jeremysolarz avatar Dec 27 '16 15:12 jeremysolarz

Hi @dmitry-timofeev,

looking closely at the source of JCommander.java execution of IValueValidtor for "Main parameters" is not implemented at all right now.

It should be implemented in the else part of parseValues.

For default values it is executed in public static void validateValueParameter(Class<? extends IValueValidator> validator, String name, Object value) in ParameterDescription.java line 283, called from validateDefaultValues line 159.

This change looks more complicated. Might come back with a PR in a couple of days.

jeremysolarz avatar Dec 27 '16 22:12 jeremysolarz

This is still an issue. But too busy to work on this for now.

jeremysolarz avatar Jan 30 '17 07:01 jeremysolarz