May 8, 2024

I’ve been trying to figure out how to precompile my JSP pages in JBoss/Jetty. I dislike waiting for a JSP to compile every time I hit it for the first time. And if I just change one JSP page, after I redeploy it, it’d have to recompile pages again. Another thing is that there is a memory leak with javac, so that eventually I’d have to restart JBoss every so often. Now that I’ve figured out how to precompile my JSPs, life has been much happier.

The basic idea to precompile JSPs is to convert the JSPs into servlets. Then compile the servlets. Then update web.xml with the new servlets. JspC is the key tool in doing all this. The JSPs will no longer be directly referenced, but be hit directly as servlets instead.

The following gives a basic idea of how I did it…

Code snippet from build.xml:


<property name="appname" value="HelloWorld"/>
<property name="basedir" value="."/>
<property name="dist.root" value="c:/jboss-3.2.3/"/>
<property name="jboss.dist" value="${dist.root}/server/default"/>
<property name="jboss.deploy.dir" value="${jboss.dist}/deploy"/>
<property name="java-debug" value="on" />
<property name="servlet.jar" value="${basedir}/vlib/javax.servlet.jar"/>
<property name="war" value="${appname}.war"/>
<property name="src.dir" value="${basedir}/src"/>
<property name="build.dir" value="${basedir}/build"/>
<property name="jsp.precompile.dir" value="${build.dir}/jsp"/>
<property name="build.classes.dir" value="${build.dir}/classes"/>
<property name="generated.src.dir" value="${basedir}/generated/src"/>
<property name="generated.metainf.dir" value="${basedir}/generated/META-INF"/>
<property name="gen.mappings" value="${basedir}/generated/META-INF/gen-mappings.xml"/>

<!-- JSP Precompile Stuff -->
<path id="jsp.precompile.path">
<pathelement location="${build.classes.dir}"/>
<fileset dir="${dist.root}">
<include name="server/default/lib/*.jar"/>
</fileset>
<fileset dir="${dist.root}">
<include name="server/default/deploy/jbossweb-jetty.sar/*.jar"/>
</fileset>
<fileset dir="${dist.root}">
<include name="lib/*.jar"/>
</fileset>
<fileset dir="${basedir}/webapp/WEB-INF/lib">
<include name="*.jar"/>
</fileset>
</path>

<target name="test-jspc">
<echo message="Testing if JSPs are uptodate..."/>
<uptodate property="jspc.notRequired">
<srcfiles dir="${basedir}/webapp" includes="**/*.jsp"/>
<mapper type="glob" from="*.jsp" to="${jsp.precompile.dir}/*_jsp.java"/>
</uptodate>
<antcall target="jspc"/>
</target>

<target name="jspc" unless="jspc.notRequired">
<mkdir dir="${jsp.precompile.dir}"/>
<echo message="Precompiling JSP to Java code..."/>
<java classname="org.apache.jasper.JspC" classpathref="jsp.precompile.path">
<arg value="-v4"/>
<arg value="-die"/>
<arg value="-d"/>
<arg value="${jsp.precompile.dir}" />
<arg value="-p"/>
<arg value="${appname}"/>
<arg value="-webinc"/>
<arg value="${gen.mappings}"/>
<arg value="-webapp"/>
<arg value="${basedir}/webapp"/>
<arg value="-uriroot"/>
<arg value="${basedir}/webapp"/>
</java>
<echo message="Compiling translated JSP code..."/>
<javac srcdir="${jsp.precompile.dir}"
destdir="${build.classes.dir}"
classpathref="jsp.precompile.path"
debug="${java-debug}" />
</target>

<target name="merge-webxml">
<echo message="Merging servlet definitions into web.xml"/>
<loadfile property="jsp.servlets.text" srcFile="${gen.mappings}"/>
<copy file="${basedir}/webapp/WEB-INF/web.xml" overwrite="true"
todir="${basedir}/generated/META-INF/" filtering="true">
<filterset begintoken="&lt;" endtoken="&gt;">
<filter token="<!-- Precompiled JSP Servlets -->"
value="${jsp.servlets.text}"/>
</filterset>
</copy>
</target>

<target name="compile">
<mkdir dir="${build.classes.dir}"/>
<javac destdir="${build.classes.dir}"
debug="${java-debug}"
deprecation="on"
optimize="off"
includes="**">
<src path="${src.dir}"/>
<classpath>
<fileset dir="webapp/WEB-INF/lib">
<include name="*.jar"/>
</fileset>
<pathelement path="vlib/jboss-j2ee.jar"/>
<pathelement location="${servlet.jar}"/>
<pathelement location="${build.classes.dir}"/>
</classpath>
</javac>
</target>

<target name="war" depends="compile,test-jspc,merge-webxml">
<war warfile="${build.dir}/${war}" webxml="${basedir}/generated/META-INF/web.xml">
<fileset dir="webapp/">
<include name="**"/>
<exclude name="**/*.jsp"/>
<exclude name="WEB-INF/web.xml"/>
<exclude name="WEB-INF/lib/**"/>
</fileset>
<lib dir="webapp/WEB-INF/lib">
<include name="**/*.jar"/>
</lib>
<classes dir="${build.classes.dir}">
<include name="**/*.class" />
</classes>
</war>
</target>

Code snippet from web.xml: (make sure line is between any preexisting <servlet> and <servlet -mapping> tags)


<!-- Precompiled JSP Servlets -->

Links:
My JBoss Framework