自作Webフレームワークで学ぶリフレクションAPI　第1回

# はじめに
## 概要
Javaの面白いけど案外認知されてない（と私が勝手に思ってる）リフレクションAPIを、モダンなWebフレームワークを作りながら実践的に学ぼう、という内容です

## ターゲット層
・Java及びサーブレットにある程度触ったことがある（ソースは読める）
・アノテーションなどを利用したモダンなWebフレームワークの中身に興味がある
といった人たち向けの記事になるかと思います
Java自体まだあんまり・・・という方はあまり楽しめないかもしれません、申し訳ないです


# リフレクションAPIってなんだ？
まずはリフレクションAPIとは何か、からお話ししたいと思います
皆さんIDEやエディタ等お使いの方が多いと思いますが、コードコンプリートはご存知ですよね？
`String.`
などと打った時にStringクラスのメソッドなどを候補として表示してくれるあれです
とても便利な機能ですが、同時にとても不思議ですよね。IDEやエティタはどうやってクラスの持っているメソッドを知ったのでしょうか。予めファイルに記述？いやいやそんな無茶な。動的に元のクラスファイルを解析？不可能ではないでしょうが少しばかり大変そうですね
さて、実際のIDEやエディタがどういった実装をしているかを私は知りませんが、少なくとももっと簡単に実現する方法がある、ということは言えます

実はJavaにはそのクラスの名前、持っているフィールドやメソッド等のメタ情報を扱うためのAPIがあります
それがリフレクションAPIと言われているものです
このAPIはJava1.2で導入され、java.lang.reflectパッケージに収められているクラスがリフレクションAPIを扱うためのクラスです
（なおClassクラスだけは1.2以前から存在していたためjava.langパッケージに含まれています）

## で、何が出来るの？
延々つまらない話をしていてもしかたありませんので、早速コードを見てみましょう

まずクラスのメタ情報を扱うクラスであるClassクラス（ややこしいですが我慢してください。私も我慢します）
これを取得するには次の2つのどちらかの方法があります
`
Class.forName("java.lang.String");
String.class
`
上は古いJDBCのコードだとおまじない的に書かれていることがあるので見たことがある人もいるかもしれません
文字列によってクラスを指定できるので、動的に取得するClassクラスのインスタンスを決定できます
下はクラスリテラルと呼ばれているものです。比較的最近の型指定を要求するAPI等で使ったことがあるかもしれませんね
とにかく、このどちらかの方法を使えばとりあえずClassクラスのインスタンスが取得できます

このClassクラスのインスタンスを使うと、以下のようなことができます
```
Class<String> stringClass = String.class;
// クラスの完全名を取得する => "java.lang.String"
System.out.println(stringClass.getName());
// クラスのpublicなメソッド一覧を取得。その名前を出力する
Method[] publicMethods = stringClass.getMethods();
for(Method m:publicMethods)
　System.out.println(m.getName());
```
このようにして、実行時にそのクラスが持っているメソッドやフィールド、アノテーションなどを調べることができます
後で述べますがこれはWebフレームワークを作る上でとても重要なことです

## WebフレームワークとリフレクションAPIの関係
さて、リフレクションAPIを使うとなかなか面白いことが出来ることはわかりました
でもこれがWebフレームワークとどう関わってくるのでしょうか
そこを説明していきたいと思います

### Webフレームワーク（のユーザ実装部分）では、事前にクラスがわからない！
例えば普通にインスタンスを作るとき、以下のようにしますね
`Hoge hoge = new Hoge();`
予めクラス名がわかっているからこそこう書けるわけですよね
さて、ここで問題が発生します。もしも予め知ることができないクラスのインスタンスを作らないといけないとしたら、どうすればよいのでしょうか？
StrutsにしろSpringにしろ、開発者が作ったコントローラはフレームワークによっていつの間にかインスタンスが作られてメソッドが呼ばれます
でもこれらのフレームワークは開発者がどんな名前の、どんなメソッドを持ったコントローラを作るかを事前に知っておくことはできません
ここで、先ほど述べた「実行時にクラスのメタ情報を知ることが出来る」リフレクションAPIが活用されます

具体的な例をコードにしてみます
どこかからclassName変数で指定されたクラス（ここではHoge）のインスタンスを作り、Stringの戻り値を返すtalkメソッドを呼びたいとしましょう
`

String className = "hogehoge.Hoge";
// どこかで指定されたクラスのインスタンスが欲しい
Class<?> clazz = Class.forName(className);
Object instance = clazz.newInstance();
// talkメソッドを呼びたいなあ
Method talkMethod = clazz.getMethod("talk");
String reply = (String)talkMethod.invoke(instance);
`

さて、ここで出てきた3つの新しいメソッドについて解説します

`Class#newInstance()`は、そのクラスの引数無しのコンストラクタ経由でそのクラスのインスタンスを取得します。逆に言うとこのメソッドを使うにはそのクラスが引数無しのコンストラクタを持ってないといけません

`Class#getMethod(name:String, parameterTypes:Class<?>...)`は、指定した名前で、指定した型の引数を取るメソッド（のメタ情報クラスインスタンス）を取得するメソッドです。ここでは引数無しのtalkメソッドを取得しましたが、Stringを引数にとるtalkメソッドを取得したいなら`clazz.getMethod("talk", String.class)`のように記述します

`Method#invoke(obj:Object, args:Object...)`は、そのメソッドを指定したインスタンスと、指定した引数で実行するメソッドです。もちろんそのメソッドを持ってないインスタンスを渡すと怒られますし、渡せない引数を渡しても怒られます

このようにリフレクションAPIは使うのが面倒だったり、仕様が複雑だったりしますが上手く使うと魔法のようなことが出来る面白いAPIです


# まとめ
いかがだったでしょうか。拙い文章でしたが少しでもリフレクションAPIの面白さが伝われば嬉しいです
以下にざっとしたまとめを置いておきます
・リフレクションAPIは、実行時にクラスやそのメンバーのメタ情報を取得するAPI
・また同時に動的にインスタンスを作ったりそのメソッドを実行することが出来る
・Webフレームワークでは、ユーザが定義したクラスをインスタンス化したりメソッドを呼び出すのにリフレクションAPIがとても重要な役割を果たす

以降は順を追ってWebフレームワークを作りながらリフレクションAPIを活用する方法を解説する予定です
連載記事として扱う機能はないようなので、この連載記事には「Blebity」というタグをつけていこうと思います
Blebityは「簡潔」という意味で、このWebフレームワークの目的が可能な限りサーブレットAPIを簡潔に扱えるようにすることから取っています
よければたまに検索してやってください