Apache Commons CLI

Apache Commons プロジェクトの一部として提供されるコマンドライン引数処理ライブラリ。

javaclicommand-lineapacheargument-parsing

フレームワーク

Apache Commons CLI

概要

Apache Commons CLIは、Apache Commons プロジェクトの一部として提供される成熟したコマンドライン引数処理ライブラリです。Apacheソフトウェア財団によって開発・保守されており、エンタープライズ環境での信頼性が高く、多くのApacheプロジェクトで使用されています。豊富な機能と柔軟な設計により、シンプルなCLIから複雑なコマンド構造まで幅広く対応できます。

なぜApache Commons CLIが選ばれるのか:

  • エンタープライズ信頼性: Apacheブランドによる高い信頼性
  • 成熟度: 20年以上の開発・運用実績
  • 豊富な機能: 多様なオプション形式とバリデーション
  • 柔軟性: シンプルから複雑なCLIまで対応
  • 標準化: Apache プロジェクト群での標準採用

詳細

歴史と発展

Apache Commons CLIは2002年頃から開発が開始され、Apache Commons プロジェクトの重要なコンポーネントとして発展しました。Apache Maven、Apache Ant、Apache Tomcatなど多くのApacheプロジェクトで採用されており、エンタープライズJava開発における標準的な選択肢となっています。

エコシステムでの位置づけ

  • Apache エコシステム: Maven、Ant、Tomcat等での採用
  • エンタープライズ: 大企業での標準ライブラリ
  • レガシーシステム: 既存システムでの安定した選択肢
  • 教育機関: Java CLI開発の教材として使用

最新動向(2024-2025年)

  • Java 11+対応: 最新Javaバージョンでの動作保証
  • 継続的メンテナンス: セキュリティ修正と機能改善
  • Maven Central: 安定したリリースサイクル

メリット・デメリット

メリット

  • 高い信頼性: Apache品質保証による安定性
  • 豊富な機能: 多様なオプション形式をサポート
  • エンタープライズ対応: 大規模システムでの実績
  • 長期サポート: Apache財団による継続的サポート
  • ドキュメント: 充実した公式ドキュメント

デメリット

  • 学習コスト: 豊富な機能による複雑さ
  • 冗長性: シンプルな用途には過剰
  • 設定の複雑さ: 詳細な設定が必要な場合がある
  • アノテーション未対応: 宣言的でないプログラマティックAPI

主要リンク

書き方の例

基本的な使用例

import org.apache.commons.cli.*;

public class BasicExample {
    public static void main(String[] args) {
        Options options = new Options();
        
        // オプションの定義
        options.addOption("v", "verbose", false, "詳細出力を有効にする");
        options.addOption("f", "file", true, "処理するファイル名");
        options.addOption("h", "help", false, "ヘルプを表示");
        
        CommandLineParser parser = new DefaultParser();
        HelpFormatter formatter = new HelpFormatter();
        
        try {
            CommandLine cmd = parser.parse(options, args);
            
            if (cmd.hasOption("help")) {
                formatter.printHelp("BasicExample", options);
                return;
            }
            
            if (cmd.hasOption("verbose")) {
                System.out.println("詳細モードが有効です");
            }
            
            if (cmd.hasOption("file")) {
                String fileName = cmd.getOptionValue("file");
                System.out.println("処理ファイル: " + fileName);
            }
            
        } catch (ParseException e) {
            System.err.println("引数解析エラー: " + e.getMessage());
            formatter.printHelp("BasicExample", options);
        }
    }
}

高度なオプション設定

import org.apache.commons.cli.*;

