Java使用JCommander实现解析命令行参数

 更新时间:2023年06月30日 09:44:30   作者:程序猿阿朗  
jcommander 是一个只有几十 kb 的 Java 命令行参数解析工具,可以通过注解的方式快速实现命令行参数解析,本文就来和大家介绍一下JCommander是如何解析命令行参数吧

前言

如果你想构建一个支持命令行参数的程序,那么 jcommander 非常适合你,jcommander 是一个只有几十 kb 的 Java 命令行参数解析工具,可以通过注解的方式快速实现命令行参数解析。

这篇教程会通过介绍 jcommadner ,快速的创建一个命令行程序,最后支持的命令参数功能如下图。

这个命令行工具仿照 git 操作命令,主要提供了如下功能命令:

  • 1. git-app.jar -help 查看命令帮助信息。
  • 2. git-app.jar -version 查看当前版本号。
  • 3. git-app.jar clone http://xxxx 通过 URL 克隆一个仓库。
  • 4. git-app.jar add file1 file2 暂存 file1 文件 file2 文件。
  • 5. git-app.jar commit -m "注释" 提交并添加注释。

jcommander 引入

截止文章编写时间,最新版本如下:

<!-- https://mvnrepository.com/artifact/com.beust/jcommander -->
<dependency>
    <groupId>com.beust</groupId>
    <artifactId>jcommander</artifactId>
    <version>1.82</version>
</dependency>

jcommander 参数绑定

命令行解析中,参数解析与绑定是最实用的一个场景,jcommander 使用 Parameter 注解进行参数绑定。我们定义一个 GitCommandOptions.java 类来测试参数绑定。

package com.wdbyte.jcommander.v1;
import com.beust.jcommander.Parameter;
/**
 * @author https://www.wdbyte.com
 */
public class GitCommandOptions {
    @Parameter(names = {"clone"},
        description = "克隆远程仓库数据")
    private String cloneUrl;
    public String getCloneUrl() {
        return cloneUrl;
    }
}

使用 jcommander 结合 GitCommandOptions 来解析参数。

package com.wdbyte.jcommander.v1;
import com.beust.jcommander.JCommander;
/**
 * @author https://www.wdbyte.com
 */
public class GitApp {
    public static void main(String[] args) {
            // args = new String[]{"clone","http://www.wdbyte.com/test.git"};
        GitCommandOptions gitCommandOptions = new GitCommandOptions();
        JCommander commander = JCommander.newBuilder()
            .addObject(gitCommandOptions)
            .build();
        commander.parse(args);
        System.out.println("clone " + gitCommandOptions.getCloneUrl());
    }
}

打包后可以执行命令参数:

$ java -jar git-app.jar clone http://www.wdbyte.com/test.git
clone http://www.wdbyte.com/test.git

这里是一个字符串参数,需要在命令中输出参数值,对于 boolean 类型的参数,不需要传值,有命令即为 true 值。

参数名称

@Parameter 注解中的 names 属性可以定义参数的名称。且可以指定多个参数名称,让我再添加 version 参数和 help 参数,同时设置参数别名。这两个参数是 boolean 类型。

@Parameter(names = {"help", "-help", "-h"},
    description = "查看帮助信息",
    help = true)
private boolean help;
@Parameter(names = {"version", "-version", "-v"},
    description = "显示当前版本号")
private boolean version = false;

参数限制

clone 参数可以接受一个要克隆的 URL 链接,但是正常情况下只需要一个 URL 链接。可以通过 arity = 1 进行限制。

@Parameter(names = {"clone"},
    description = "克隆远程仓库数据",
    arity = 1)
private String cloneUrl;

帮助信息

使用 usage() 参数可以打印命令帮助信息。

GitCommandOptions gitCommandOptions = new GitCommandOptions();
JCommander commander = JCommander.newBuilder()
    .addObject(gitCommandOptions)
    .build();
