tokuhirom's blog

maven central にリリースしてみた

Maven central にあげようと以前奮闘してみたが、うまく行かずに諦めていた。

アカウントの登録まではいっていたのだが、なんかうまくいかなくて諦めていたのだ。 が、モリスさんのエントリを見ながら pom を設定していったら今回はなぜかうまく出来た。 http://d.hatena.ne.jp/tagomoris/20141028/1414485679

Maven central は難しいか?

Maven central にアップロードするまでに間には以下のようなステップが必要になる。

  • JIRA にサインアップする
  • JIRA でパッケージに対するアップロード権限を要求する
  • gpg の設定をする
  • settings.xml/pom.xml をセットアップする
  • mvn release:prepare release:perform する

このうち、最初の JIRA へのサインアップは難しいことはない。

Step2 は、要求したあと使えるようになるまでの間に若干の英語でのやりとりが必要なのでたいがいダルい。 「このドメイン本当にお前のなの?」って聞かれたりする。パッケージに対するアップロード権限の要求は、me.geso.avans のようなプロジェクトごとにする必要があると思い込んでいて、いちいちこのやりとりするのめんどくさすぎるなーと思ってたのだが、実際には me.geso 以下に対するアップロード権限をもらえるので、めんどくさいのは最初の一回だけである。ドメイン名を持っていない場合には com.github.gfx のようなパッケージ名で申請すればよい。

gpg の設定は、やや面倒だがググれば情報出てくるので、まあやるしかない。

settings.xml/pom.xml の設定が、僕はどうやったらいいかよくわからなくてはまってたんだけど woothee のレポジトリみながらやったらなんかうまく行った。 woothee は、なんか色々ごちゃごちゃやってるので、僕の pom.xml を見ながら設定してもいいと思います。 https://github.com/tokuhirom/webscrew/blob/master/pom.xml

mvn release:prepare release:perform がちょっと難しくて、だいぶハマった。 基本的にはこれが minil release みたいなものになっている。タギングとかそういうのもひと通りやってくれる。 なっているのだけど、ちょっと癖があるというか戦略が minil とかと違っている。 なにしろ2ステップでリリースするわけなので。 release:prepare をすると、前処理が行われて、なんか謎のテンポラリファイルが幾つかできる。ここでバージョンの bump とかもしてくれる。 終わったら mvn release:perform すればよろしい。うまくいけばアップロードされる。 なんか dirty な状態になったら、混乱するんだけど mvn release:clean すれば元に戻せるので、冷静に元に戻したらいい。

最初の一個あげるまでがちょっと面倒だけど、よく考えると CPAN とそんなにすごく変わるわけではない、と思う。CPAN に最初にあげたのとか10年ぐらい前だから難しかった記憶も得にないんだけどね。CPAN もメールおくって承認されないとアップロードできないし。

gradle なら楽か?

結局、gradle に maven central にアップロードするためには相応の設定が必要なので、あまり手間は変わらないと思う。あと gradle の maven-publish プラグインはまだ Incubator だし。。

コミュニティ的なものが無いのが辛い

mvn release 関連で、何か質問したいと思っても、どこで聞いたらいいのやら。 日本語の forum 的なものが存在しないんで、それが辛い気がした。

あと、ネットに転がってる記事を見ても、なんか情報が恐ろしく古いのが多くて。。

そういうわけで、、

https://tokuhirom.github.io/maven/ のレポジトリはしばらくしたら消すので、よろしくお願いします!

こちら利用している方いらっしゃいましたら今のうちに新しいバージョンに依存するように変更してください。

Created: 2014-10-31 08:52:38
Updated: 2014-10-31 08:52:38

Shipped router-simple 0.16

Added directory_slash option by @fayland++. It works like Apache's DirectorySlash option.

Created: 2014-10-27 10:54:01
Updated: 2014-10-27 10:54:01

tinyorm 0.28.7 がでてます

