使用 JCommander 解析命令行参数

news2024/12/23 6:42:04

前言

如果你想构建一个支持命令行参数的程序,那么 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

总体测试

一如既往,文章代码都存放在 Github.com/niumoo/javaNotes.

参考:https://jcommander.org/

本文 Github.com/niumoo/JavaNotes仓库已经收录。
本文原发于网站:https://www.wdbyte.com/tool/jcommander/
我的公众号:使用 JCommander 解析命令行参数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/702378.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【WinRAR技巧】如何合并RAR分卷压缩文件?

很多小伙伴在压缩RAR文件的时候&#xff0c;会选择分卷压缩&#xff0c;便于网上上传、下载或邮件发送。 那如果后续不需要分卷压缩了&#xff0c;如何将RAR分卷压缩文件重新合并成一个文件呢&#xff1f;下面小编来分享一下具体的操作方法。 一般来说&#xff0c;我们都会选…

【C++初阶】C++STL详解(三)—— vector的介绍及使用

​ ​&#x1f4dd;个人主页&#xff1a;Sherry的成长之路 &#x1f3e0;学习社区&#xff1a;Sherry的成长之路&#xff08;个人社区&#xff09; &#x1f4d6;专栏链接&#xff1a;C初阶 &#x1f3af;长路漫漫浩浩&#xff0c;万事皆有期待 上一篇博客&#xff1a;【C初阶】…

(三)灌溉系统WIFI通信部分

ESP8266 ESP8266S烧录器&#xff1a;CH430C arduino离线配置esp8266参考&#xff1a;参考文章 灯光闪烁就是烧录成功 ESP8266调试入门&#xff1a;参考文章 ESP8266调试&#xff1a;参考文章 人麻了已经&#xff0c;尝试半天了&#xff0c;AT指令没回应&#xff0c;尝试刷固…

Feed流实现

关注推送 关注推送也称为Feed流(直译为投喂)&#xff0c;为用户持续的提供“沉浸式”的体验&#xff0c;通过无限下拉刷新获取新的信息(如&#xff0c;短视频、博客等)。 获取信息的两种模式 传统模式&#xff1a;需要用户自己去根据所需去查询内容。 Feed模式&#xff1a;…

八、Docker安装MySQL主从

学习参考&#xff1a;尚硅谷Docker实战教程、Docker官网、其他优秀博客(参考过的在文章最后列出) 目录 前言一、pull一个mysql镜像二、主服务器master配置2.1 新建主服务器容器实例2.2 配置master的my.cnf2.3 重启master容器实例并验证2.4 master容器实例内创建数据同步用户 三…

JVM知识扫盲篇

JVM扫盲 一&#xff1a;故事背景二&#xff1a;知识点主要构成2.1 JVM为什么能跨平台2.2 JVM整体结构2.1 类加载子系统2.1.1 概述2.1.2 具体类加载器2.1.3 双亲委派机制2.1.4 Tomcat为什么要自定义类加载器 2.2 运行时数据区2.2.1 整体概念2.2.2 程序计数器的作用2.2.3 虚拟机栈…

MySQL - 数据库级别的外键

1. 外键 FOREIGN KEY (了解) 测试数据 &#xff1a; 学生表 CREATE TABLE IF NOT EXISTS student (id INT(4) NOT NULL AUTO_INCREMENT COMMENT 学号,name VARCHAR(30) NOT NULL DEFAULT 匿名 COMMENT 姓名,pwd VARCHAR(20) NOT NULL DEFAULT 123456 COMMENT 密码,sex VARC…

在 Mac 上安装 K8S

本篇文章将介绍如何在 Mac 上使用 minikube 搭建单机版的 Kubernetes。 安装步骤 安装 Docker 安装 docker 主要是用于提供容器引擎。直接下载安装即可。 下载地址 安装 Kubectl 推荐使用 home brew 安装 brew install kubectl可以使用下面的命令查看是否已经安装完毕 …

MAYA粒子圈

无法修改 完成一圈的时间

