#author("2020-09-22T02:27:50+00:00","","")
#author("2020-12-06T07:56:09+00:00","","")
// 下階層用テンプレート
#topicpath
----
//ここにコンテンツを記述します。

#contents

コマンドライン引数を制御するライブラリargs4j ( http://args4j.kohsuke.org/ ) を使ってみます。
Javaのコマンドライン引数ってチェックするのとかなにげにメンドクサイですが、このライブラリを使うことで
必須チェックなどの自動化、args[i] の値をフィールドに自動でセット、usageの表示、 -u userid -p password みたいな指定を可能に、などをやってくれます。

Jenkinsの内部で Jenkins CLI でも使われている便利なライブラリです。

***インストール [#wd4914f6]
Mavenのpomだけ示しときますが、
 <dependency>
   <groupId>args4j</groupId>
     <artifactId>args4j</artifactId>
     <version>2.33</version>
 </dependency>
を追加しましょう


***やってみる [#m601e54d]
たとえばこんな引数を持つ、コマンドラインプログラムがあったとします。パラメタに
  -U url [-p password] [-u userid]
みたいなパラメタをとるケースを考えます。ちなみにこの意味は
 -U url は必須
 -p password はオプション
 -u userid もオプション
という意味です。


 import org.kohsuke.args4j.Argument;
 import org.kohsuke.args4j.Option; 
 
 public class ProgramA {
     // こういうAnnotationをつける。nameはパラメタ名、aliasesは別名(の配列)、
     // metaVarはusageに表示される文字、requiredは必須かどうか、usageは説明
     @Option(name = "-U", aliases = {"--url" }, metaVar = "url", required = true, usage = "URL")
     private static String url;
 
     @Option(name = "-u", metaVar = "userid", usage = "Userid")
     private static String userid;
 
     @Option(name = "-p", metaVar = "password", usage = "Password")
     private static String password;
 
     // とりあえずは値を表示するだけ
     public void execute() {
         System.out.printf("url = %s \n", url);
         System.out.printf("userid = %s \n", userid);
         System.out.printf("password = %s \n", password);
      }
 }
あらかじめこのようにパラメタにAnnotationをつけておきます。このプログラムを呼び出すクラスは下記の通り:

 import org.kohsuke.args4j.CmdLineException;
 import org.kohsuke.args4j.CmdLineParser;
  
 public class BatchMain {
      public static void main(String[] args) {
         ProgramA main = new ProgramA();
         CmdLineParser parser = new CmdLineParser(main);
         try {
             parser.parseArgument(args);
         } catch (CmdLineException e) {
             System.out.println("usage:");
             parser.printSingleLineUsage(System.out);
             System.out.println();
             parser.printUsage(System.out);
             return;
         }
         main.execute();
     }
 }

こんだけです。CmdLineParserをかませるだけで、一通りのチェック処理とフィールドへの値のセット、usageの文字列構築などをやってくれます。必須パラメタなどがないと例外が発生し、

parser.printSingleLineUsage(System.out); だと
  -U (--url) url [-p password] [-u userid]
と始めにしめしたusageが表示され、((--urlというaliasだけちょっと違うけど))


parser.printUsage(System.out); だと
 -U (--url) url : URL
 -p password    : Password
 -u userid      : Userid

と複数行に表示されます。なかなか便利ですね。

*** 普通のパラメタをつかう [#i1ef51da]
usage:
 [param1] [others ...] -U (--url) url [-p password] [-u userid]
こんな感じのパラメタをとるケースを考えます。 -U 値 とかではない普通の引数指定ですね。0番目の引数は param1に 1..n番目の引数はothersに、それ以外は今まで通り、なんて指定です。

クラスに下記の通り@Argument を追加します。
 public class ProgramA {
 
     @Option(name = "-U", aliases = {"--url" }, metaVar = "url", required = true, usage = "URL")
     private static String url;
 
     @Option(name = "-u", metaVar = "userid", usage = "Userid")
     private static String userid;
 
     @Option(name = "-p", metaVar = "password", usage = "Password")
     private static String password;
 
     // 普通の引数が入る。
     @Argument(index = 0, metaVar = "param1", required = false, usage = "Param1")
     private static String param1;
 
     // フィールドが配列なので1...n番目の引数が入る
     @Argument(index = 1, metaVar = "others", required = false, usage = "Others ...")
     private static String[] others;
 
     public void execute() {
         System.out.printf("url = %s \n", url);
         System.out.printf("userid = %s \n", userid);
         System.out.printf("password = %s \n", password);
         System.out.printf("param1 = %s \n", param1);
         if (others != null) {
             for (int i = 0; i < others.length; i++) {
                 String other = others[i];
                 System.out.printf("others[%d] = %s \n", i, other);
             }
         }
     }
 }

これでOKです。usageでは
 [param1] [others ...] -U (--url) url [-p password] [-u userid]
と出ますが、たとえば
 aaa  -U http://www.masatom.in/  bbb  -u userA   ccc
などとわりとグッチャグチャに指定しても、
 url = http://www.masatom.in/ 
 userid = userA 
 password = null 
 param1 = aaa 
 others[0] = bbb 
 others[1] = ccc 
などとちゃんと処理してくれました。かなりステキです。

***pom.xml について [#n618a2c3]
蛇足ですがこういうバッチプログラムを実行するのにMavenが実行可能jarを作成してくれるとイイですよね。下記のpom.xmlを使って mvn clean package でjarを作成することで

 java -jar target/Args4jSample-0.0.1-jar-with-dependencies.jar 
   aaa -U http://www.masatom.in/  bbb -u userA   ccc
などと実行可能になります。


 <?xml version="1.0" encoding="UTF-8"?>
 <project xmlns="http://maven.apache.org/POM/4.0.0" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
  http://maven.apache.org/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>Args4jSample</groupId>
   <artifactId>Args4jSample</artifactId>
   <version>0.0.1</version>
 
   <build>
     <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-jar-plugin</artifactId>
         <version>2.2</version>
       </plugin>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-assembly-plugin</artifactId>
         <configuration>
           <archive>
             <manifest>
               <mainClass>batch.BatchMain</mainClass>
             </manifest>
             <manifestEntries>
               <Class-Path>.</Class-Path>
               <!-- これ↑でjarのある場所にクラスパスが通る。
                    たとえばlogback.xmlをjarとおなじディレクトリに置いておけば、参照してくれるようになる。 -->
             </manifestEntries>
           </archive>
           <descriptorRefs>
             <descriptorRef>jar-with-dependencies</descriptorRef>
           </descriptorRefs>
         </configuration>
         <executions>
           <execution>
             <phase>package</phase>
             <goals>
               <goal>single</goal>
             </goals>
           </execution>
         </executions>
       </plugin>
     </plugins>
   </build>
 
   <dependencies>
     <dependency>
       <groupId>args4j</groupId>
       <artifactId>args4j</artifactId>
       <version>2.33</version>
     </dependency>
   </dependencies>
 </project>

:追記|mavenで作ったjarから実行すると、parser.printUsage(System.out); でヌルポが。。ちゃんと調べる時間がなくてよく分からない。。。とりあえずは、parser.printSingleLineUsage(System.out); をつかっておけば問題なさそうな雰囲気。。 


 
***関連リンク [#dc75d9ff]
- [[args4j parent - Args4j>http://args4j.kohsuke.org/]]
- [[Args4jを使ってコマンドライン引数を処理する - terurouメモ>http://terurou.hateblo.jp/entry/20110215/1297700839]]

 





----
この記事は
#vote(おもしろかった[4],そうでもない[2])
#vote(おもしろかった[5],そうでもない[2])
- mavenで作ったjarから実行すると、parser.printUsage(System.out); でヌルポが。。ちゃんと調べる時間がなくてよく分からない。。。 -- [[きの]] &new{2016-07-13 (水) 13:27:10};

#comment
#topicpath


SIZE(10){現在のアクセス:&counter;}

トップ   編集 差分 バックアップ 添付 複製 名前変更 リロード   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS