Jasper Configuration & Precompilation
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
This page is written against Jakarta Pages 4.0 (Jakarta EE 11), Jakarta Servlet 6.1, Jakarta Expression Language 6.0 and
Jakarta Standard Tag Library 3.0, as implemented by the Jasper engine of Apache Tomcat 11.0.26 on Java 21, with side
notes for Eclipse Jetty 12.1.14 (jetty-ee11-jspc-maven-plugin 12.1.14, which is also Apache Jasper) and Eclipse
GlassFish 8.0.x (8.0.5 on Maven Central; its JSP engine is Eclipse WaSP). Everything was verified on 2026-10-08: the
parameter names and defaults against the Tomcat 11.0.26 Jasper how-to, the Jetty 12.1 operations guide and the GlassFish
deployment guide, and every Tomcat example by building it into a Maven WAR (the g7jasper* family of scratch WARs,
about thirty small variants of one web application) and running it on Tomcat 11.0.26 with curl; JspC was run through
Ant 1.10.15, through its command line and through the Jetty Maven plugin. Where a statement was only read in the
documentation and not run (everything about Jetty at run time and GlassFish), the page says so. Jasper is the part of
the container that turns a page into a servlet. The JSP Lifecycle and Translation
page explains what it does; this page explains how to tell it to do it differently, how to do the work before the first
request, and which settings belong in a developer’s Tomcat and which in a production one. The running scenario is the
Bookshelf, a small catalogue of books, here with a servlet that forwards to a catalogue page, two small pages that make
the settings visible, a tag file and a tag library.
Where Jasper Is Configured
Jasper is one servlet. In Tomcat it is the class org.apache.jasper.servlet.JspServlet, declared under the name jsp in
the global $CATALINA_BASE/conf/web.xml and mapped there to *.jsp and *.jspx. Every Jasper setting is an
init-param of that servlet (a handful are context parameters, covered below), so the question "where do I configure
it" is the question "where do I declare or redefine the jsp servlet". There are four places and they stack.
| Place | Scope | Notes (rows marked "observed" were reproduced) |
|---|---|---|
|
Every web application of the Tomcat instance |
The stock file already sets |
|
One web application |
Observed: the redefinition may omit the |
|
One web application, Tomcat only |
Identical format to |
Context parameters ( |
One web application |
Used for the pluggable interpreters and the page-context pool (see below). They are read from the |
Parameter names are case-sensitive in Tomcat. Observed: keepGenerated is silently ignored (the generated .java file was
kept) while keepgenerated works, and scratchdir and mappedfile are all lower case but genStringAsCharArray,
modificationTestInterval and compilerSourceVM are camel case. The Jetty operations guide says the same in other
words: if a value does not take effect, try a different capitalisation, because the names are inconsistent. A typo is
never an error, the parameter is simply ignored.
jsp servlet redefinition in WEB-INF/web.xml (g7jasperprod.war)<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param><param-name>development</param-name><param-value>false</param-value></init-param>
<init-param><param-name>genStringAsCharArray</param-name><param-value>true</param-value></init-param>
<init-param><param-name>trimSpaces</param-name><param-value>single</param-value></init-param>
<init-param><param-name>keepgenerated</param-name><param-value>false</param-value></init-param>
<init-param><param-name>xpoweredBy</param-name><param-value>true</param-value></init-param>
<init-param><param-name>classdebuginfo</param-name><param-value>false</param-value></init-param>
<init-param><param-name>mappedfile</param-name><param-value>false</param-value></init-param>
<load-on-startup>3</load-on-startup>
</servlet>
WEB-INF/tomcat-web.xml keeps web.xml portable (g7jaspertw.war; only development is set)<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param><param-name>development</param-name><param-value>false</param-value></init-param>
<load-on-startup>3</load-on-startup>
</servlet>
Observed with curl -D - http://localhost:18080/g7jasperprod/books: the response carried X-Powered-By: JSP/4.0
(xpoweredBy is on), the work directory held only the .class file and no .java file (keepgenerated is off), and
the page body came back 184 bytes long instead of 198 (trimSpaces). The default jsp servlet of the same Tomcat sends
no X-Powered-By header.
What Jasper 2 Adds: Pooling, Background Compilation and the Eclipse Compiler
The how-to’s introduction lists the reasons Jasper 2 behaves as it does, and each one maps to a parameter below.
-
Custom tag pooling. Tag handler instances are pooled and reused, which makes pages with many custom tags considerably faster (
enablePooling,poolTagsWithExtends). -
Background compilation. If a page that was already compiled changes, Jasper can compile the new version in the background while the old class keeps serving requests, and swap it in once compilation succeeds (
checkInterval). -
Recompile on a changed include. A page that is included at translation time (the
includedirective) is tracked, and the including page is recompiled when it changes. The dependency list is the_jspx_dependantsmap of the generated class; the behaviour is covered on the Includes, Forwards and Page Composition page. -
The Eclipse JDT compiler. The generated source is compiled with the Eclipse compiler (
ecj-4.40.jarin the Tomcat 11.0.26libdirectory), which loads its dependencies from the container class loader. No JDK is needed at run time. Ant andjavaccan still be used by settingcompiler.
Every Jasper Parameter and Its Default
The tables list all the init parameters documented for the Tomcat 11.0.26 Jasper servlet, with the documented default. The last column says what was done here: observed means the setting was changed in a scratch WAR and the effect was seen, docs means the behaviour is the documentation’s and was not exercised.
| Parameter | Default | Effect | Checked |
|---|---|---|---|
|
none |
An Ant |
docs |
|
|
The Java source level of the generated source |
observed |
|
|
The class file level of the generated classes. Observed: with the default the class file major version is 61 (Java 17) on a Java 21 run time; |
observed |
|
|
Only meaningful with Ant: compile in a separate JVM. The stock |
docs |
|
|
Compile with debugging information. Observed: the class file had |
observed |
|
built from the web application |
The compile class path. It only counts if the |
docs |
|
|
The name of the |
docs |
|
|
The encoding of the generated |
docs |
|
|
Fail when the |
docs |
|
|
Enforce that the object named in |
docs |
|
|
When |
docs |
|
|
Apply the JSP.1.6 quote-escaping rules to scriptlet expressions used as attribute values |
docs |
|
|
Apply the JSP.1.6 attribute quoting rules to EL in attribute values |
docs |
| Parameter | Default | Effect | Checked |
|---|---|---|---|
|
|
Development mode: pages are checked for modification, at most once per |
observed |
|
|
Do not check a page and its dependencies again within this interval; |
observed |
|
|
With |
observed |
|
off |
After a failed compilation, ignore |
observed |
|
|
The most pages loaded at once; beyond it the least recently used page is unloaded. Zero or less means no limit |
observed |
|
|
An idle page is unloaded after this time; zero or less means never |
observed |
| Parameter | Default | Effect | Checked |
|---|---|---|---|
|
|
Keep the generated |
observed |
|
the web application’s work directory |
Where generated sources and classes go. It must exist and be writable |
observed |
|
|
The default package of compiled pages |
observed |
|
|
The default package of handlers generated from tag files (the tag file classes of the example below ended up in |
docs |
|
|
One |
observed |
|
|
Do not generate the JSR-045 line table ( |
observed |
|
|
Also write the line table to a |
observed |
|
|
Include a fragment of the source in exception messages |
docs |
|
|
Prefix of the generated temporary variables (the tag plugin example below shows |
docs |
|
|
Name of the generated expression factory variable |
docs |
|
|
Name of the generated instance manager variable |
docs |
|
|
The base class of the generated servlets |
docs |
|
|
The service method the base class calls |
docs |
|
|
Add |
observed |
| Parameter | Default | Effect | Checked |
|---|---|---|---|
|
|
|
observed |
|
|
Generate text strings as |
observed |
| Parameter | Default | Effect | Checked |
|---|---|---|---|
|
|
Tag handler pooling. A compilation option: it does not change pages already compiled |
observed |
|
|
Pages with their own base class (the |
docs |
|
|
Obtain tag handler instances from the instance manager |
docs |
|
|
Destroy and recreate any tag buffer that grows beyond |
docs (accepted) |
|
|
The size of a tag buffer |
docs (accepted) |
| Parameter | Default | Effect | Checked |
|---|---|---|---|
|
|
A replacement |
docs |
|
|
The name of the request parameter that precompiles without invoking the page (specification 11.4.2). Observed: with the value |
observed |
The same parameters have different names in GlassFish (genStrAsCharArray) and a differently spelled Ant attribute in
JspC (smapSuppressed, poolingEnabled and so on); the JspC and GlassFish names appear in their own sections below.
Development Versus Production
The defaults are tuned for a developer who edits a page and reloads it: modification checks on, generated source kept,
debug information on. The how-to names the four settings to revisit for production and says the main optimisation is
precompilation, which is sometimes impossible (it gives the jsp-property-group feature as an example) or impractical, and
that the configuration of the servlet matters most in exactly those cases.
| Parameter | Development default | Production | Why |
|---|---|---|---|
|
|
|
Stops the on-access modification check. Observed: an edited page was then never recompiled (still the old text after more than 30 seconds) |
|
|
|
Slightly more efficient char arrays |
|
|
a high value, only if |
Fewer file system checks |
|
|
|
Removes unnecessary bytes. Observed on the Bookshelf catalogue page: 198 bytes with |
|
|
|
Not in the how-to’s list; keeps the work directory small. Keep it |
|
|
|
Smaller classes, no debugger support. The GlassFish deployment guide recommends the same set. A trade-off against being able to debug: see the testing and debugging page of this section |
Modification Detection in Development Mode
With the defaults, a page is checked for modification when a request arrives and at least modificationTestInterval
seconds have passed since the last check. The first request, the edit and a request inside the interval show the old
page, a request after the interval shows the new page and the old instance is destroyed (jspDestroy) before the new
one is initialised (jspInit).
g7jasper.war: stamp.jsp declares jspInit and jspDestroy that print to the log; the file was edited between the second and third request$ curl -s http://localhost:18080/g7jasper/stamp.jsp | tail -1
Bookshelf edition: TWO
$ sed -i '' 's/TWO/THREE/' webapps/g7jasper/stamp.jsp
$ curl -s http://localhost:18080/g7jasper/stamp.jsp | tail -1 # immediately: inside the 4 second interval
Bookshelf edition: TWO
$ sleep 5
$ curl -s http://localhost:18080/g7jasper/stamp.jsp | tail -1
Bookshelf edition: THREE
catalina.outg7jasper stamp.jsp: jspDestroy
g7jasper stamp.jsp: jspInit org.apache.jsp.stamp_jsp
Production Without Precompilation: Background Compilation
With development false the pages are never checked, so a changed page is only picked up by a redeploy. If pages must
change in place on a production server, set checkInterval above zero: Jasper then checks in the background and
compiles in the background, and the old class keeps serving until the new one is ready (the
availability point of the introduction). Observed with development=false and checkInterval=2
(g7jaspercheck.war): three requests in the nine seconds after the edit still returned the old page, the new text
appeared between nine and about twenty-five seconds after the edit, and in a second run after six seconds. A background check
runs when the container’s background processor runs, and the Engine’s backgroundProcessorDelay defaults to 10
seconds, so checkInterval cannot make the delay shorter than that cycle. The same edit in g7jasperprod.war (no
checkInterval) was still not visible after more than 30 seconds.
Recovering From a Failed Compilation
In development mode a page that fails to compile is not retried inside modificationTestInterval. Observed with
modificationTestInterval=600 (g7jrofoff.war and g7jrofon.war): a page with a syntax error in a scriptlet returned
500, was fixed, and kept returning 500 for as long as it was tried (25 seconds) without recompileOnFail. With
recompileOnFail=true the fixed page returned 200 about four seconds after the edit, the same delay as the default
interval, so the retry is allowed but not instantaneous. The documentation says the setting makes the next access
trigger a recompilation attempt; the observed behaviour was a delay of about four seconds.
Shaping the Output: trimSpaces and genStringAsCharArray
Template text is the HTML around the tags, and whitespace-only runs of it are what a page’s directives and loops leave
behind. The Bookshelf catalogue page is a good subject because it has two directives, a forEach and indented markup.
The Bookshelf servlet forwards to it and the response was measured with curl for each setting of trimSpaces.
WEB-INF/views/books.jsp<%@ page contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<!DOCTYPE html>
<html>
<body>
<h1>Bookshelf</h1>
<ul>
<c:forEach var="b" items="${books}">
<li>${b.title} by <c:out value="${b.author}"/> (${b.year})</li>
</c:forEach>
</ul>
</body>
</html>
trimSpaces |
Bytes | What was removed |
|---|---|---|
|
198 |
Nothing |
|
179 |
Template text that is only whitespace |
|
184 |
The same text, each run replaced by one space (so two directives on separate lines leave two spaces at the top) |
|
156 |
Also leading and trailing whitespace of text and runs of whitespace collapsed to one newline |
trimSpaces=extended, produced by curl -s http://localhost:18080/g7jtrime/books<!DOCTYPE html>
<html>
<body>
<h1>Bookshelf</h1>
<ul><li>Dune by Frank Herbert (1965)</li><li>Neuromancer by William Gibson (1984)</li></ul>
</body>
</html>
The page-level equivalent, trimDirectiveWhitespaces, is a page directive attribute and takes precedence over the
container setting for that page or tag file; it is covered with the other directives on the
JSP Directives page. Choose the container setting for a whole application and
the directive for the pages where whitespace is significant (a pre block or an inline-formatted fragment); extended
changes the layout of such text.
genStringAsCharArray changes how the static text is written. Observed on the two-line page shelf.jsp (the text
Shelf: ` and `class=): the default writes the text as string literals in the generated servlet and the setting writes
it through static char arrays.
g7jasper) and with genStringAsCharArray=true (g7jchars)// default
out.write("\n");
out.write("class=");
// genStringAsCharArray=true
out.write(_jspx_char_array_1);
...
static char[] _jspx_char_array_0 = "Shelf: ".toCharArray();
static char[] _jspx_char_array_1 = "\nclass=".toCharArray();
The Work Directory, Package Names and the Scratch Directory
Jasper writes generated files below the web application’s work directory, work/Catalina/localhost/<context>/ in Tomcat,
under the package org.apache.jsp, with the path of the page encoded into the package: WEB-INF/views/books.jsp becomes
org/apache/jsp/WEB_002dINF/views/books_jsp.java, because - is not legal in a Java name. Observed on g7jasper.war
after three requests: a .java and a .class file for each of books_jsp, shelf_jsp and stamp_jsp.
scratchdir moves the output elsewhere and generatedJspPackageName renames the package. Observed
(g7jpkg.war, scratchdir pointing at an existing directory, generatedJspPackageName=org.example.gen): the request
returned class=org.example.gen.shelf_jsp and the directory held org/example/gen/shelf_jsp.java and .class.
java.lang.IllegalStateException: The scratchDir you specified: [.../scratch-out] is unusable.
The failure appears as a 500 on the first request (Servlet.init() for servlet [jsp] threw exception), and after the
directory was created the next request succeeded without a redeploy.
The default class file level deserves a check on a new server. The how-to says compilerSourceVM and
compilerTargetVM default to 17, and the generated class files are Java 17 files (major version 61) even on a Java 21
run time; to use newer language features in scriptlets, set both parameters.
Controlling Which Pages Stay Loaded, and Warming Pages Up
Every page that has been requested is a loaded servlet instance. Two parameters bound that set. Observed with
jspIdleTimeout=2 (g7jidle.war): stamp.jsp was requested and, with no further requests, jspDestroy was logged
within 25 seconds (the unload happens in the background processor cycle); the next request ran jspInit again. With maxLoadedJsps=1 (g7jmax.war): after stamp.jsp, shelf.jsp and
books.jsp had been requested, jspDestroy of stamp.jsp, the least recently used page, was logged within the next 22
seconds; the unload is not instantaneous. Use these when a very large application would otherwise keep every page in
memory; they cost a reload for an unloaded page.
The opposite need is to avoid the slow first request. A servlet declaration can name a JSP file and give it a
load-on-startup value, which also gives a page a servlet name and a second URL.
jsp-file (g7jfile.war)<servlet>
<servlet-name>edition</servlet-name>
<jsp-file>/stamp.jsp</jsp-file>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>edition</servlet-name>
<url-pattern>/edition</url-pattern>
</servlet-mapping>
Observed: jspInit of stamp.jsp was logged during the deployment, before any request, and /g7jfile/edition and
/g7jfile/stamp.jsp both returned Bookshelf edition: ONE. The jsp-file element and servlet naming are described with the other
web.xml elements on the Servlet Fundamentals page.
The Optimisation Extension Points: Pooling, Tag Plugins and Interpreters
The how-to’s Optimisation section lists three extension points. All three change generated code and were checked by reading the generated source.
Tag Handler Pooling
The default generated servlet creates one TagHandlerPool per tag-and-attributes combination in _jspInit and
releases it in _jspDestroy. Observed on shelf.jsp: six references to TagHandlerPool with the default and none with
enablePooling=false (g7jnopool.war), where each use is a new org.apache.taglibs.standard.tag.rt.core.IfTag(). The
parameter is a compilation option, so it only affects pages compiled after it is set. The behaviour that makes pooling
a correctness concern (a handler instance reused across invocations) is the subject of the
Classic Custom Tags page.
Tag Plugins
A tag plugin replaces the handler of a tag with code inlined into the page. Plugins are registered in
WEB-INF/tagPlugins.xml; Jasper ships plugins for the JSTL core tags in the org.apache.jasper.tagplugins.jstl.core
package and a sample registration file inside jasper.jar.
WEB-INF/tagPlugins.xml registering three of the shipped JSTL plugins (g7jplug.war)<tag-plugins>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.rt.core.IfTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.If</plugin-class>
</tag-plugin>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.rt.core.OutTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.Out</plugin-class>
</tag-plugin>
<tag-plugin>
<tag-class>org.apache.taglibs.standard.tag.rt.core.ForEachTag</tag-class>
<plugin-class>org.apache.jasper.tagplugins.jstl.core.ForEach</plugin-class>
</tag-plugin>
</tag-plugins>
Observed with shelf.jsp (a c:set, a c:if and a c:out): the generated servlet of the default application referenced
IfTag and OutTag (two matches) and was 248 lines long; with the plugins it had no reference to either, was 207
lines long, and the c:if had become an inline if. The page output was identical.
c:if and c:out with the plugins (g7jplug); c:set, which was not registered, kept its handlerboolean _jspx_temp0=
((java.lang.Boolean) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${not empty shelf}", boolean.class, (jakarta.servlet.jsp.PageContext)_jspx_page_context, null)).booleanValue();
if (_jspx_temp0){
out.write("Shelf: ");
...
boolean _jspx_temp5 = org.apache.jasper.tagplugins.jstl.core.Out.output(out, _jspx_temp1, _jspx_temp2, _jspx_temp3, _jspx_temp4);
The plugin classes target the Tomcat JSTL implementation class names, org.apache.taglibs.standard.tag.rt.core.*, which
is also the package of the Jakarta Tags 3.0 implementation used here (org.glassfish.web:jakarta.servlet.jsp.jstl
3.0.1). Check the registration file in the jasper.jar of the version in use rather than copying one from an older
release.
The EL and String Interpreters
Two further extension points are chosen with context parameters named after the interface they replace.
org.apache.jasper.compiler.ELInterpreter names a class implementing the EL interpreter and
org.apache.jasper.compiler.StringInterpreter one that implements the String interpreter, which coerces attribute
strings. The how-to points at two implementations in org.apache.jasper.optimizations, and the Javadoc is blunt about
their cost: ELInterpreterTagSetters is described as not specification compliant, an interpreter that optimises a subset of tag
attribute setters (expressions that are solely a literal boolean, or a constant string coerced to the setter’s type)
and effectively hard-codes the fourth EL resolver; StringInterpreterEnum coerces strings to enums.
g7jopt.war)<context-param>
<param-name>org.apache.jasper.compiler.ELInterpreter</param-name>
<param-value>org.apache.jasper.optimizations.ELInterpreterTagSetters</param-value>
</context-param>
<context-param>
<param-name>org.apache.jasper.compiler.StringInterpreter</param-name>
<param-value>org.apache.jasper.optimizations.StringInterpreterEnum</param-value>
</context-param>
<context-param>
<param-name>org.apache.jasper.runtime.JspFactoryImpl.POOL_SIZE</param-name>
<param-value>-1</param-value>
</context-param>
<servlet>
<servlet-name>jsp</servlet-name>
<servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
<init-param><param-name>limitBodyContentBuffer</param-name><param-value>true</param-value></init-param>
<init-param><param-name>bodyContentTagBufferSize</param-name><param-value>256</param-value></init-param>
<load-on-startup>3</load-on-startup>
</servlet>
The last two entries are the how-to’s hint for limiting memory: POOL_SIZE=-1 disables PageContext pooling and
limitBodyContentBuffer caps tag buffers. They were set and the application ran; their performance effect was not
measured.
The effect of the two interpreters was observed with a small tag library for the Bookshelf (bk:label, whose handler has
a String text, an int copies and an enum level attribute). With literal expressions such as
text="${'Dune'}" the optimised interpreters generate direct setter calls, while the default one calls
PageContextImpl.proprietaryEvaluate and the property editor machinery.
bk:label attributes in lit.jsp, and the setter calls of the default application (g7jplain) against the optimised one (g7jopt)<bk:label text="${'Dune'}" level="${'WARN'}" copies="${'3'}"/>
// default
_jspx_th_bk_005flabel_005f0.setText((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${'Dune'}", java.lang.String.class, ...));
_jspx_th_bk_005flabel_005f0.setLevel((org.example.bookshelf.Level) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${'WARN'}", org.example.bookshelf.Level.class, ...));
_jspx_th_bk_005flabel_005f0.setCopies(((java.lang.Integer) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${'3'}", int.class, ...)).intValue());
// ELInterpreterTagSetters and StringInterpreterEnum
_jspx_th_bk_005flabel_005f0.setText("Dune");
_jspx_th_bk_005flabel_005f0.setLevel(org.example.bookshelf.Level.WARN);
_jspx_th_bk_005flabel_005f0.setCopies(3);
Two observations from the same experiment bound the claim. An expression that is not a literal (text="${shelf}") was
generated identically by both, so the optimisation is for constants only. And StringInterpreterEnum generated
LabelTag$Level.WARN for an enum nested in the tag handler class, which does not compile.
StringInterpreterEnum is active (Tomcat 11.0.26)An error occurred at line: [5] in the jsp file: [/label.jsp]
The nested type org.example.bookshelf.LabelTag$Level cannot be referenced using its binary name
Moving the enum to a top-level class (as in the working example) avoided the failure. Treat the interpreters as opt-in optimisations to be verified against the application’s pages, never as defaults.
Precompilation: Doing the Translation Before the First Request
A page is translated and compiled the first time it is requested, which is the slow first request and, more importantly, the moment a typo in a scriptlet turns into a 500 in front of a customer. Precompilation moves that work to build time. The specification names two different things under the word, and a third is a servlet container feature.
| Mechanism | What happens | Where it is defined |
|---|---|---|
The |
A request with the parameter asks the container to translate and compile that page now and not to run it |
Pages specification 11.4.2, implemented by Jasper (see below, and the lifecycle page of this section) |
Build-time translation and compilation (JspC) |
A tool turns the page sources into servlet classes plus the |
Pages specification 1.1.9 and Appendix A (non-normative); the tool is container-specific |
Load-on-startup of a page |
The container translates the page when the application starts, with no tool and no request |
Servlet |
The benefits the specification lists for build-time compilation are the removal of the start-up lag, a smaller
footprint (the Java compiler is not needed), and compilation in the context of the web application, so that relative
URLs in include directives, tag library references and translation-time actions are resolved. Its Appendix A shows
the whole idea in miniature: compile HelloWorld.jsp into a servlet class, declare it in web.xml with
servlet-class and a servlet-mapping to /HelloWorld.jsp, and package WEB-INF/web.xml and
WEB-INF/classes/... with no JSP source in the WAR. Every tool in this section produces that shape.
The jsp_precompile Request and Reserved Parameter Names
Specification 11.4.1 reserves every request parameter whose name starts with jsp; a page should ignore any parameter
that starts with jsp_ and containers and users should not invent names with the prefix. Section 11.4.2 defines
jsp_precompile: with no value or the value true or false the request is a precompilation request and must not be
delivered to the page (the value true or none is the suggestion to compile, and the container may
ignore it), and any other value is illegal and yields a 500. The lifecycle page of this section verified all of that
against Tomcat 11.0.26 (see the Precompilation section).
The Jasper-specific part is that the parameter name is configurable (jspPrecompilationQueryParameter, observed above),
and that the request does not deliver anything to the page: on g7jpq.war ?precomp=true returned 200 with an empty body.
A build can use the request as a smoke test (request every page once with the parameter after deployment, to translate and compile all of them and see compile errors before users do), but it needs a list of the pages and a running server; JspC does the same job without a server.
JspC: the Pipeline
JspC is Jasper without the servlet container. It translates every JSP (and tag file) under a web application directory into Java source, optionally compiles it, and writes the servlet declarations and mappings that bind each generated class to the URL of its page.
in the web application"] --> jspc["JspC
Ant task, command line,
Maven plugin"] jspc --> java["generated Java source
org.apache.jsp.*"] jspc --> map["servlet and servlet-mapping
declarations"] java --> comp["compile
javac, ECJ,
or JspC compile=true"] comp --> cls["WEB-INF/classes
org/apache/jsp/*.class"] map --> wx["WEB-INF/web.xml
merged or included"] cls --> war["WAR"] wx --> war war --> run["container: each page URL
is a plain servlet mapping,
no translation at run time"]
The ordering matters: JspC reads the tag libraries and TLDs the pages use, so the application’s libraries must already be
in WEB-INF/lib and its own classes in WEB-INF/classes when it runs. A page’s relative references are resolved against
the web application root (uriroot).
JspC With the Ant jasper Task
The how-to calls Ant the preferred way to compile a web application with JspC, and ships the script, which is also
included in the Tomcat deployer download. It imports bin/catalina-tasks.xml, which defines the jasper task, runs
the task to write Java source and a generated_web.xml, then compiles the source with the javac task and a class path
of the application and Tomcat libraries. The output is then added to web.xml by hand, or by the task.
g7jasperpre (the how-to script with addWebXmlMappings and release="21" added; the cleanup target is unchanged)<project name="Webapp Precompilation" default="all" basedir=".">
<import file="${tomcat.home}/bin/catalina-tasks.xml"/>
<target name="jspc">
<jasper validateXml="false"
uriroot="${webapp.path}"
addWebXmlMappings="true"
webXmlInclude="${webapp.path}/WEB-INF/generated_web.xml"
outputDir="${webapp.path}/WEB-INF/src" />
</target>
<target name="compile">
<mkdir dir="${webapp.path}/WEB-INF/classes"/>
<mkdir dir="${webapp.path}/WEB-INF/lib"/>
<javac destdir="${webapp.path}/WEB-INF/classes" debug="on" failonerror="false"
srcdir="${webapp.path}/WEB-INF/src" excludes="**/*.smap" release="21">
<classpath>
<pathelement location="${webapp.path}/WEB-INF/classes"/>
<fileset dir="${webapp.path}/WEB-INF/lib"><include name="*.jar"/></fileset>
<pathelement location="${tomcat.home}/lib"/>
<fileset dir="${tomcat.home}/lib"><include name="*.jar"/></fileset>
<fileset dir="${tomcat.home}/bin"><include name="*.jar"/></fileset>
</classpath>
<include name="**"/>
<exclude name="tags/**"/>
</javac>
</target>
<target name="all" depends="jspc,compile"/>
<target name="cleanup">
<delete>
<fileset dir="${webapp.path}/WEB-INF/src"/>
<fileset dir="${webapp.path}/WEB-INF/classes/org/apache/jsp"/>
</delete>
</target>
</project>
The run, on the exploded Bookshelf WAR, with Ant 1.10.15 launched directly from its two jars (the command the how-to
gives, ant -Dtomcat.home=... -Dwebapp.path=..., is the same):
g7jasper.war (abridged)jspc:
[jasper] INFO: Generation completed with [0] errors in [132] milliseconds
compile:
[javac] Compiling 4 source files to .../webapp/WEB-INF/classes
all:
BUILD SUCCESSFUL
Result: WEB-INF/classes/org/apache/jsp/{label,shelf,stamp}_jsp.class and WEB_002dINF/views/books_jsp.class, the Java
source under WEB-INF/src, and a web.xml into which the task merged, between two marker comments, a servlet and a
servlet-mapping for each page.
WEB-INF/web.xml by addWebXmlMappings="true" (abridged to two pages)<!-- JSPC servlet mappings start -->
<servlet>
<servlet-name>org.apache.jsp.stamp_jsp</servlet-name>
<servlet-class>org.apache.jsp.stamp_jsp</servlet-class>
</servlet>
...
<servlet-mapping>
<servlet-name>org.apache.jsp.stamp_jsp</servlet-name>
<url-pattern>/stamp.jsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>org.apache.jsp.WEB_002dINF.views.books_jsp</servlet-name>
<url-pattern>/WEB-INF/views/books.jsp</url-pattern>
</servlet-mapping>
<!-- JSPC servlet mappings end -->
Note the second mapping: a page under WEB-INF is mapped to its own path so that the servlet’s
getRequestDispatcher("/WEB-INF/views/books.jsp").forward(...) finds it, which is exactly how the Bookshelf servlet
reaches its view.
The WAR was then assembled from the output with WEB-INF/src, every .jsp and the JSP of WEB-INF/views removed, so
the only thing that could serve the pages was the compiled classes. Observed on g7jasperpre.war: /books,
/shelf.jsp, /stamp.jsp and /label.jsp all returned 200 with the same output as before, shelf.jsp?x=1 also returned
200, and the work directory of the application stayed empty (no .java, no .class): the container did not translate or
compile anything.
The how-to’s hints about the task are worth reading with the experiment in mind.
-
addWebXmlMappingsandwebXmlIncludego together. The how-to presentsaddWebXmlMappingsas an option that mergesgenerated_web.xmlintoweb.xmlautomatically. Observed on Tomcat 11.0.26:addWebXmlMappings="true"withoutwebXmlIncludeends the build withBUILD FAILED ... java.lang.NullPointerException at org.apache.jasper.JspC.mergeIntoWebXml(JspC.java:1270). With both, the merged block was written and no separategenerated_web.xmlremained in the directory. -
Locale and verbosity. With a non-English default locale the JspC messages are localised (the first run printed Spanish INFO lines); add
-Duser.language=enwhen the output is parsed. -
Do not stop at the first error.
failOnError="false"withshowSuccess="true"lists every page that converted, which helps when a legacy application has many broken pages. -
Java level. The how-to says to add
sourceandtargetattributes to thejavactask to pick the Java version of the classes, and to setdebug="off"for production (the build file above usedrelease="21"). -
Regenerate on every Tomcat upgrade. The hint is explicit: when switching to another Tomcat release, regenerate and recompile the JSPs with the new Tomcat. The generated classes extend the Jasper runtime base class and call its internals; a class generated by one release is not guaranteed to run on another.
The task also takes more attributes than the how-to uses. They are the setters of the org.apache.jasper.JspC class, so
the Javadoc lists them. The ones a Bookshelf build needs most often: compile (compile inside JspC, below), outputDir,
uriroot, jspFiles (a list of pages instead of the whole tree), package, webXml, webFragmentXml (a complete
web-fragment.xml for packaging the pages in a library JAR), failOnError, threadCount, trimSpaces,
genStringAsCharArray, poolingEnabled, mappedFile, classDebugInfo, smapSuppressed, smapDumped,
compilerSourceVM, compilerTargetVM, useNonstandardTagOptimizations and blockExternal.
JspC From the Command Line, and the compile Option
Tomcat 11.0.26 no longer ships a jspc script in bin, but the class has a main method and prints its options with
-help. Observed: running it needs Ant on the class path, because the class extends the Ant Task class
(NoClassDefFoundError: org/apache/tools/ant/Task without it).
web.xml (the class path is the Tomcat lib directory, tomcat-juli.jar and ant-1.10.15.jar; the output directory must exist)$ mkdir out
$ java -cp "$CATALINA_HOME/lib/*:$CATALINA_HOME/bin/tomcat-juli.jar:ant-1.10.15.jar" \
org.apache.jasper.JspC -uriroot webapp -d out -compile -webxml out/web.xml -s -l
Observed: out/ held the .java and .class files of the four pages and out/web.xml; no separate Java compiler step was
needed (-compile uses the Eclipse compiler). The options are those printed by -help: -webapp/-uriroot, -d, -p
(package), -c (class name of the first page), -mapped, -die, -uribase, -compile, -failFast, -webinc (partial
mappings), -webfrg (a web-fragment), -webxml, -addwebxmlmappings, -classpath, -xpoweredBy, -trimSpaces,
-javaEncoding, -source, -target and -threadCount. Three findings from the run:
-
The directory of
-webxmlis not created: pointing it at a directory that did not exist ended withFileNotFoundException: cli/out/web.xml (No such file or directory). -
-helpstill prints "default 1.8" for-sourceand-target; the classes generated were Java 17 (major version 61). -
JspC does not emit the line-number table for debuggers unless asked. Observed: with
compileon and the default forsmapSuppressedthe class had noSourceDebugExtensionattribute, and withsmapSuppressed="false"(the Ant attribute; the servlet parameter issuppressSmap) it had two. This is the how-to’s remark that SMAP information is only in the classes "ifsuppressSmapis false andcompileis true".
build2.xml, run on the exploded WAR)<jasper validateXml="false" uriroot="${webapp.path}" outputDir="${out.dir}" compile="true"
smapSuppressed="false" webXml="${out.dir}/web.xml" failOnError="true"/>
Tag Files and Libraries Under JspC
Tag files under WEB-INF/tags are translated and compiled with the pages. Observed with a badge.tag and a page that used
it: the output contained org/apache/jsp/tag/web/badge_tag.class (in the org.apache.jsp.tag.web package, a sub-package
of generatedTagFilePackageName), JspC also wrote a stray badge_tag.class next to the generated source (a reason to
delete WEB-INF/src before packaging, as the how-to’s cleanup target does), and the WAR with the tag file source and
the page source both removed still rendered the tag. The how-to’s javac task excludes tags/**, a pattern that
matches only a top-level tags directory of the source tree and not org/apache/jsp/tag/web, so it excluded nothing
in this experiment. The tag file features themselves are on the Tag Files and Layouts page, and
the specification’s remark that a tag file can also be packaged as a precompiled handler is in section 8.4.4.
Jetty: The JSP Module and the JspC Maven Plugin
Jetty uses Apache Jasper for JSP. This section is from the Jetty 12.1 operations and programming guides, from the contents of the 12.1.14 artifacts, and from one experiment: the JspC plugin was run, and the WAR it produced was deployed on Tomcat. Jetty itself was not started, so the run-time statements are documentation and artifact inspection.
JSP support is a module per EE level, ee8-jsp to ee11-jsp (the ee11-jsp module depends on ee11-servlet,
ee11-annotations and ee11-apache-jsp). Jetty identifies the JSP servlet by the attribute id="jsp" in the default
descriptor. That descriptor, webdefault-ee11.xml in jetty-ee11-webapp-12.1.14.jar, declares the servlet jsp
with the class org.eclipse.jetty.ee11.jsp.JettyJspServlet, sets xpoweredBy to false and, notably,
compilerTargetVM and compilerSourceVM to 1.8, loads it with load-on-startup 0, and maps it to *.jsp, *.jspf,
*.jspx and *.xsp in lower and upper case. An application changes it by re-declaring a servlet with the same
servlet-name and id="jsp" in its web.xml and adding init-param entries, for example keepgenerated or the
async-supported element (the JSP servlet does not support asynchronous processing by default). Logging of the
org.apache.jasper packages is bridged to Jetty logging. The parameters are Jasper’s, so the table above applies; the
Jetty guide lists them with Jetty’s defaults and an important caveat: parameter spellings differ in some places from
Tomcat’s (the guide spells scratchDir, mappedFile and genStrAsCharArray), and the instruction is to try all
lower case if a value does not take effect.
web.xml (from the Jetty 12.1 guide; not run here)<servlet id="jsp">
<servlet-name>jsp</servlet-name>
<init-param>
<param-name>keepgenerated</param-name>
<param-value>true</param-value>
</init-param>
</servlet>
The Jetty JspC Maven Plugin
For Jakarta EE 11 the plugin is org.eclipse.jetty.ee11:jetty-ee11-jspc-maven-plugin 12.1.14. It precompiles the pages and
works with the maven-war-plugin so that the classes and the merged descriptor go into the WAR. The plugin’s own
documentation recommends putting it in a profile that is switched on only for a production build.
prod profile that precompiles the Bookshelf (pom.xml of g7jasperjetty; run with mvn -Dprod clean package)<profiles>
<profile>
<id>prod</id>
<activation>
<property><name>prod</name></property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.eclipse.jetty.ee11</groupId>
<artifactId>jetty-ee11-jspc-maven-plugin</artifactId>
<version>12.1.14</version>
<executions>
<execution>
<id>jspc</id>
<goals>
<goal>jspc</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<webXml>${project.basedir}/target/web.xml</webXml>
</configuration>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Observed: the plugin ran after the Java compilation and before the test resources step, compiled
stamp.jsp,shelf.jsp,WEB-INF/views/books.jsp,label.jsp from the default includes (**/*.jsp, **/*.jspx) and reported
Generation completed with [0] errors; the build printed three The XML schema [...] could not be found warnings that did
not matter. The WAR it produced contained WEB-INF/classes/org/apache/jsp/*.class for all four pages, a WEB-INF/web.xml
(the merged file target/web.xml) with servlet and servlet-mapping entries for each page, and also one that Tomcat
does not need: <context-param>org.eclipse.jetty.jsp.precompiled = true</context-param>, which tells Jetty’s
JSP servlet to expect precompiled classes. The JSP sources stayed in the WAR, because the war plugin copies the webapp
directory. The WAR was then deployed on Tomcat 11.0.26 (g7jasperjetty): /books, /shelf.jsp, /stamp.jsp and
/label.jsp all returned 200 and the work directory stayed empty, so the classes the Jetty plugin generates run on
Tomcat’s Jasper too. That portability is a convenience of this experiment; the classes extend the Jasper base class
of the plugin’s Jasper version, and the how-to’s rule of regenerating on a release change still applies.
| Parameter | Default | Meaning |
|---|---|---|
|
|
Root of the JSPs and tags |
|
|
The |
|
|
Where the generated declarations are written; merged output goes to the same directory |
|
|
Whether to merge the fragment into the source |
|
none |
A marker in the source |
|
|
Which files are processed |
|
|
Where the application classes are read and the generated classes written |
|
|
Put |
|
|
Keep the generated |
|
|
Also scan class path directories and JAR manifests for TLDs |
|
depends on the plugin version |
Java level of the pages and classes |
|
JARs named like taglibs or jstl (two patterns) |
Patterns, separated by a vertical bar, of container-path JARs that contain TLDs |
|
the |
All setters of |
For a WAR that overlays another WAR, the plugin’s guide separates the work into an exploded execution of the war plugin in
generate-resources (to unpack the overlay) and a war execution in package (to pack the result), and points the plugin’s
webXml at the unpacked descriptor, so that the plugin can see the overlaid resources.
GlassFish: jsp-config, --precompilejsp and jspc
Eclipse GlassFish runs JSP on Eclipse WaSP (eclipse-ee4j/wasp, an implementation of Jakarta Pages; no separate Maven coordinate is
published for it, so only the repository is cited). This section is from the GlassFish deployment and development guides published as latest on glassfish.org and was not
run here: GlassFish was not installed in the scratch environment.
An application configures the engine in WEB-INF/glassfish-web.xml with a jsp-config element that holds property
subelements, so the settings stay out of the portable web.xml.
glassfish-web.xml (from the GlassFish deployment guide; not run here)<glassfish-web-app>
<jsp-config>
<property name="development" value="false"/>
<property name="genStrAsCharArray" value="true"/>
<property name="trimSpaces" value="true"/>
<property name="keepgenerated" value="false"/>
</jsp-config>
</glassfish-web-app>
The property names are close to Jasper’s, with GlassFish-specific additions and different defaults. The ones that matter
here, from the guide’s table: development (default true), checkInterval (0), modificationTestInterval
(default 0 there, so a page is checked on every access in development mode), reload-interval (0; -1 disables
checks and recompilation), mappedfile (true), trimSpaces (false, and only true or false), suppressSmap,
dumpSmap, classdebuginfo, keepgenerated (true with JDK 5 and before and for jspc, otherwise false),
genStrAsCharArray (false) and genStrAsByteArray (true: text as bytes encoded with the page encoding, if the page is not
buffered), enablePooling (true), enableTldValidation, scratchdir, usePrecompiled (false; when true an accessed
page is not compiled and its precompiled servlet class, assumed to be in WEB-INF/lib or WEB-INF/classes, is used),
initialCapacity, httpMethods, ignoreJspFragmentErrors, defaultBufferNone, xpoweredBy (default true in GlassFish,
against false in Tomcat), saveBytecode, javaEncoding, compilerSourceVM, compilerTargetVM, fork, compiler and
classpath. The guide’s performance recommendation is the same list as above, expressed as GlassFish property values:
development false (or true with a large modificationTestInterval), mappedfile false, trimSpaces true,
suppressSmap true, classdebuginfo false, and fork false on Solaris.
GlassFish has three ways to compile JSP files: automatically at run time, with the --precompilejsp option of
asadmin deploy, and with the jspc command-line tool in glassfish/bin (glassfish/bin/jspc -help lists its options).
A web application that was precompiled with jspc is used with usePrecompiled set to true.
A Known Issue: Very Large Pages
The how-to lists one known issue: a JVM defect (bug 6294277, reported against Tomcat as bug 39089) can cause
java.lang.InternalError: name is too long to represent when compiling very large JSPs. The workarounds are to reduce the
size of the page, which is also the right fix for readability (split it into fragments with
includes or tag files),
or to disable SMAP generation with suppressSmap set to true. The line table is exactly what the debugger uses, so the second
workaround trades debuggability for compilability.
The Bookshelf in Production: Putting It Together
A reasonable production arrangement for the Bookshelf, as a checklist built from the sections above.
-
Precompile in the build. Use JspC (the Ant task,
-compilefrom the command line, or the Jetty plugin in aprodprofile) and package the classes with the mergedweb.xml. Do not ship the JSP sources unless an operator needs them, and deleteWEB-INF/srcbefore packaging. Then the first request cost, and a class of translation errors, are gone. -
Check that nothing is translated at run time. After deployment, request the pages and confirm the work directory has no
.javaor.classfiles for them (observed ong7jasperpre). -
Keep production settings for what is still translated at run time. Pages that cannot be precompiled, such as pages covered by a
jsp-property-groupor generated at run time, use the how-to’s four settings (developmentfalse, andtrimSpaces,genStringAsCharArray,modificationTestIntervalas needed), acheckIntervalif they must change in place, andjspIdleTimeoutormaxLoadedJspsif there are very many. -
Put the settings in the right file. A portable
web.xmlfor the application and, when it must be Tomcat specific,tomcat-web.xml; a global change inconf/web.xmlonly for a deliberate policy across every application. -
Rebuild on every container upgrade. Precompiled classes are bound to the Jasper runtime they were generated against; move from Tomcat 10.1 to 11 (the Jakarta namespace has been
jakarta.*since Tomcat 10) by regenerating, never by copyingWEB-INF/classes/org/apache/jsp. -
Keep a development profile with the defaults. Developers want modification checks, the generated source and the line table; a Maven or Gradle profile that precompiles only with
-Dprod(as the Jetty guide recommends) keeps both.
Pitfalls and Error Names
| Symptom | Cause | Fix |
|---|---|---|
An edited page never changes (observed) |
|
Wait for the interval, set |
A setting has no effect and there is no error (observed) |
The name is wrong or in the wrong case ( |
Copy the name from the table; names are case-sensitive and a typo is ignored |
|
|
Create the directory with the right permissions |
|
The Ant task has |
Set both attributes |
|
The output directory was not created |
Create it first |
|
JspC extends the Ant |
Add |
Precompiled pages still compiled at run time (or missing mappings) |
The generated |
Merge them ( |
No line numbers in an exception or debugger for a precompiled page (observed) |
JspC leaves |
Set |
|
|
Move the enum to a top-level class, or do not use the interpreter |
Tag handler state leaks between requests, or |
Pooling and the |
See the classic tags page; set |
|
Only none, |
Use |
Generated classes from the old container fail after an upgrade |
Precompiled classes depend on the Jasper runtime and on the |
Regenerate with the new release’s JspC and recompile |
|
A very large page and JVM bug 6294277 |
Split the page, or set |
Jetty ignores a Tomcat-style parameter spelling |
Jetty’s guide uses different spellings in places |
Try all lower case, as the Jetty guide suggests, and test the effect |
What Changed Recently
| Change | Effect | Evidence |
|---|---|---|
Jakarta namespace |
The generated servlets import |
Generated source of |
Tomcat 11 Jasper implements Jakarta Pages 4.0 |
The engine and the expression factory follow Pages 4.0 and EL 6.0; |
How-to 11.0.26 introduction; observed class version 61 with a value of |
No |
JspC is run through Ant (the how-to’s script, with |
|
The Eclipse compiler is bundled |
No JDK is needed on a production server; |
|
JspC per Jakarta EE level in Jetty |
A plugin per release ( |
Jetty 12.1 guides; Maven Central |
Jetty plugin writes a Jetty-only context parameter |
|
Observed in the merged descriptor |
Tomcat 9 and 10.1 still exist |
Tomcat 11 is the version of this page; 10.1.60 and 9.0.x ("end of support no earlier than 31 March 2027") are in service, and each has its own Jasper how-to |
Tomcat which-version page, verified 2026-10-08 |
Source: Apache Tomcat — Which Version?
Where the Books Are Outdated
-
Scripts and task names. Older material commonly describes a
jspclauncher script and earlier Ant task names. Tomcat 11.0.26 ships nojspcscript; the task is namedjasperand imported throughcatalina-tasks.xml, and the how-to calls Ant the preferred route. -
A JDK on the server. Older descriptions often assume the container compiles with the JDK’s
javacand therefore needs a JDK at run time; Jasper 2 compiles with the bundled Eclipse compiler, and precompilation removes the compiler from the run-time path altogether (the specification’s own list of the benefits). -
Hand-merging
web.xml. The older workflow is to paste the generated mappings intoweb.xml. The Ant task’saddWebXmlMappingsand the Maven plugin’s merge do it; the one trap is thewebXmlIncludepairing noted above. -
Package names. Examples from the
javax.servletera refer to the attributejavax.servlet.context.tempdir. The attribute isjakarta.servlet.context.tempdirnow (the Jetty guide’sscratchDirdescription still saysjavax). -
jsp_precompileand reserved names. This part of the specification is unchanged in Pages 4.0 (11.4), so old material on the parameter is still right; only the class names and defaults around it have changed. -
Defaults. Check any default quoted in older material against the tables above: in Tomcat 11.0.26 the source and target levels are 17,
forkisfalsein the stockconf/web.xmlandxpoweredByisfalse. GlassFish defaultsxpoweredBytotrue.
Two inconsistencies were found in the official documentation while preparing the page: the how-to’s addWebXmlMappings
paragraph leaves out that webXmlInclude is required (a NullPointerException otherwise), and the Jetty guide names the
servlet class org.eclipse.jetty.jsp.JettyJspServlet while the 12.1.14 default descriptor uses
org.eclipse.jetty.ee11.jsp.JettyJspServlet; it also says javax.servlet.context.tempdir and names a genStrAsCharArray
parameter that is GlassFish’s spelling.
Related Pages
The lifecycle that Jasper implements is on the JSP Lifecycle and Translation page. Container-wide
page behaviour that does not need Jasper parameters (property groups, encodings, scripting) is on
JSP Configuration and Property Groups. Reading the generated sources, the line table
and the debugger use of suppressSmap, and testing pages, are the subject of the Testing and Debugging page of this
section, and the deployment and WAR layout questions that surround precompilation are on
Servlet Fundamentals and Getting Started. The error pages that show a
compile failure to a user are on the JSP Error Handling page.
References
-
Apache Tomcat 11 — Jasper 2 JSP Engine How-To, Configuration
-
Apache Tomcat 11 — Jasper 2 JSP Engine How-To, Production Configuration
-
Apache Tomcat 11 — Jasper 2 JSP Engine How-To, Web Application Compilation
-
Apache Tomcat 11 — The Engine Component, backgroundProcessorDelay
-
Apache Tomcat 11 Javadoc — package org.apache.jasper.tagplugins.jstl.core
-
Jakarta Pages 4.0 — 8.4.4 Packaging as Precompiled Tag Handlers
-
Eclipse Jetty 12.1 Programming Guide — Jetty JspC Maven Plugin
-
Eclipse Jetty 12.1 Programming Guide — Precompiling only for Production Build
-
Eclipse Jetty 12.1 Programming Guide — Precompiling JSPs with Overlaid Wars
-
Eclipse GlassFish Application Development Guide — Options for Compiling JSP Files