当前位置: 首页 > 知识库问答 >
问题:

带有Apache Commons CLI的两个独家选项组

夏法
2023-03-14

我正在构建一个命令行Java应用程序,在使用Apache Commons CLI解析命令行参数时遇到问题。

我试图讲述我的场景,其中我需要有两个独占的命令行参数组,分别具有长(-abc)和短(-a)参数。

用例1

  • 短params:-d oracle-j jdbc: oracle:薄:@//host: port/数据库
  • 相同,但与长params:-方言oracle-jdbcUrl jdbc: oracle:薄:@//host: port/数据库

用例2:

  • 短参数:-d oracle-h host-p 1521-s database-U user-p pwd
  • 相同但有长参数:-方言oracle-主机主机主机-端口1521-sid数据库-用户-密码pwd

因此,我创建了两个带有适当的选项的选项组

OptionGroup jdbcUrlGroup = new OptionGroup();
jdbcUrlGroup.setRequired(true);
jdbcUrlGroup.addOption(jdbcUrl);

第二组:

OptionGroup customConfigurationGroup = new OptionGroup();
customConfigurationGroup.setRequired(true);
customConfigurationGroup.addOption(host);
customConfigurationGroup.addOption(port);
customConfigurationGroup.addOption(sid);
customConfigurationGroup.addOption(user);
customConfigurationGroup.addOption(password);

然后我用这种方式构建选项对象:

Options options = new Options();
options.addOptionGroup(jdbcUrlGroup);
options.addOptionGroup(customConfigurationGroup);
options.addOption(dialect);

但这并不起作用,因为它期望定义这两个组。

方言选项是这样定义的:

Option dialect = Option
        .builder("d")
        .longOpt("dialect")
        .required(false)
        .hasArg()
        .argName("DIALECT")
        .desc("supported SQL dialects: oracle. Default value: oracle")
        .build();

除了这个属性之外,其他强制Option定义看起来类似:

.required(true)

结果:

  • -d oracle:缺少必需的选项:[-j…],[-h…,-p…,-s…,-U…,-p…]
  • -d oracle-jdbcUrl xxx:缺少必需的选项:[-h…,-p…,-s…,-U…,-p…]
  • -d oracle-h yyy:缺少必需的选项:[-j…]

但是我想要的是以下内容:如果提供了JDBC URL,那么就不需要主机、端口等参数,或者相反。


共有1个答案

齐浩淼
2023-03-14

我认为是时候忘记Apache Commons CLI并将其标记为不推荐使用的库了。好的,如果您只有几个命令行参数,那么您可以使用它,否则最好不要使用。事实上,这个Apache项目最近(2019年2月17日)进行了更新,但仍然缺少许多功能,使用Apache Commons CLI库有点痛苦。

picocli项目看起来更适合解析命令行参数。这是一个非常直观的库,易于使用,并有一个很好的和全面的文档。我认为,一个拥有完美文档的中档工具比一个没有任何文档的闪亮项目要好。

无论如何picocli是一个非常好的库与完美的留档,所以我给双加加到它:)

这就是我如何用picocli覆盖我的用例:

import picocli.CommandLine;
import picocli.CommandLine.ArgGroup;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;

@Command(name = "SqlRunner",
        sortOptions = false,
        usageHelpWidth = 100,
        description = "SQL command line tool. It executes the given SQL and show the result on the standard output.\n",
        parameterListHeading = "General options:\n",
        footerHeading = "\nPlease report issues at arnold.somogyi@gmail.com.",
        footer = "\nDocumentation, source code: https://github.com/zappee/sql-runner.git")
public class SqlRunner implements Runnable {

    /**
     * Definition of the general command line options.
     */
    @Option(names = {"-?", "--help"}, usageHelp = true, description = "Display this help and exit.")
    private boolean help;

    @Option(names = {"-d", "--dialect"}, defaultValue = "oracle", showDefaultValue = CommandLine.Help.Visibility.ALWAYS, description = "Supported SQL dialects: oracle.")
    private static String dialect;

    @ArgGroup(exclusive = true, multiplicity = "1", heading = "\nProvide a JDBC URL:\n")
    MainArgGroup mainArgGroup;

    /**
     * Two exclusive parameter groups:
     *    (1) JDBC URL parameter
     *    (2) Custom connection parameters
     */
    static class MainArgGroup {
        /**
         * JDBC URL option (only one parameter).
         */
        @Option(names = {"-j", "--jdbcUrl"}, arity = "1", description = "JDBC URL, example: jdbc:oracle:<drivertype>:@//<host>:<port>/<database>.")
        private static String jdbcUrl;

        /**
         * Custom connection parameter group.
         */
        @ArgGroup(exclusive = false, multiplicity = "1", heading = "\nCustom configuration:\n")
        CustomConfigurationGroup customConfigurationGroup;
    }

