Hatena::ブログ(Diary)

..たれろぐ.. このページをアンテナに追加 RSSフィード

2016-06-17

Commons CLI でソートせずにオプション一覧を出力する

Commons CLI で設定したオプションをソートせずに help 表示・出力する方法。

HelpFormatter#setOptionComparator に null を渡せばソートが無効化される。

HelpFormatter のデフォルトでは、 Options に設定したオプションが通常の文字列順序にソートされて出力される。

例えば、こんな感じで x -> b -> a の順に add していても、

Options options = new Options();
options.addOption(
    Option.builder("x").required().hasArg().argName("exe")
                    .desc("set honyarara exe").build());
options.addOption(
    Option.builder("b").hasArg().argName("path")
                    .desc("set foobar path").build());
options.addOption(
    Option.builder("a").hasArg().argName("addr")
                    .desc("set hogehoge address").build());

HelpFormatter h = new HelpFormatter();
h.printHelp(72, "hoge", "", options, 2, 2, "", true);

次の通り、文字列順でソートされて表示されてしまう。

usage: hoge [-a <addr>] [-b <path>] -x <exe>
  -a <addr>   set hogehoge address
  -b <path>   set foobar path
  -x <exe>    set honyarara exe


Options に add した順序を維持したい場合は、次のように HelpFormatter#setOptionComparator に null を指定すればソートされずに表示されるようになる。

HelpFormatter h = new HelpFormatter();
h.setOptionComparator(null);
h.printHelp(72, "hoge", "", options, 2, 2, "", true);
usage: hoge -x <exe> [-b <path>] [-a <addr>]
  -x <exe>    set honyarara exe
  -b <path>   set foobar path
  -a <addr>   set hogehoge address

2016-06-15

JSON の Jackson が勝手に Stream を close してしまう問題

問題

JSON ライブラリ JacksonObjectMapper を使ったシリアライズ・デシリアライズで、Stream や Reader/Writer を対象にしたメソッドを使うと、そのStream, Reader/Writer が自動的に close されてしまうので、再び読み書きしようとした際に IOException になってしまう。
(Jackson 2.7 時点)

解決策

これは、デフォルトで読み書き後に close されるようになっているためで、この自動 close を無効にすれば解決する。

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);    // read 時の自動 close を無効に
objectMapper.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);       // write 時の自動 close を無効に

ObjectMapper に与える JsonFactory に対して指定してもいいので、別解としてこんな書き方も。

MessagePackFactory factory = new MessagePackFactory();
factory.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET);    // read 時の自動 close を無効に
factory.disable(JsonParser.Feature.AUTO_CLOSE_SOURCE);       // write 時の自動 close を無効に
ObjectMapper objectMapper = new ObjectMapper(factory);

こんな時に問題になる

ObjectMapper#readValue や ObjectMapper#writeValue を使って、複数のオブジェクトを順番にストリームに書き出し/から読み込みする場合、例えばこんなコードで IOException が出る。

ObjectMapper objectMapper = new ObjectMapper();
for (Object msg : msgs) {
   objectMapper.writeValue(out_stream, msg);    // ※ 2 個目の msg を write する時に IOException になる
}

ObjectMapper objectMapper = new ObjectMapper();
while(true) {
   Map<String, Object> msg = objectMapper.readValue(in_stream, HashMap.class);    // ※ 2周目に read する時に IOException になる
   callback(msg);
}


経緯

Jackson と MessagePack と組み合わせて、ネットワーク経由で届く MessagePack エンコードなメッセージを順次処理して〜みたいなことをしようとしてぶつかった。

参考

GitHub - msgpack/msgpack-java: MessagePack serializer implementation for Java
msgpack-java/MessagePackGenerator.java at 0.8.7 · msgpack/msgpack-java
msgpack-java/MessagePackParser.java at 0.8.7 · msgpack/msgpack-java
JsonGenerator.Feature.html#AUTO_CLOSE_TARGET (Jackson-core 2.7.0 API)
JsonParser.Feature.html#AUTO_CLOSE_SOURCE (Jackson-core 2.7.0 API)

2016-06-01

カード切替による e-TAX 登録の電子証明書の更新

住基カードからマイナンバーカードに切り換えると、 e-TAX 用の電子証明書の再登録が必要になります。
Q. どうすんの?
A. ここで再登録 (リンクは2016/6/1時点のもの)

必要なもの

ほぼ e-TAX 用と言い切っていい感じだった住基カードを、持ち運ぶのが危険なので e-TAX 専用で金庫の肥やしにせざるを得ないマイナンバーカードに切り換えた(ようやく届いた)。
切り換え時にもらった添付文書によると、『e-TAX に登録している電子証明書も再登録が必要です』とのことなので再登録しようと『e-tax 電子証明書 再登録』で調べても、『e-Taxソフトを起動し、』みたいに要e-TAXソフトインストールなのかと('A`)な顔になったわけですが、よく見ると Web で完結する方法もありました。

ググって出てくる『更新した電子証明書をe-Taxに再登録するには、どうすればいいですか。』の最初の方に『個人でご利用の方は、「確定申告書等作成コーナー」のトップ画面にある「ご利用の前に」からも再登録が可能です』がその入口。

確定申告書等作成コーナー』の左側の「ご利用の前に」にある「電子証明書の登録・再登録のみを行う方」が目的のページで、e-TAXのトップページからは、『個人での利用』→『確定申告書を作成する』でたどり着ける。

後は新しい電子証明書が入ったカードとそれに対応したICカードリーダを繋げて、ページの指示に従って入力していけば5分ほどで終わるはず。