public class AdvancedExample {
    public static void main(String[] args) {
        Options options = new Options();
        
        // 必須オプション
        Option input = Option.builder("i")
            .longOpt("input")
            .hasArg()
            .required()
            .desc("入力ファイル(必須)")
            .build();
        options.addOption(input);
        
        // 複数値を受け取るオプション
        Option files = Option.builder("f")
            .longOpt("files")
            .hasArgs()
            .valueSeparator(',')
            .desc("カンマ区切りのファイルリスト")
            .build();
        options.addOption(files);
        
        // デフォルト値付きオプション
        Option output = Option.builder("o")
            .longOpt("output")
            .hasArg()
            .desc("出力ディレクトリ(デフォルト: current)")
            .build();
        options.addOption(output);
        
        // グループ化されたオプション
        OptionGroup formatGroup = new OptionGroup();
        formatGroup.addOption(new Option("xml", "XML形式で出力"));
        formatGroup.addOption(new Option("json", "JSON形式で出力"));
        formatGroup.addOption(new Option("csv", "CSV形式で出力"));
        formatGroup.setRequired(false);
        options.addOptionGroup(formatGroup);
        
        CommandLineParser parser = new DefaultParser();
        HelpFormatter formatter = new HelpFormatter();
        
        try {
            CommandLine cmd = parser.parse(options, args);
            
            System.out.println("入力ファイル: " + cmd.getOptionValue("input"));
            
            String outputDir = cmd.getOptionValue("output", "current");
            System.out.println("出力ディレクトリ: " + outputDir);
            
            if (cmd.hasOption("files")) {
                String[] fileList = cmd.getOptionValues("files");
                System.out.println("ファイルリスト: " + String.join(", ", fileList));
            }
            
            // フォーマット確認
            if (cmd.hasOption("xml")) {
                System.out.println("出力形式: XML");
            } else if (cmd.hasOption("json")) {
                System.out.println("出力形式: JSON");
            } else if (cmd.hasOption("csv")) {
                System.out.println("出力形式: CSV");
            } else {
                System.out.println("出力形式: デフォルト");
            }
            
        } catch (ParseException e) {
            System.err.println("エラー: " + e.getMessage());
            formatter.printHelp("AdvancedExample", options);
        }
    }
}

サブコマンドの実装例

import org.apache.commons.cli.*;

public class SubCommandExample {
    public static void main(String[] args) {
        if (args.length == 0) {
            printMainHelp();
            return;
        }
        
        String command = args[0];
        String[] subArgs = new String[args.length - 1];
        System.arraycopy(args, 1, subArgs, 0, subArgs.length);
        
        switch (command) {
            case "create":
                handleCreateCommand(subArgs);
                break;
            case "update":
                handleUpdateCommand(subArgs);
                break;
            case "delete":
                handleDeleteCommand(subArgs);
                break;
            case "list":
                handleListCommand(subArgs);
                break;
            default:
                System.err.println("不明なコマンド: " + command);
                printMainHelp();
        }
    }
    
    private static void handleCreateCommand(String[] args) {
        Options options = new Options();
        options.addOption("n", "name", true, "項目名(必須)");
        options.addOption("d", "description", true, "説明");
        options.addOption("t", "type", true, "タイプ");
        options.addOption("h", "help", false, "ヘルプを表示");
        
        CommandLineParser parser = new DefaultParser();
        HelpFormatter formatter = new HelpFormatter();
        
        try {
            CommandLine cmd = parser.parse(options, args);
            
            if (cmd.hasOption("help")) {
                formatter.printHelp("create", options);
                return;
            }
            
            if (!cmd.hasOption("name")) {
                System.err.println("エラー: --name オプションは必須です");
                formatter.printHelp("create", options);
                return;
            }
            
            String name = cmd.getOptionValue("name");
            String description = cmd.getOptionValue("description", "");
            String type = cmd.getOptionValue("type", "default");
            
            System.out.println("項目を作成します:");
            System.out.println("  名前: " + name);
            System.out.println("  説明: " + description);
            System.out.println("  タイプ: " + type);
            
        } catch (ParseException e) {
            System.err.println("引数エラー: " + e.getMessage());
            formatter.printHelp("create", options);
        }
    }
    