commander.parse(args);
// 打印帮助信息
commander.usage();

运行输出帮助信息:

$ java -jar git-app.jar
Usage: <main class> [options]
  Options:
    clone
      克隆远程仓库数据
    help, -help, -h
      查看帮助信息
    version, -version, -v
      显示当前版本号
      Default: false

虽然正确的输出了帮助信息,但是其中有 main class 这段,是因为我们没有指定项目名称,我们指定项目名称为 git-app

JCommander commander = JCommander.newBuilder()
            .programName("git-app")
            .addObject(gitCommandOptions)
            .build();

参数排序

在帮助信息中,如果想要自定义参数顺序,可以通过 order = 来排序,数字越小越靠前。

@Parameter(names = {"version", "-version", "-v"},
    description = "显示当前版本号",
    order = 2)
private boolean version = false;

参数绑定完整测试

package com.wdbyte.jcommander.v2;
import com.beust.jcommander.Parameter;
/**
 * @author https://www.wdbyte.com
 */
public class GitCommandOptions {
    @Parameter(names = {"help", "-help", "-h"},
        description = "查看帮助信息",
        order = 1,
        help = true)
    private boolean help;
    @Parameter(names = {"clone"},
        description = "克隆远程仓库数据",
        order = 3,
        arity = 1)
    private String cloneUrl;
    @Parameter(names = {"version", "-version", "-v"},
        description = "显示当前版本号",
        order = 2)
    private boolean version = false;
    //...get method
}

GitApp.java

package com.wdbyte.jcommander.v2;
import com.beust.jcommander.JCommander;
public class GitApp {
    public static void main(String[] args) {
        GitCommandOptions gitCommandOptions = new GitCommandOptions();
        JCommander commander = JCommander.newBuilder()
            .programName("git-app")
            .addObject(gitCommandOptions)
            .build();
        commander.parse(args);
        // 打印帮助信息
        if (gitCommandOptions.isHelp()) {
            commander.usage();
            return;
        }
        if (gitCommandOptions.isVersion()) {
            System.out.println("git version 2.24.3 (Apple Git-128)");
            return;
        }
        if (gitCommandOptions.getCloneUrl() != null) {
            System.out.println("clone " + gitCommandOptions.getCloneUrl());
        }
    }
}

运行测试:

jcommander 参数验证

在上面的例子中, 假设 clone 命令传入的参数必须是一个 URL,那么我们就要进行参数验证,jcommander 也提供了特有的参数验证方式。

1. 编写参数验证类,需要实现 IParameterValidator 接口。

package com.wdbyte.jcommander.v3;
import java.net.MalformedURLException;
import java.net.URL;
import com.beust.jcommander.IParameterValidator;
import com.beust.jcommander.ParameterException;
/**
 * @author https://www.wdbyte.com
 */
public class UrlParameterValidator implements IParameterValidator {
    @Override
    public void validate(String key, String value) throws ParameterException {
        try {
            new URL(value);
        } catch (MalformedURLException e) {
            throw new ParameterException("参数 " + key + " 的值必须是 URL 格式");
        }
    }
}

2. clone 参数指定验证类。

@Parameter(names = {"clone"},
    description = "克隆远程仓库数据",
    validateWith = UrlParameterValidator.class,
    order = 3,
    arity = 1)
private String cloneUrl;

运行测试:

$ java -jar git-app.jar clone https://www.wdbyte.com/test.git
clone https://www.wdbyte.com/test.git

$ java -jar git-app.jar clone test.git
Exception in thread "main" com.beust.jcommander.ParameterException: 参数 clone 的值必须是 URL 格式
    at com.wdbyte.jcommander.v3.UrlParameterValidator.validate(UrlParameterValidator.java:19)
    at com.beust.jcommander.ParameterDescription.validateParameter(ParameterDescription.java:377)
    at com.beust.jcommander.ParameterDescription.validateParameter(ParameterDescription.java:344)

jcommander 子命令

在使用 git 时,我们经常会使用下面两个命令。

1. git add file1 file2 暂存 file1 文件 file2 文件。

2. git commit -m "注释" 提交并添加注释。

什么是子命令

这是一种很常见的操作,git commit 除了可以跟 -m 子参数外,还可以跟各种参数,通过 git 帮助文档可以看到。

git commit [-a | --interactive | --patch] [-s] [-v] [-u<mode>] [--amend]
           [--dry-run] [(-c | -C | --fixup | --squash) <commit>]
           [-F <file> | -m <msg>] [--reset-author] [--allow-empty]
           [--allow-empty-message] [--no-verify] [-e] [--author=<author>]
           [--date=<date>] [--cleanup=<mode>] [--[no-]status]
           [-i | -o] [-S[<keyid>]] [--] [<file>...]

这种有子参数的情况,我们可以称 commit 为 git 的一个子命令,使用 jcommander 如何配置子命令呢?

jcommander 子命令实现

我们新增子命令对应的参数类 GitCommandCommit.java.

package com.wdbyte.jcommander;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
/**
 * git commit -m "desc"
 * @author https://www.wdbyte.com
 */
@Parameters(commandDescription = "提交文件", commandNames = "commit")
public class GitCommandCommit {
    public static final String COMMAND = "commit";
    @Parameter(names = {"-comment", "-m"},
        description = "请输入注释",
        arity = 1,
        required = true)
    private String comment;
    public String getComment() {
        return comment;
    }
}

代码中使用 @Parameters 注解指定了子命令为 commit,同时使用 @Paramete 注解指定子参数 -m,同时 -m 参数是必须的,使用属性 required = true 来指定。

使用 GitCommandCommit:

使用 addCommand 添加 Commit 命令参数类。

GitCommandOptions gitCommandOptions = new GitCommandOptions();
GitCommandCommit commandCommit = new GitCommandCommit();
JCommander commander = JCommander.newBuilder()
    .programName("git-app")
    .addObject(gitCommandOptions)
    .addCommand(commandCommit)
    .build();
commander.parse(args);
String parsedCommand = commander.getParsedCommand();
if ("commit".equals(parsedCommand)) {
    System.out.println(commandCommit.getComment());
}

运行测试:

$ java -jar git-app.jar commit -m '注释一下'
注释一下

同上,我们可以添加 add 命令对应的参数类:GitCommandAdd.java. 这次我们定义一个 List 类型参数,但是不在属性上指定子参数名称。

package com.wdbyte.jcommander.v5;
import java.util.List;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
/**
 * git add file1 file2
 *
 * @author https://www.wdbyte.com
 */
@Parameters(commandDescription = "暂存文件", commandNames = "add", separators = " ")
public class GitCommandAdd {
    public static final String COMMAND = "add";
    @Parameter(description = "暂存文件列表")
    private List<String> files;
    public List<String> getFiles() {
        return files;
    }
}

同样添加到子命令:

JCommander commander = JCommander.newBuilder()
    .programName("git-app")
    .addObject(gitCommandOptions)
    .addCommand(commandCommit)
    .addCommand(commandAdd)
    .build();
commander.parse(args);
if ("add".equals(parsedCommand)) {
    for (String file : commandAdd.getFiles()) {
        System.out.println("暂存文件:" + file);
    }
}

运行测试:

$ java -jar git-app.jar add file1.txt file2.txt
暂存文件:file1.txt
暂存文件:file2.txt

jcommander 参数转换

在上面的 GitCommandAdd 代码中,add 命令传入的都是文件路径,现在是使用 List<String> 来接收入参,通常情况想我们可能需要直接转换成方便操作的类型,如 File 或者 Path,这该如何方面的转换呢,jcommander 也提供了方便转换类。

首先编写一个转换类 FilePathConverter 用于把入参转换成 Path 类,同时校验文件是否存在