SELECT ~ FOR UPDATEINSERT ~ ON DUPLICATE KEY UPDATE の2つの機能が実装されてます。 この2つは、mysql 特有のクエリですが、ないと不便なのでつけました。

【追記】 FOR UPDATE は標準だそうです!!

Created: 2014-10-27 10:32:54
Updated: 2014-10-27 10:32:54

Yosemite にしたら AppleScriptEngine.jar がどやこやで Eclipse でコンパイルできなくなった。

http://support.apple.com/kb/dl1572 から Java for OS X 2014-001 を入れたら治った。よかった。

Created: 2014-10-25 23:28:04
Updated: 2014-10-25 23:28:04

[java] webscrew に basic auth header のパーサーつけた

表題の通りです。

avans で Authorization header をパースするのがダルいので、一応そのへんの機能をつけた。

(webscrew とは web application を作るときに必要な部品を集めたライブラリで、Perl でいうところの Plack に相当するものです。)

Created: 2014-10-23 20:21:46
Updated: 2014-10-23 20:21:46

avans 0.34.0 出した

avans の 0.34.0 を出した。 クエリパラメータが足りていない場合などに例外をあげていたのだが、例外的な状況じゃないので、エラーレスポンスを真面目に返すようにした。

Created: 2014-10-10 13:05:57
Updated: 2014-10-10 13:05:57

[java] SecureRandom のアルゴリズムの選択について

前提

Java SE 8 + Linux 前提です。

Java で暗号的に安全な乱数をえる

Java で暗号的に安全な乱数を得るには SecureRandom クラスを利用します。 SecureRandom ではいくつかの乱数生成アルゴリズムをサポートしています。

各プラットフォームでもっとも安全な SecureRandom の実装は ${JAVA_HOME}/jre/lib/security/java.security の securerandom.strongAlgorithms という項目に書いてあります。 SecureRandom#getInstanceStrong() で取得できるのはこれです。

インスタンスの取得方法

  • new SecureRandom() でデフォルト実装が得られます
    • OSX や linux では NativeBlocking です(SHA1PRNGの場合もある)
  • SecureRandom#getInstance(name) で名前を指定して実装を得られます
  • SecureRandom#getInstanceStrong() で、プラットフォームでもっとも強力な実装が得られます
    • OSX や linux では NativePRNGBlocking です
    • /dev/random を利用します

各アルゴリズムの詳細

実装は以下のようになっています。

SHA1PRNG (Initial seeding is currently done via a combination of system attributes and the java.security entropy gathering device)
NativePRNG (nextBytes() uses /dev/urandom, generateSeed() uses /dev/random)
NativePRNGBlocking (nextBytes() and generateSeed() use /dev/random)
NativePRNGNonBlocking (nextBytes() and generateSeed() use /dev/urandom)

http://docs.oracle.com/javase/jp/8/technotes/guides/security/SunProviders.html

NativePRNGBlocking は /dev/random から取得するので、遅いです。 あまり利用されていない開発サーバーなどでは 30 秒ぐらいかかります。 鍵の生成などにはこれを利用するべきですが、ちょっとしたトークンの生成などに利用すると、めっちゃ遅くてなけます。

トークンの生成等には NativePRNG または NativePRNGNonBlocking を利用すれば十分かと。

ちなみに、NativePRNGBlocking と NativePRNGNonBlocking は最近導入されたようです。

For UNIX-like platforms, two new implementations were introduced which provide blocking and non-blocking behavior: NativePRNGBlocking and NativePRNGNonBlocking. http://docs.oracle.com/javase/8/docs/technotes/guides/security/enhancements-8.html

securerandom.source の変更について

インターネットを見ていると、securerandom.source を変更して /dev/urandom を見るようにしろ、という記述を見かけますが、これは Java 8 の世界では間違ったやり方だと私は思います。

NativePRNGNonBlocking を利用するように実装を変更するのが正しいアプローチだと私は考えます。

tips

/dev/random がどんどん出てくるかどうかは head -n 1 /dev/random で調べることができる。