    private static void handleUpdateCommand(String[] args) {
        Options options = new Options();
        options.addOption("i", "id", true, "更新する項目のID(必須)");
        options.addOption("n", "name", true, "新しい名前");
        options.addOption("d", "description", true, "新しい説明");
        options.addOption("h", "help", false, "ヘルプを表示");
        
        CommandLineParser parser = new DefaultParser();
        HelpFormatter formatter = new HelpFormatter();
        
        try {
            CommandLine cmd = parser.parse(options, args);
            
            if (cmd.hasOption("help")) {
                formatter.printHelp("update", options);
                return;
            }
            
            if (!cmd.hasOption("id")) {
                System.err.println("エラー: --id オプションは必須です");
                formatter.printHelp("update", options);
                return;
            }
            
            String id = cmd.getOptionValue("id");
            System.out.println("項目 " + id + " を更新します:");
            
            if (cmd.hasOption("name")) {
                System.out.println("  新しい名前: " + cmd.getOptionValue("name"));
            }
            if (cmd.hasOption("description")) {
                System.out.println("  新しい説明: " + cmd.getOptionValue("description"));
            }
            
        } catch (ParseException e) {
            System.err.println("引数エラー: " + e.getMessage());
            formatter.printHelp("update", options);
        }
    }
    
    private static void handleDeleteCommand(String[] args) {
        Options options = new Options();
        options.addOption("i", "id", true, "削除する項目のID(必須)");
        options.addOption("f", "force", false, "確認なしで削除");
        options.addOption("h", "help", false, "ヘルプを表示");
        
        CommandLineParser parser = new DefaultParser();
        HelpFormatter formatter = new HelpFormatter();
        
        try {
            CommandLine cmd = parser.parse(options, args);
            
            if (cmd.hasOption("help")) {
                formatter.printHelp("delete", options);
                return;
            }
            
            if (!cmd.hasOption("id")) {
                System.err.println("エラー: --id オプションは必須です");
                formatter.printHelp("delete", options);
                return;
            }
            
            String id = cmd.getOptionValue("id");
            boolean force = cmd.hasOption("force");
            
            if (force) {
                System.out.println("項目 " + id + " を削除しました");
            } else {
                System.out.println("項目 " + id + " を削除しますか? (確認するには --force を使用)");
            }
            
        } catch (ParseException e) {
            System.err.println("引数エラー: " + e.getMessage());
            formatter.printHelp("delete", options);
        }
    }
    
    private static void handleListCommand(String[] args) {
        Options options = new Options();
        options.addOption("a", "all", false, "すべての項目を表示");
        options.addOption("t", "type", true, "指定タイプの項目のみ表示");
        options.addOption("h", "help", false, "ヘルプを表示");
        
        CommandLineParser parser = new DefaultParser();
        HelpFormatter formatter = new HelpFormatter();
        
        try {
            CommandLine cmd = parser.parse(options, args);
            
            if (cmd.hasOption("help")) {
                formatter.printHelp("list", options);
                return;
            }
            
            System.out.println("項目一覧:");
            
            if (cmd.hasOption("all")) {
                System.out.println("  すべての項目を表示中...");
            } else if (cmd.hasOption("type")) {
                String type = cmd.getOptionValue("type");
                System.out.println("  タイプ '" + type + "' の項目を表示中...");
            } else {
                System.out.println("  標準項目を表示中...");
            }
            
        } catch (ParseException e) {
            System.err.println("引数エラー: " + e.getMessage());
            formatter.printHelp("list", options);
        }
    }
    
    private static void printMainHelp() {
        System.out.println("Usage: SubCommandExample <command> [options]");
        System.out.println();
        System.out.println("Available commands:");
        System.out.println("  create   新しい項目を作成");
        System.out.println("  update   既存の項目を更新");
        System.out.println("  delete   項目を削除");
        System.out.println("  list     項目一覧を表示");
        System.out.println();
        System.out.println("各コマンドの詳細は 'SubCommandExample <command> --help' で確認できます");
    }
}