かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

Tomcat3.3とTomcat5でのJSPから生成されるJavaコードの違い

元になるJSP

<html>
<body>
  <%= "Hello world " %>
</body>
</html>

出力されるJavaのコード
Tomcat3.3だと、以下のような雰囲気で出力されます

out.write("<html>\n<body>\n  ");
out.write("Hello world");
out.write("\n</body></html>\n");

Tomcat5.xだと以下のような雰囲気で出力されます

out.write("<html>\n");
out.write("<body>\n");
out.write("  ");
out.write("Hello world");
out.write("\n");
out.write("</body>\n");
out.write("</html>\n");

人間が見る分にはTomcat5系のほうが見やすいですが、冗長な表現になっています。行単位での出力が基本ポリシーになったのかな?

ちょっと問題が・・・

まぁどうでもいいかなと思ってたんですが、この差ではまりました。
長いJSPで、Tomcat3.3では動いてたけど、Tomcat5.xにうつすと1メソッド64KBの制限にひっかかって

try 文のコードが大きすぎます。
コードが大きすぎます。

というエラーが出るようになってしまった・・・。
まぁそんなJSPが、どうよ?っていう話はあるのですが、とりあえずTomcat5.xの生成するJavaコードをコンパクトにできないか調べてみたので、もしかしたら誰かの役に立つかもしれないので書いておきます。

JspServletのパラメータ設定

%CATALINA_HOME%\conf\web.xmlにあるJspServletの定義に以下のパラメータを追加します。

パラメータ名 説明
trimSpaces true スクリプトレットとかのある行をtrimしてくれる
genStrAsCharArray true 文字列をcharの配列にしてくれる

*1
パラメータを設定した後のservletタグは以下のようになりました。

  <servlet>
    <servlet-name>jsp</servlet-name>
    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
    <init-param>
      <param-name>fork</param-name>
      <param-value>false</param-value>
    </init-param>
    <init-param>
      <param-name>xpoweredBy</param-name>
      <param-value>false</param-value>
    </init-param>
    <init-param>
      <param-name>mappedfile</param-name>
      <param-value>true</param-value>
    </init-param>
    <!-- ここから追加設定 -->
    <init-param>
      <param-name>trimSpaces</param-name>
      <param-value>true</param-value>
    </init-param>
    <init-param>
      <param-name>genStrAsCharArray</param-name>
      <param-value>true</param-value>
    </init-param>
    <!-- ここまで追加設定 -->
    <load-on-startup>3</load-on-startup>
  </servlet>

この設定をすると、Tomcatが生成するJavaのコードが以下のような感じになります。

// フィールドの宣言に以下のようなcharの配列が追加される
char[] _jspx_char_array_0 = "<html>\n<body>".toCharArray();
char[] _jspx_char_array_1 = "</body></html>\n".toCharArray();

// HTMLを出力する部分のコード
out.write(_jspx_char_array_0);
out.write("Hello world");
out.write(_jspx_char_array_1);

余計な改行やスペースが削除されるのと、charの配列にテキストが抜き出される単位が行単位じゃなくて、静的な部分をまとめてくれるのでメソッドの呼び出しコードが減ります。
これで、とりあえず応急処置・・・。

本当は、コードを分割すべきなんだけどね・・・。

追記(2010/02/17 14:30)

genStrAsCharArrayじゃなくてmappedfileが、JSPの1行をJavaの1行に対応させるかどうかの設定項目らしいので、mappedfileをfalseにするほうがセオリーっぽい。

*1:追記部分にあるようにgenStrAsCharArrayよりもmappedfileを設定するほうがよさそう