まとめ

とりあえず弱いよりは強い方がいいだろってことで SecureRandom#getInstanceStrong() を呼んだりしてるとサービスが刺さる。

参考文献

Created: 2014-10-09 12:50:50
Updated: 2014-10-09 12:50:50

[ruby] スクリプトの実行結果をログファイルに書く

Ruby で書いたスクリプトの実行結果をログファイルに残したい。しかし tee とかでトルのもめんどくさい。 そんな時は ruby の STDOUT/STDERR をロガーのパイプに置き換えてしまえばよろしい。 ついでに、どの行がいつ出たかがわかりやすいようにタイムスタンプもつけて欲しい。

そんな時ってありますよね。そんな時に使えるスニペットが以下になります。

logfile = Time.now.strftime("#{LOG_BASE}/%Y-%m-%d.%H%M%S.log")
log_fh = open("| /usr/local/bin/tai64n | tee -a '#{logfile}' | /usr/local/bin/tai64nlocal", 'a') 
log_fh.sync = true
$stderr.reopen(log_fh)
$stdout.reopen(log_fh)

本当は、もっと ruby らしい解法があると思うけど、

  • 標準ライブラリでできる
  • 行数が少ない

という条件を満たすために、UNIX 的解法で済ませた。

Created: 2014-10-03 11:43:58
Updated: 2014-10-03 11:43:58

[ruby] readline がなくて後から入れたい時

readline ライブラリは ruby の標準ライブラリなはずだけど入ってない環境もあるので

gem install rb-readline

しておく必要がある。

Created: 2014-10-02 17:28:03
Updated: 2014-10-02 17:28:03

LL から Java に移行した人がはまりがちなこと

こんにちは。Java 初心者です。

Java 初心者、得に LL から Java に来た人にありがちな問題について社内向けに書いたものをオープンアンドシェアさせていただきます。

前提として、我々は Java 8 でガンガン攻めているということをご承知おきください。

また、自分がこの数ヶ月で「うわー。こうしとくべきだったのかー」と気づいたやつをドヤ顔で語っているということにもご注意ください。

【追記】 対象は中規模 B2C の場合です(中規模というのは facebook より小さいという程度の意味です)

例外を握りつぶさないようにしよう

Eclipse が生成する以下のようなコードをそのまま残しているケース。 これは言うまでもなく良くないですね。デバッグが困難になります。

try {
} catch (IOException e) {
    e.printStackTrace();
}

Perl でいうと eval { ... }; warn $@ if $@; みたいなもんですからね。。

賞味、ウェブアプリケーションを書いている場合、何も考えたくない時は以下のように RuntimeException でくるんで rethrow してあげるのがいいです。 try { ... } catch (IOException e) { throw new RuntimeException(e); }

フレームワークがなんか適当にエラーページ出してくれます。

基本的に、ウェブアプリケーションではリカバリ可能な例外というものがほぼ無いんで、何も考えずに RuntimeException にしちゃって問題ないです。たいがいの場合は。(バッチ処理やワーカーの処理の場合はこの限りではありません)

null を return しないようにしよう

Java 8 で書いている場合、基本的に null を返してはいけませんね。Optional 使いましょう。

Optional 型は、null か null じゃないものかが入っているコンテナです。Java でメソッドを書いている場合、基本的にいつでも null を返せるわけですが、null にたいしてメソッドを呼び出すと NullPointerException が発生します。

毎回 null かどうかをチェックするのはめんどくさいし、まあ意味が無いケースも多いわけです。 そういうわけで、null を返したいケースでは Optional 型を利用して、null が返る可能性を明示して、それ以外のときには基本的に null を返さないようにする、ということが肝要となってまいります。

ライブラリから null が返ってくるケースはままあるわけですが、それをアプリケーションコード内のメソッドから返却してはいけません。

@NonNull を活用しよう