【C51】基于51单片机的自动输液监控系统设计与实现

摘 要 随着科技进步&#xff0c;我国的医疗设施不断完善&#xff0c;逐渐达到现代化水平。在当今的医疗环境下&#xff0c;病患更关心自己是否能够及时进行有效的治疗&#xff0c;医护人员对患者进行输液过程的全程监控。医生治疗的效果明显提高&#xff0c;不仅节约大量的时间…

Linux: 进程管理

一&#xff0c;快速上手&#xff0c;结束一个失控的进程 在主目录中&#xff0c;用文本编辑器创建一个文本文件badpro&#xff0c;如下&#xff1a; #! /bin/bash while echo "Im making files!!" domkdir adircd adirtouch afilesleep 2s done将该文件设定为可执行…

Leetcode 刷题 动态规划 子序列问题

300. 最长递增子序列 首先明确什么是子序列 子序列是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序 不一定要连续 可以删除部分元素 但是要保证相对顺序 1. dp[i]的定义 dp[i]表示i之前包括i的以nums[i]结尾的最长…

Hutool 30

Hutool是一个Java工具包&#xff0c;提供了丰富的工具类库和简化开发的工具方法。它的目标是提供一套丰富、实用、高效和易用的Java工具类&#xff0c;以提升开发者的开发效率和开发质量。以下是Hutool的一些主要特点和功能模块&#xff1a; 常用工具类&#xff1a;Hutool提供了…

【Linux | Shell命令】bash shell 进程、磁盘、排序命令

目录 一、概述二、进程相关命令2.1 ps 命令 三四五 一、概述 上篇文章 bash shell 基础命令 中&#xff0c;介绍了一些与目录、文件相关的 shell 命令&#xff0c;本文继续介绍其他与进程、磁盘、排序、归档相关的命令&#xff0c;读者可以在自己的Linux系统下&#xff0c;实操…

【AI赋能未来】一文带你了解生成对抗网络(GAN)

自我介绍⛵ &#x1f4e3;我是秋说&#xff0c;研究人工智能、大数据等前沿技术&#xff0c;传递Java、Python等语言知识。 &#x1f649;主页链接&#xff1a;秋说的博客 &#x1f4c6; 学习专栏推荐&#xff1a;MySQL进阶之路、C刷题集、网络安全攻防姿势总结 欢迎点赞 &…

shiro框架 02使用shiro进行用户的认证

01.shiro框架的具体业务&#xff1a; 具体的内部结构: Subject&#xff08;主体&#xff09;:与软件交互的一个特定的实体&#xff08;用户、第三方服务等&#xff09;。 SecurityManager(安全管理器) :Shiro 的核心&#xff0c;用来协调管理组件工作。 其中的&#xff1a; Au…

小研究 - Java 指针分析综述(二)

近年来静态程序分析已成为保障软件可靠性、安全性和高效性的关键技术之一. 指针分析作为基 础程序分析技术为静态程序分析提供关于程序的一系列基础信息&#xff0c;例如程序任意变量的指向关系、变量 间的别名关系、程序调用图、堆对象的可达性等. 介绍了 Java 指针分析的重要…

亚马逊云科技积极探索多样化生态合作模式,助力实现可持续发展愿景

2023年6月26日&#xff0c;亚马逊云科技中国峰会在上海世博中心盛大开幕&#xff01;以主题“因构建 而可见”为大家拉开帷幕。当前&#xff0c;越来越多的企业客户&#xff0c;以及当地政府监管机构对企业的要求&#xff0c;都需要企业告知碳足迹&#xff0c;亚马逊云科技提供…

优盘数据恢复怎么做?3个方法分享!

我的优盘里保存了很多有纪念意义的照片&#xff0c;但是刚刚将u盘插入电脑后&#xff0c;发现有些照片已经损坏了。我想将优盘里的数据恢复&#xff0c;有什么靠谱的方法吗&#xff1f;给我推荐一下吧&#xff01; 优盘是一种便携式存储设备&#xff0c;常用于存储和传输数据。…