    /**
     * Definition of the SQL which will be executed.
     */
    @Parameters(index = "0", arity = "1", description = "SQL to be executed. Example: 'select 1 from dual'")
    String sql;

    /**
     * Custom connection parameters.
     */
    static class CustomConfigurationGroup {
        @Option(names = {"-h", "--host"}, required = true, description = "Name of the database server.")
        private static String host;

        @Option(names = {"-p", "--port"}, required = true, description = "Number of the port where the server listens for requests.")
        private static String port;

        @Option(names = {"-s", "--sid"}, required = true, description = "Name of the particular database on the server. Also known as the SID in Oracle terminology.")
        private static String sid;

        @Option(names = {"-U", "--user"}, required = true, description = "Name for the login.")
        private static String user;

        @Option(names = {"-P", "--password"}, required = true, description = "Password for the connecting user.")
        private static String password;
    }

    /**
     * The entry point of the executable JAR.
     *
     * @param args command line parameters
     */
    public static void main(String[] args) {
        CommandLine cmd = new CommandLine(new SqlRunner());
        int exitCode = cmd.execute(args);
        System.exit(exitCode);
    }

    /**
     * It is used to create a thread.
     */
    @Override
    public void run() {
        int exitCode = 0; //executeMyStaff();
        System.exit(exitCode);
    }
}

生成的帮助是这样的:

$ java -jar target/sql-runner-1.0-shaded.jar --help
Usage: SqlRunner [-?] [-d=<dialect>] (-j=<jdbcUrl> | (-h=<host> -p=<port> -s=<sid> -U=<user>
                 -P=<password>)) <sql>
SQL command line tool. It executes the given SQL and show the result on the standard output.

General settings:
      <sql>                 SQL to be executed. Example: 'select 1 from dual'
  -?, --help                Display this help and exit.
  -d, --dialect=<dialect>   Supported SQL dialects: oracle.
                              Default: oracle

Custom configuration:
  -h, --host=<host>         Name of the database server.
  -p, --port=<port>         Number of the port where the server listens for requests.
  -s, --sid=<sid>           Name of the particular database on the server. Also known as the SID in
                              Oracle terminology.
  -U, --user=<user>         Name for the login.
  -P, --password=<password> Password for the connecting user.

Provide a JDBC URL:
  -j, --jdbcUrl=<jdbcUrl>   JDBC URL, example: jdbc:oracle:<drivertype>:@//<host>:<port>/<database>.

Please report issues at arnold.somogyi@gmail.com.
Documentation, source code: https://github.com/zappee/sql-runner.git

这种外观比Apache CLI生成的帮助要好得多。

 类似资料:
  • 问题内容: 我有一堆选择列表,我正在尝试向它们添加“无”和标题选项。代码如下所示: 目前,我无法将它们添加到数据中,因此我试图找到一种方法来使其正常工作。当我第一次加载它们时,“ none”选项不存在。标题在那里并且可以按预期工作,但是似乎我无法在此选择列表中添加两个空白条目。 最简单的方法是将“ none”选项添加到数据中,但这对我来说是不可能的。有没有实现我想要的正确方法? 问题答案: 没错,

  • 我有一个数据项目和UI项目。这两个项目都是Spring Boot应用程序。两个项目都有相同的根包(com.myorg),其中一个主类用注释。 UI项目的主类是: UI项目通过以下Gradle依赖项依赖于数据项目: 如果我运行UI应用程序,它将毫无问题地运行。但是,如果我在UI应用程序中运行集成测试,如下所示: 在数据项目的主类中,如果我将替换为 我在尝试运行其集成测试时遇到以下初始化错误: 例如,

  • 1-4:玩家从1-6随机向前移动 5:玩家从4-11向前移动一个随机量(随机8+4) 6:玩家移动到另一个玩家所在的位置(见下文) 我是新的代码编写(这是我的第四个程序编写),并没有广泛的知识知道什么是错误的。代码不需要熟练地完成,我只想让它正常工作。我们非常感谢您的帮助。 }

  • 我在我的项目中包含了2个BC JAR:bcpkix-jdk15on-1.47.jar和bcprov-jdk15on-157.jar。 作为代码中的第一行,我添加了: 行发生异常: 有没有什么方法可以让我定期包括这两个BouncyCastle罐子?

  • 在客户端,我被迫使用socketio,因为浏览器支持的WebSocket不能与flask-socketio一起工作。总是这样,还是我做错了什么(这与问题2有关)。 到目前为止,我成功地在Flask调试模式下运行了Flask-socketio(python my_flask_source.py)。我阅读了Flask-socketio文档,了解到此模式不支持Websockets,只支持长轮询。事实上,