package picocli.examples.interactive; import picocli.CommandLine.Command; import java.security.MessageDigest; import java.util.Arrays; import java.util.Base64; import java.util.concurrent.Callable; @Command(name = "interactive", subcommands = EnterPasswordCommand.class) public class InteractivePositionalParam implements Callable { @Override public Integer call() throws Exception { System.out.println("This command needs a subcommand"); return null; } } @Command(name = "password", description = "Prompts for a password and prints its MD5 hash") class EnterPasswordCommand implements Callable { // https://github.com/remkop/picocli/issues/840 // Picocli cannot handle _single_ interactive positional parameters: // an interactive positional parameter must be followed by another positional parameter. // // Alternatively: use the System.console().readPassword() API directly: @Override public Void call() throws Exception { char[] password = System.console().readPassword("Password to encrypt"); byte[] raw = char2bytes(password); MessageDigest md5 = MessageDigest.getInstance("MD5"); System.out.printf("Your password is hashed to %s.%n", base64(md5.digest(raw))); Arrays.fill(password, '*'); Arrays.fill(raw, (byte) 0); return null; } private byte[] char2bytes(char[] password) { byte[] raw = new byte[password.length]; for (int i = 0; i < raw.length; i++) { raw[i] = (byte) password[i]; } return raw; } private String base64(byte[] bytes) { return Base64.getEncoder().encodeToString(bytes); } }