lombok を使ってる場合、@NonNull というアノテーションいれるだけで、引数に対する null check が簡単にできるんで、気が向いた時に入れておくと、どこから null が混入したかがわかりやすくなって便利だったりします。

リソースを明示的にクローズしましょう!

Perl では Reference Count GC が全面的に採用されており、リソースはその変数が参照されなくなった時点で即座にリリースされます。 ファイルも $fh がスコープから外れたらすぐにクローズされます。

しかし、Java の場合にはそうではない!!ちゃんと明示的に閉じて上げる必要があります。 しかし、明示的に .close メソッド呼ぶとかだるいので、try-with-resources を使いましょう。

try-with-resources を使いまくろう

Java 7 で導入された try-with-resources 構文はめちゃんこ便利なので必ず覚える必要がある。

以下のように書くと、try を抜けるタイミングで、自動的に br.close() が呼ばれます。

static String readFirstLineFromFile(String path) throws IOException {
  try (BufferedReader br = new BufferedReader(new FileReader(path))) {
    return br.readLine();
  }
}

昔の Java の本や、インターネッツにのってるコードだと以下のようなコードがよくありますが、今ではずっと簡潔に書くことができるのです。

static String readFirstLineFromFileWithFinallyBlock(String path) throws IOException {
  BufferedReader br = new BufferedReader(new FileReader(path));
  try {
    return br.readLine();
  } finally {
    if (br != null) br.close();
  }
}

try-with-resources を使っていて、ウェブアプリケーションを書いている限り、基本的に finally block を書くことはほとんどありません。finally を書きたいなーと思ったら、一度立ち止まってよく考えてみるか、誰かに相談してみるといいと思います。

(Note. try-with-resources は、Guard の代わりにも使えますね)

Object 型をできるだけ避けよう

どうせ Perl だったら返り値なんか Object 型相当なんだし、Object 型をたまには返してもいいよね?と思う向きもあると思いますが、実際にはアプリケーションコードで Object 型を返却しなければいけないケースは現在ではほぼありません。だいたいはジェネリクスにより、うまいことなんとかなります。

なんとかならないケースがあったら、たぶんだいたいはよく調べたらなんとかなるので、誰かに聞いてください。

FindBugs を使おう

FindBugs は Perl でいうと Perl::Critic に対応するもの、JS でいうと jshint に相当するものです。 ありがちなコーディングミスをひと通り教えてくれます。

人間によるコードレビューを受ける前にひと通り findbugs でチェックしておきましょう。

findbugs の利用は maven を使っている場合は

mvn clean compile findbugs:check

とするか、pom.xml に以下のように書いて、mvn site && open target/site/index.html するのがいいかと思います。

<reporting>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>findbugs-maven-plugin</artifactId>
            <version>3.0.0</version>
        </plugin>
    </plugins>
</reporting>

Effective Java を読もう

Effective Java って、なんか Java 6 対応!! とか書いてあるし、めっちゃ内容古そうに見えますが、実際まあ、よく出来ている書籍で、ハマりどころをひと通り教えてくれます。 (実際は訳注で Java7 に関するフォローも入っています)

Effective Java は Effective Perl というよりは Perl Best Practices に近い書籍なんで、ひと通り読んでおくといいと思います。

というか、読んでなくてダメなコードを書いていると後ろ指さされる感じあるので、読んだほうがいいです。

マルチスレッドで動いていることを意識してコーディングしよう

Perl の場合には基本的にアプリケーション・サーバーは pre-fork モデルで実行するのが普通です。 pre-fork の場合は、各プロセスの間ではデータは共有されません。

しかし!! Java の場合は multi-thread モデルで、各リクエストごとに thread が割り当てられます。 他のスレッドと変数を共有することが可能となっているのです。

これはつまり、スレッド間での競合が起きるとまじひどい目にあうということです。 ですから、基本的に、スレッド間でのデータ共有をできるだけ避けてコーディングするようにしたほうがいいです。

