Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

jakarta.validation-api with picocli #1798

Closed
ashr123 opened this issue Sep 1, 2022 · 4 comments
Closed

jakarta.validation-api with picocli #1798

ashr123 opened this issue Sep 1, 2022 · 4 comments

Comments

@ashr123
Copy link

ashr123 commented Sep 1, 2022

is there a way to use jakarta.validation-api with plain picocli (without Springboot/Hibernate etc.)? it may be silly but I'm trying to use it as it is but is doesn't work.
Example:

@CommandLine.Parameters(description = "Is to show sum calculation? (values: true, false)")
private boolean isDetailed;
@Positive
@CommandLine.Parameters(description = "How many roles should the program make?")
private long roles;
@Min(3)
@CommandLine.Parameters(description = "Used to tell the number of side the dice has.")
private int d;
@PositiveOrZero
@CommandLine.Parameters(
		description = "Used to be added per role.",
		defaultValue = "0"
)
private int constantAddition;
@ashr123 ashr123 changed the title jakarta.validation-api withpicocli jakarta.validation-api with picocli Sep 1, 2022
@remkop
Copy link
Owner

remkop commented Sep 1, 2022

I suspect that is not possible but you can ask the maintainers of the jakarta.validation-api project, they may be better positioned to answer that question.

@ashr123
Copy link
Author

ashr123 commented Sep 1, 2022

@remkop I see that hibernate-validator is an implementation that uses validation but there is need to create Validator (see https://docs.jboss.org/hibernate/validator/8.0/reference/en-US/html_single/#_validating_constraints) can this integrate dynamically to picocli (i.e. recognize the existence of hibernate-validator and initiate a Validator)?
Maybe it can be used in picocli.CommandLine#executeUserObject

@remkop
Copy link
Owner

remkop commented Sep 2, 2022

There are several ways to think about this.
I don't plan on adding built-in support for jakarta.validation-api to the picocli library.

However, the example in the user manual (calling a helper method from the run method) is only one way to accomplish this.

Perhaps a nicer way is to have a custom IExecutionStrategy which does the validation before executing the command.

Such a custom IExecutionStrategy could look something like this:

class ValidatingExecutionStrategy implements IExecutionStrategy {
    public int execute(ParseResult parseResult) {
        validate(parseResult.commandSpec());
        return new CommandLine.RunLast().execute(parseResult); // default execution strategy
    }

    void validate(CommandSpec spec) {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<Object>> violations = validator.validate(spec.userObject());
        if (!violations.isEmpty()) {
            String errorMsg = "";
            for (ConstraintViolation<?> violation : violations) {
                errorMsg += "ERROR: " + violation.getMessage() + "\n";
            }
            throw new ParameterException(spec.commandLine(), errorMsg);
        }
    }
}

The application would wire it in like this:

    public static void main(String[] args) {
        MyApp app = new MyApp();
        new CommandLine(app)
                .setExecutionStrategy(new ValidatingExecutionStrategy())
                .execute(args);
    }

I have added this example to the user manual (the HTML will be published with the next release),
and updated the java examples
and added a kotlin example.

@ashr123
Copy link
Author

ashr123 commented Sep 2, 2022

@remkop thanks 😃
eventually I went with the following code:

Logger.getLogger("org.hibernate").setLevel(Level.OFF);
final CommandLine commandLine = new CommandLine(DiceRoller.class);
CommandLine.IExecutionStrategy executionStrategy = commandLine.getExecutionStrategy();
commandLine.setExecutionStrategy(parseResult ->
		{
			try (ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory())
			{
				Set<ConstraintViolation<Object>> violations = validatorFactory.getValidator().validate(parseResult.commandSpec().userObject());
				if (!violations.isEmpty())
				{
					final StringBuilder errorMsg = new StringBuilder();
					for (ConstraintViolation<?> violation : violations)
						errorMsg.append("ERROR: ").append(violation.getPropertyPath()).append(' ').append(violation.getMessage()).append(System.lineSeparator());
					throw new CommandLine.ParameterException(parseResult.commandSpec().commandLine(), errorMsg.toString());
				}
			}
			return executionStrategy.execute(parseResult);
		})
		.execute(args);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants