锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

picocli-入门

时间:2022-10-28 23:30:00 jhs200t电阻器jhs保电阻电缆

https://picocli.info/#_introduction

前言

相信每个Java程序员都用过Scanner ,兴奋地写了一个命令行程序。
但是,使用命令行程序也很实用Java编写一个强大的命令程序并不容易,主要有以下痛点:

  • 没有成熟的框架包装参数接收、参数提示、参数验证
  • 很难处理参数的互斥以及特定命令的相互依赖
  • 无法进行命令自动补全
  • 由于JVM解释执行字节码,并解释执行字节码JIT不能在短期执行中发挥作用,Java慢慢启动命令行程序
  • 集成SpringBoot以及其他组件,启动更慢

这些问题都可以使用Picocli来解决

引用:https://blog.csdn.net/qq_40419564/article/details/115290878

Picocli 基本介绍

Every main method deserves picocli!
Picocli aims to be the easiest way to create rich command line applications that can run on and off the JVM.

入门

引入maven依赖

<dependency>      <groupId>info.picocligroupId>      <artifactId>picocliartifactId>      <version>4.6.3version>  dependency> 

应用demo

@CommandLine.Command(name = "checksum", mixinStandardHelpOptions = true, version = "checksum 4.0",         description = "Prints the checksum (SHA-256 by default) of a file to STDOUT.") public class CheckSum implements Callable<Integer> { 
              @CommandLine.Parameters(index = "0", description = "The file whose checksum to calculate.")     private File file;      @CommandLine.Option(names = { 
        "-a", "--algorithm"}, description = "MD5, SHA-1, SHA-256, ...")     prvate String algorithm = "SHA-256";

    @Override
    public Integer call() throws Exception { 
         // your business logic goes here...
        byte[] fileContents = Files.readAllBytes(file.toPath());
        byte[] digest = MessageDigest.getInstance(algorithm).digest(fileContents);
        System.out.printf("%0" + (digest.length*2) + "x%n", new BigInteger(1, digest));
        return 0;
    }

    public static void main(String... args) { 
        
        int exitCode = new CommandLine(new CheckSum()).execute(args);
        System.exit(exitCode);
    }
}

maven打包

<build>
        <finalName>demo1finalName>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-pluginartifactId>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependenciesdescriptorRef>
                    descriptorRefs>
                    <archive>
                        <manifest>
                            <mainClass>cn.jhs.CheckSummainClass>
                        manifest>
                    archive>
                configuration>
                <executions>
                    <execution>
                        <id>make-assemblyid>
                        <phase>packagephase>
                        <goals>
                            <goal>singlegoal>
                        goals>
                    execution>
                executions>
            plugin>
        plugins>
    build>

执行命令mvn clean package

Command

> java -jar target/demo1-jar-with-dependencies.jar                 
Missing required parameter: ''
Usage: checksum [-hV] [-a=<algorithm>] <file>
Prints the checksum (SHA-256 by default) of a file to STDOUT.
      <file>      The file whose checksum to calculate.
  -a, --algorithm=<algorithm>
                  MD5, SHA-1, SHA-256, ...
  -h, --help      Show this help message and exit.
  -V, --version   Print version information and exit.

> echo "hello" > hello.txt
> java -jar target/demo1-jar-with-dependencies.jar hello.txt            
5891b5b522d5df086d0ff0b110fbd9d21bb4fc7163af34d08286a2e846f6be03

使用别名

> alias checksum=java\ -jar\ target/demo1-jar-with-dependencies.jar

> checksum hello.txt -a SHA-1
f572d396fae9206628714fb2ce00f72e94f2258f


Options and Parameters

Command line arguments可以分为optionspositional parameters
- option有一个名称

  • positional parameters位置参数通常是 option后面的值,但它们可能是混合的。

在这里插入图片描述

Options

option必须有一个或多个名称。 Picocli 允许您使用任何您想要的选项名称。

默认情况下,option名称区分大小写.

class Tar { 
        
    @Option(names = "-c", description = "create a new archive")
    boolean create;

    @Option(names = { 
         "-f", "--file" }, paramLabel = "ARCHIVE", description = "the archive file")
    File archive;

    @Parameters(paramLabel = "FILE", description = "one or more files to archive")
    File[] files;

    @Option(names = { 
         "-h", "--help" }, usageHelp = true, description = "display a help message")
    private boolean helpRequested = false;
}

TestCase

String[] args = { 
         "-c", "--file", "result.tar", "file1.txt", "file2.txt" };
Tar tar = new Tar();
new CommandLine(tar).parseArgs(args);

assert !tar.helpRequested;
assert  tar.create;
assert  tar.archive.equals(new File("result.tar"));
assert  Arrays.equals(tar.files, new File[] { 
        new File("file1.txt"), new File("file2.txt")});

Interactive (Password) Options

对于标记为Interactive Optionspositional parameters,会提示用户在控制台上输入一个值。

交互式

class Login implements Callable<Integer> { 
        
    @Option(names = { 
        "-u", "--user"}, description = "User name")
    String user;

	//响应式 Option
    @Option(names = { 
        "-p", "--password"}, description = "Passphrase", interactive = true)
    char[] password;

    public Integer call() throws Exception { 
        
        byte[] bytes = new byte[password.length];
        for (int i = 0; i < bytes.length; i++) { 
         bytes[i] = (byte) password[i]; }

        MessageDigest md = MessageDigest.getInstance("SHA-256");
        md.update(bytes);

        System.out.printf("Hi %s, your password is hashed to %s.%n", user, base64(md.digest()));

        // null out the arrays when done
        Arrays.fill(bytes, (byte) 0);
        Arrays.fill(password, ' ');

        return 0;
    }

    private String base64(byte[] arr) { 
         /* ... */ }
}

testcase
执行命令:new CommandLine(new Login()).execute("-u", "user123", "-p");
然后会提示用户输入一个值:

Enter value for --password (Passphrase):

在 Java 6 或更高版本上运行时,用户输入不会回显到控制台。
用户输入密码值并按下回车后,将call()调用该方法,该方法将打印如下内容:

Hi user123, your passphrase is hashed to 75K3eLr+dx6JJFuJ7LwIpEpOFmwGZZkRiB84PURz6U8=.

#### 可选的 Interactive 
默认情况下,` Interactive  Options`会导致应用程序等待标准输入上的输入。
对于即需要以交互方式 又需要以批处理模式运行的命令,如果该选项**可以选择的**,这将很有用。

**arity**
```java
@Option(names = "--user")
String user;

@Option(names = "--password", arity = "0..1", interactive = true)
char[] password;
  • 通过以下输入,密码字段将被初始化为“123”,而不提示用户输入:--password 123 --user Joe
  • 但是,如果未指定密码,--password --user Joe , 则会提示用户输入密码。

Short (POSIX) Options

class ClusteredShortOptions { 
        
    @Option(names = "-a") boolean aaa;
    @Option(names = "-b") boolean bbb;
    @Option(names = "-c") boolean ccc;
    @Option(names = "-f") String  file;
}

以下命令行参数都是等效的,解析它们会得到相同的结果:

<command> -abcfInputFile.txt
<command> -abcf=InputFile.txt
<command> -abc -f=InputFile.txt
<command> -ab -cf=InputFile.txt
<command> -a -b -c -fInputFile.txt
<command> -a -b -c -f InputFile.txt
<command> -a -b -c -f=InputFile.txt
...

Boolean Options

Boolean Options通常不需要参数:在命令行中指定选项名称就足够了。

class BooleanOptions { 
        
    @Option(names = "-x") boolean x;
}
  • x 的值默认为 false,
  • 如果在命令行上指定了-x,则设置为 true(与默认值相反)。
  • 如果在命令行上多次指定-x,则 x 的值保持为true

Negatable Options-否定选项

@Command(name = "negatable-options-demo")
class NegatableOptionsDemo { 
        
    @Option(names = "--verbose",           negatable = true) boolean verbose;
    @Option(names = "-XX:+PrintGCDetails", negatable = true) boolean printGCDetails;
    @Option(names = "-XX:-UseG1GC",        negatable = true) boolean useG1GC = true;
}

上述示例的使用帮助如下所示:

Usage: negatable-options-demo 
		[--[no-]verbose] 
		[-XX:(+|-)PrintGCDetails]
      	[-XX:(+|-)UseG1GC]
      	
      --[no-]verbose     Show verbose output
      -XX:(+|-)PrintGCDetails Prints GC details
	  -XX:(+|-)UseG1GC   Use G1 algorithm for GC


Positional Parameters

Explicit Index - 显式索引

使用[0,+oo)索引属性来准确指定要捕获的参数。数组或集合字段可以捕获多个值。

class PositionalParameters { 
        
    @Parameters(index = "0")    InetAddress host;
    @Parameters(index = "1")    int port;
    @Parameters(index = "2..*") File[] files;

    @Parameters(hidden = true)  // "hidden": don't show this parameter in usage help message
    List<String> allParameters; // no "index" attribute: captures _all_ arguments
}

testcase

String[] args = { 
         "localhost", "12345", "file1.txt", "file2.txt" };
PositionalParameters params = CommandLine.populateCommand(new PositionalParameters(), args);

assert params.host.getHostName().equals("localhost");
assert params.port == 12345;
assert Arrays.equals(params.files, new File[] { 
        new File("file1.txt"), new File("file2.txt")});

assert params.allParameters.equals(Arrays.asList(args));

Omitting the Index -省略索引

可以省略 index 属性。

  • 对于多值位置参数(数组或集合),省略 index 属性意味着该字段捕获所有位置参数(相当于 index = "0..*")。
  • 对于单值位置参数
    • 在 picocli 4.3 之前,单值位置参数的默认索引也是 index = "0..*",即使只有一个值(通常是第一个参数) 可以被捕获。
    • 从 4.3 版开始,picocli 根据同一命令中定义的其他位置参数自动分配索引。**Automatic Parameter Indexes **

Mixing Options and Positional Parameters

 class Mixed { 
        
    @Parameters
    List<String> positional;

    @Option(names = "-o")
    List<String> options;
}

testcase

 String[] args = { 
         "param0", "-o", "AAA", "param1", "param2", "-o", "BBB", "param3" };
Mixed mixed = new Mixed();
new CommandLine(mixed).parseArgs(args);

assert mixed.positional.equals(Arrays.asList("param0", "param1", "param2", "param3");
assert mixed.options.equals   (Arrays.asList("AAA", "BBB"));

Double dash (–)

当命令行参数之一只是两个破折号而没有附加任何字符 (--) 时,picocli 将所有后续参数解释为Positional Parameters,甚至是与选项名称匹配的参数

class DoubleDashDemo { 
        
    @Option(names = "-v")     boolean verbose;
    @Option(names = "-files") List<String> files;
    @Parameters               List<String> params;
}

testcase

String[] args = { 
         "-v", "--", "-files", "file1", "file2" };
DoubleDashDemo demo = new DoubleDashDemo();
new CommandLine(demo).parseArgs(args);

assert demo.verbose;
assert demo.files == null;
assert demo.params.equals(Arrays.asList("-files", "file1", "file2"));

@-files

长命令行的参数文件

假设有文件:/home/foo/args,内容如下

# This line is a comment and is ignored.
ABC -option=123
'X Y Z'

执行命令: java MyCommand @/home/foo/args
等价于执行:java MyCommand ABC -option=123 "X Y Z"

encoding
若要执行命令: java -DFile.encoding=UTF8 MyCommand ABC -option=123 "X Y Z"
可以通过:

SET JAVA_TOOL_OPTIONS=-Dfile.encoding=UTF8
java MyCommand ABC -option=123 "X Y Z"

@-files Usage Help: showAtFileInUsageHelp

@Command(name = "myapp", showAtFileInUsageHelp = true,
         mixinStandardHelpOptions = true, description = "Example command.")
class MyApp { 
        
    @Parameters(description = "A file.") File file;
}

执行命令结果如下:

Usage: myapp [-hV] [@<filename>...] <file>
Example command.
      [@<filename>...]   One or more argument files containing options.
      <file>             A file.
  -h, --help             Show this help message and exit.
  -V, --version          Print version information and exit.

增加了-h -V选项。



Subcommands

Subcommands复杂的命令行工具,例如著名的 git 工具,有许多子命令(例如,commit、push 等),每个子命令都有自己的一组选项和位置参数。 Picocli 使得使用subcommandssub-subcommands的命令变得非常容易,达到任何深度。

例1

@Command(name = "foo", subcommands = Bar.class)
class Foo implements Callable<Integer> { 
        
    @Option(names = "-x") int x;

    @Override public Integer call() { 
        
        System.out.printf("hi from foo, x=%d%n", x);
        boolean ok = true;
        return ok ? 0 : 1; // exit code
    }

    public static void main(String... args) { 
        
        int exitCode = new CommandLine(new Foo()).execute(args);
        System.exit(exitCode);
    }
}

@Command(name = "bar", description 元器件数据手册IC替代型号,打造电子元器件IC百科大全!
          

相关文章