こんにちは、深澤です。
最近、何かとplayframeworkを使う機会が多いのですが、あるアプリケーションのログイン機能を実装してたらこんなエラーが出ました。
play.api.Application$$anon$1:Execution exception[[RuntimeException: java.lang.reflect.InvocationTargetException]]
わかりにくいな、これは。
検索しても日本のサイトには出会いません。
そんな中、こんなサイトに出会いました。
http://stackoverflow.com/questions/19134105/playframework-runtimeexception-java-lang-reflect-invocationtargetexception
今回はこのサイトの定義やメソッドなどを参考にさせていただきながら、和訳的な感じで、日本語でわかりやすく書いていけたらなと思います。
なお、今回はplay2.4のjava8です。
これって何が起きてるの??
結論から申し上げると、javaエンジニアの方なら一度は経験しているであろう、NullPointerExceptionが発生してます。
エラーにはそんなこと、一言も書いてませんけどね・・・(笑)
なので、何も入っていない値を呼び出しているのが原因です。
なんでそうなるの?
僕はこの現象、ログイン機能を実装した際に発生したのですが、playでログイン機能を実装する時って、フォームに入った値をバインドする(取り出す)際にパスワードとユーザ名をデータベースで検索すると思います。
それで、その時って、javaの場合はインナークラスなり、別クラスなり、フォーム用のクラスを定義して、その中にvalidateメソッドを用意、そこからmodelsの適当なメソッドを呼び出すと思うんですね。
そのmodelsのメソッドの部分で、このNullPointerExceptionが起きている可能性が高いです(この流れ通りならNullPointerExceptionが発生するのはmodelsしかないので)。
ここでどのように値を取り出すかがポイントになってきます。
たぶん、playでjavaを使う時は先ほど紹介させていただいたサイトの方のように、こんな感じでFinderのインスタンスを作って、検索メソッドを用意する方法がほとんどだと思います。
public static Model.Finder<String,User> find = new Model.Finder<String,User>(String.class, User.class);
検索をする時、次のように書くことで検索にヒットしたレコードの特定の値を取り出すことができます。
String tempId = AccountDetails.find.where().eq("email", email).eq("password", password)
.findUnique().userId;
しかし、この書き方は危険です。
万が一、検索にヒットしなかった場合などにはNullPointerExceptionが発生します。
じゃあ、どうしたらいいの??
findUnique()メソッド自体は例えnull値(検索にヒットしなかった)だとしても単純にnullを返すだけですが、その検索結果のインスタンスに対して変数(コンストラクタ)を呼び出そうとすると、万が一検索にヒットしなかった場合はnullとなりますので、NullPointerExceptionになるわけです。
つまり、上記のサイトの解答例にも書いてある通り、次のようにfindUnique()の値を直接参照するのではなく、findUnique()の結果からコンストラクタを呼び出すべきです。
AccountDetails accountDetails = AccountDetails.find.where().eq("email", email).eq("password", password).findUnique();
if (accountDetails != null) {
String tempId = accountDetails.userId;
}
これにより、無事に String tempId を取り出すことに成功しました。
まとめ
今回はログインの際の処理にフォーカスして記事を書いたのですが、
こういうようなケース以外にも、findUnique()した値の一部が欲しいケースは多いと思います。
僕もよくやってしまうのですが、検索結果のインスタンスに対して、直接、値を参照してしまうとエラーになりますので気をつけて下さい。
以上です。
また今回もコメントなどあればお気軽にお願いします。
ありがとうございました。