明示的にスレッドセーフであると宣言されているライブラリ以外はスレッドセーフではないと考えよう

たまに、「何回か動かして問題ないからスレッドセーフだろ。。」みたいな考え方をする人がいるのですが、そういうことではないです!

ごくたまに起きるスレッド競合とかあるとまじ最悪な感じになりますので、「このライブラリはスレッドセーフです!」と明示的にマークされているもの以外は、スレッド間で共有しないようにしましょう。

JSON を文字列で書かずに Jackson で生成しよう

なぜか知らないけど、Java で書くときになると JSON を手で書いて文字列でハードコードしたくなる人がいます。

これは、invalid な JSON をハイて、ひどい目にあうリスクがあるんで、基本的に Jackson などにお任せしましょう。

printf デバッグの代わりにロガーを使おう

System.err.println() とか System.out.println() でデバッグするのはやめましょう。 かわりに slf4j のロガーに出しましょう。

あと、そもそも printf デバッグを避けて debugger を使うようにしていきましょう。

jax-rs でクラスとメソッドに分けて Path 定義するのを避けよう

クラスに @Path("/blog") してメソッドに @Path("/{id}") つける、みたいなコーディングが jax-rs だと可能なんですが、こういうふうに書くのは grep-ability が低くなってよくないので、@Path("/blog/{id}") みたいに書くのが僕は好きです。

ここは好みの面もあると思いますけど、メソッド側にまとめて書いたほうがメンテナンス性が高いと、僕は思います。

Diamond inference を使おう

Java7 以後では Diamond inference で簡潔に書けるので、簡潔に書いたらいいです。

List<Foo> foo = new ArrayList<Foo>();

List<Foo> foo = new ArrayList<>();

Javadoc を書こう

クラス/メソッドにコメント書きましょう。Java の場合、メソッド補完するときに javadoc のコメントが見えるんで、書いといたほうが開発効率が後々よくなってきます。

Hibernate はインメモリキャッシュを勝手にやるので注意

Data::ObjectDriver 的なメモリキャッシュを持ってくれるので、気をつけよう!

デフォルトだと、セッションの間でだけ有効なインメモリキャッシュが有効になっているはず。 一部で、「よっしゃここは SQL で高速化やでー」といって hibernate バイパスして SQL 直接ぶっこんだりするとひどい目にあう気がしている。

警告をなくそう!

warnings が出ているのひと通り治しましょう。警告出たままにしておくと、重要な警告を見落とす結果になってしまいます。 引き継ぎした案件で warnings 出まくってると、めっちゃなえます。

Java の警告、そもそもなんでそんなに怒ってるのかわからないというケースもままあると思うんで、そういうときはスクショをとって他のひとに聞くとよいです。

Jackson で constructCollectionType じゃなくて TypeReference を使おう

Jackson は以下のように constructCollectionType とか使えますが、可読性が低いと感じるのが僕です。

JavaType type = mapper.getTypeFactory().
  constructCollectionType(List.class, Foo.class)

↓↓こっちのほうが好き。

List<Foo> list = mapper.readValue(jsonString, new TypeReference<List<Foo>>() { });

後者のほうが、読みやすいが、無名クラスを一個つくることになるというデメリットはあります。 ただまあ、そんなデメリットでもないんで、別によいのでは。

(これは好みの問題でもあるんで、どっちでもいいっちゃいいです)

自分で考えすぎないで人に頼ろう

社内の hipchat に Java っていう名前のチャットルームがあるので、入って聞いたらいいです。 だいたいすぐに誰か答えてくれると思います。

基本的に自分でがんばって考えても無駄なんで、どんどん人に聞くのがよいと思います。

【追記】 Reflection をさける

アプリケーションコードで Reflection を使いたくなったら、それはたぶん何かが間違ってる可能性があるというか、Java っぽくないコードを書こうとしているケースな可能性が極めて高いので、だれかに相談してください。

Created: 2014-10-01 09:00:07
Updated: 2014-10-01 09:00:07