Sunday, September 13, 2009

Precompiling JSP Pages with Maven

Recently I encountered the requirement to precompile JSP pages in a Maven webapp project using the following environment:
  • Java 5
  • Tomcat 5.x
  • Jsp pages with XML Syntax (jspx)
Solving the problem is not too difficult if you keep some things in mind.
Precompiling JSP pages has a number of advantages (and some disadvantages too):
  1. The precompiled JSP pages are delivered as servlets which means that the application runs at full speed immediately after deploying it. Compiling JSP pages on demand may not matter with an application that uses a few JSP pages but it definitely matters when having 300+ JSP pages.
  2. It is possible to tweak the Java Compiler for JSP pages to use optimisations and to leave out debug informations which can speed up the application a little further.
  3. The Precompiler finds every error in every JSP (even in seldomly used pages/error pages)
There are some disadvantages which should be remembered as well:
  1. The used JSP compiler version has to match the container version as close as possible. So if you update your tomcat installation you need to recompile your webapp or it may fail in a worst case scenario.
  2. Turning on javac optimisations and turning off debug information makes it much harder to track down errors. So you'd better have good loggin in your application to get an idea why errors happened.
  3. Not all servlet containers are supported by the used plugin. Currently it should work without problems with Jetty and Tomcat.
So, what is needed to include JSP precompilation in your Maven web project?
  • A recent Maven version (2+). I currently use Maven 2.2.1.
  • The Maven JspC Plugin from codehaus (currently 2.0-alpha-3)
The first step is to declare the plugins and configure them as with every other maven plugin. The jspc plugin documentation could use some improvement and updating. It took me some time to gather the required information to get it up and running. The results of this exptedition are found in the next code snippet:
<plugin>
  <groupid>org.codehaus.mojo.jspc</groupid>
  <artifactid>jspc-maven-plugin</artifactid>
  <executions>
    <execution>
      <id>precompileJsp</id>
      <goals>
        <goal>compile</goal>
      <goals>
      <configuration>
        <sources>
          <directory>${basedir}/WebContent</directory>
          <includes>
            <include>**/*.jspx</include>
          </includes>
        </sources>
        <source></source>1.5
        <target>1.5</target>
      </configuration>
    <execution>
  </execution>
  <dependencies>
    <dependency> 
      <groupid>org.codehaus.mojo.jspc</groupid> 
      <artifactid>jspc-compiler-tomcat5</artifactid> 
      <version>2.0-alpha-3</version> 
    </dependency> 
    <dependency> 
      <groupid>org.slf4j</groupid> 
      <artifactid>slf4j-log4j12</artifactid> 
      <version>1.5.6</version> 
    </dependency> 
    <dependency> 
      <groupid>org.slf4j</groupid> 
      <artifactid>jcl-over-slf4j</artifactid> 
      <version>1.5.6</version> 
    </dependency> 
  </dependencies>
</plugin>
There are some obvious and some, well, less obvious settings to configure.
 The biggest pain with the jspc plugin is the incomplete declaration of  dependencies of the jsp compiler that is actuall used.
For some reason you have to include the slf4j jars in the dependencies or the jspc plugin refuses to work with some misleading error.

The specific version of Tomcats JSP compiler implementation defaults to 5.5.23 for the jspc-plugin 2.0-alpha-3.
If you need to use another version of thew Jasper compiler, you have to declare the following dependencies for the jspc-maven-plugin:
<dependency>
  <groupid>tomcat</groupid>
  <artifactid>jasper-compiler</artifactid>
  <version>5.5.27</version>
</dependency>
<dependency>
  <groupid>tomcat</groupid>
  <artifactid>jasper-compiler-jdt</artifactid>
  <version>5.5.27</version>
</dependency>
<dependency>
  <groupid>tomcat</groupid>
  <artifactid>jasper-runtime</artifactid>
  <version>5.5.27</version>
</dependency>

With this configuration your WAR should grow by a few bytes to a few MB. If you are using Servlet 2.4+ you do not need to change your web.xml to add the servlet mappings.

If you are stuck with Servlet API 2.3 you'll have to paste the generated web.xml fragement into your file.

In the next post I will extend JSP precompilation to projects using WAR dependencies, which poses some additional implications and problems.

No comments:

Post a Comment