読者です 読者をやめる 読者になる 読者になる

せかいや

いまいるここを、おもしろく http://sekai-in-the-box.appspot.com/

【Java】JSPコンパイルのタイミング パーフェクトJava学習感想文 その7

パーフェクトJavaを読んで改めてJavaを振り返り中。


経緯については学習記録その1をご参照ください。

以下、学んだこと。

 

リフレクションは単なるAPI

例えばアノテーションは言語仕様だけれど
リフレクションは「仕様」という範疇ではない。
Java言語仕様にだってリフレクションという項目はない

当たり前・・・なんだけれど、
自分はリフレクションを特別なものだと思っていたので反省をこめて。

 

JavaBeansはリフレクションの応用例

これも言われたら納得ですが。

Beansが最低限持つ特徴は、
リフレクションによる実行時オブジェクト生成を想定した設計です

確かに。
Beanってインスタンスをnewしたりしない。
裏で暗黙的に生成してもらってた。

あるクラスがBeanクラスか否かを決定付ける要因はクラス自身にはありません。Beansクラスをインスタンス化し、Beanオブジェクトを操作するツールやフレームワークの要請で決まります。
一般にこのようなツールやフレームワークを「Beanコンテナ」と呼びます。

確かに。
「Beanコンテナ」がBeanのインスタンスを作ってる。

 

アノテーションは「宣言的プログラミング」の道を開く

宣言型プログラミングは手順でなく目的を記述します。アノテーションで目的を記述することは、Javaによる宣言型プログラミングの道を開きます

ふーむ。
 

宣言的プログラミングとは

純粋関数型プログラミング、論理プログラミング、制約プログラミングの総称である。

http://ja.wikipedia.org/wiki/%E5%AE%A3%E8%A8%80%E5%9E%8B%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0

こともあるみたい。

ある出力を得るにあたってそれを作成する方法ではなく、出力の性質を記述することを「宣言型」と称する。

うーん。。
確かに「@Deprecated」と一行書けば後はよろしくやってくれるけど。
宣言型プログラミングを良く知っていないからそこまでぴんと来ない。
ライブラリを使うこととは訳が違うんだよね?
 

関数型言語とは

関数プログラムは代入文を含まない。
関数プログラムには全く副作用がない。
いつの時点で式の値を評価してもよい。

http://www.sampou.org/haskell/article/whyfp.html

え!?すごい!
関数型言語も、ちょっとは勉強してみよう。
「ちょっと」で済むのかな。。


 

アノテーションはPOJO

プラグインするコードから他への依存性を完全に排除できる

うーん確かに?
「(継承も拡張もしていないから)依存性がありません」
っていう文脈かな。
だって@hoge と書いて動くものを@hage と書いたらエラーになるよね。
アノテーションの定義名に当然従わなくてはいけないけど、
これは依存性には当たらないのか。
 
wikiでも「なんか曖昧だよね」と言っている。

定義は本質的に不安定で曖昧である。

http://ja.wikipedia.org/wiki/Plain_Old_Java_Object

 
同じくWiki↓

EJB 3の仕様はPOJOプログラミングモデルであることを宣言しており、EJB3 Session BeanをPOJOとして記述している。ただし、通常はアノテーションを必要とする。

http://ja.wikipedia.org/wiki/Plain_Old_Java_Object

「通常はアノテーションを必要とする」って断り書きが入ってる。
完全なPOJOは「アノテーションを必要としない」わけだ。
 
まあイメージがつかめてるからいいか。

 

JSPのコンパイルはJSPコンパイラが行います

確かに!
実装を調べてみよう
http://www.docjar.com/html/api/org/apache/jasper/servlet/JspServlet.java.html
JspServletクラスのserviceメソッドをたどっていくと

wrapper.service(request, response, precompile);

 
■JspServletWrapperのserviceメソッド

 public void service(HttpServletRequest request, …

/*
* (1) Compile
*/
if (options.getDevelopment() || firstTime ) {
	synchronized (this) {
	firstTime = false;
	// The following sets reload to true, if necessary
		ctxt.compile();
	}
} else {

存在しないとコンパイルしているー。

 
色々調べているうちに、
JspCompilerクラス、これ矛盾があるよね?
Compilerクラスの抽象メソッドgenerateClassを実装してない。

ソース(apache-tomcat-6.0.26-src)を落として確認したら、
やっぱりJspCompilerクラスは存在していない。

if (options.getCompiler() == null) {
    jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler");
    if (jspCompiler == null) {
        jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler");
    }
} else {
    jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler");
    if (jspCompiler == null) {
        jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler");
    }
}

ふーん。コンパイラは2種類になったのか。
ネット上のJavaDocとソースを過信するのはやめとこう


 

Javaメソッド内でコンパイル処理を呼び出す

インタフェース JavaCompiler
Java プログラムから Javaプログラミング言語コンパイラを呼び出すインタフェースです。

http://docs.oracle.com/javase/jp/6/api/javax/tools/JavaCompiler.html

へー。
「javax.tools」パッケージって全然使ったことなかった。
こんなのあったんだ。
 
あれ?

JavaCompiler. JDK1.6から、Javaのコンパイルを行う(javacを起動する)クラスが用意された。

http://www.ne.jp/asahi/hishidama/home/tech/java/JavaCompiler.html

ならそれまでのJSPサーブレットはどうやってコンパイルしていたんだ?調べてみよう。


 
■AntCompilerのgenerateClassメソッド(部分)
http://www.docjar.com/html/api/org/apache/jasper/compiler/AntCompiler.java.html

Javac javac = (Javac) project.createTask("javac");
・・・
javac.setEncoding(javaEncoding);
javac.setClasspath(path);
・・・
javac.execute();

なるほど。
JavaCompilerはあくまでJavacの起動を便利にラップしているだけであって、
JSPサーブレットやANTはJDK1.6以前も自前でコンパイルしていたのか。
当たり前か。


 

JSPJavaファイル

TomcatではJavaファイルを$TOMCAT/work以下で見つけることができます

知らなかった。
バグが出たときはここを調べてみよう。