package com.wdbyte.jcommander;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import com.beust.jcommander.IStringConverter;
import com.beust.jcommander.ParameterException;
/**
 *
 * @author https://www.wdbyte.com
 */
public class FilePathConverter implements IStringConverter<Path> {
    @Override
    public Path convert(String filePath) {
        Path path = Paths.get(filePath);
        if (Files.exists(path)) {
            return path;
        }
        throw new ParameterException(String.format("文件不存在,path:%s", filePath));
    }
}

通过注解指定转换类:

@Parameter(description = "暂存文件列表", converter = FilePathConverter.class)
private List<Path> files;

打包测试:

$ java -jar git-app.jar add file1 file2
文件不存在,path:file1

$ ls -l
total 12448
drwxr-xr-x  2 darcy  staff    64B  6 15 21:10 archive-tmp
drwxr-xr-x  3 darcy  staff    96B  6 15 21:10 classes
drwxr-xr-x  3 darcy  staff    96B  6 15 21:10 generated-sources
-rw-r--r--  1 darcy  staff   5.6M  6 16 20:44 git-app.jar

$ git-app.jar git-app.jar
暂存文件:git-app.jar

总体测试

以上就是Java使用JCommander实现解析命令行参数的详细内容,更多关于Java JCommander解析命令行参数的资料请关注脚本之家其它相关文章!

相关文章

  • Java经典算法汇总之冒泡排序

    Java经典算法汇总之冒泡排序

    冒泡排序基本思想:在要排序的一组数中,对当前还未排好序的范围内的全部数,自上而下对相邻的两个数依次进行比较和调整,让较大的数往下沉,较小的往上冒。即:每当两相邻的数比较后发现它们的排序与排序要求相反时,就将它们互换。
    2016-04-04
  • 手把手教你写Maven的archetype项目脚手架

    手把手教你写Maven的archetype项目脚手架

    本文主要介绍了Maven的archetype项目脚手架,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • Java.SE数组的一些常见练习题

    Java.SE数组的一些常见练习题

    数组可以看成是相同类型元素的一个集合,在内存中是一段连续的空间,这篇文章主要给大家介绍了关于Java.SE数组的一些常见练习题,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2024-02-02
  • 关于Spring Cloud 本地属性覆盖的问题

    关于Spring Cloud 本地属性覆盖的问题

    这篇文章主要介绍了关于Spring Cloud 本地属性覆盖的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-03-03
  • Kotlin中常见的List使用示例教程

    Kotlin中常见的List使用示例教程

    filter 就像其本意一样,可以通过 filter 对 Kotlin list 进行过滤,本文重点给大家介绍Kotlin中常见的List使用,感兴趣的朋友一起看看吧
    2023-11-11
  • Hibernate validator使用以及自定义校验器注解

    Hibernate validator使用以及自定义校验器注解

    这篇文章主要介绍了Hibernate validator使用以及自定义校验器注解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-01-01
  • Hibernate传入Java对象创建动态表并录入数据

    Hibernate传入Java对象创建动态表并录入数据

    这篇文章主要介绍了Hibernate传入Java对象创建动态表并录入数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-10-10
  • Java中关键字final finally finalize的区别介绍

    Java中关键字final finally finalize的区别介绍

    这篇文章主要给大家分享的是 Java中final,finally,finalize 到底有什么区别,文章围绕final,finally,finalize的相关资料展开详细内容,具有一定的参考的价值,需要的朋友可以参考一下
    2022-04-04
  • java按钮控件数组实现计算器界面示例分享

    java按钮控件数组实现计算器界面示例分享

    本文主要介绍了JAVA通过按钮数组来管理界面中的所有按钮控件,从而使用最少的代码实现模拟的计算器界面
    2014-02-02
  • 关于java数组与字符串相互转换的问题

    关于java数组与字符串相互转换的问题

    这篇文章主要介绍了java数组与字符串相互转换的问题,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2021-10-10

最新评论