9.1 Dealing with Syntax Errors
The first type of error you will encounter is the one
you, or your coworkers, create by simple typos; in other
words, syntax errors. The JSP container needs every JSP
element to be written exactly as it's defined in the
specification in order to process the JSP page. When it finds
something that's not right, it tells you. How easy it is to
understand what it tells you depends on the type of error, the
JSP container implementation, and sometimes, on how fluent you
are in computer gibberish.
9.1.1 Element Syntax Errors
All container implementations
report syntax errors, but details such as the wording of the
messages, how much information the message contains, and where
the message is written differ between them. In this chapter, I
show examples only of the messages produced by Tomcat.
Let's first look at how Tomcat reports some
typical syntax errors in JSP directives and action elements.
Example
9-1 shows a version of the easy.jsp page from Chapter
5 with a syntax error.
Example 9-1. Improperly
terminated directive (error1.jsp) <%@ page contentType="text/html" >
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<html>
<head>
<title>JSP is Easy</title>
</head>
<body bgcolor="white">
<h1>JSP is as easy as ...</h1>
1 + 2 + 3 = <c:out value="${1 + 2 + 3}" />
</body>
</html>
The syntax error here is that the page
directive on the first line isn't closed properly with
%>; the percent sign is missing. Figure
9-1 shows what Tomcat has to say about it.
Tomcat reports the error by sending an error
message to the browser. This is the default behavior for
Tomcat, but it's not mandated by the JSP specification. The
specification requires only that a response with the HTTP status code
for a severe error (500) is returned, but how a JSP container
reports the details is vendor-specific. For instance, the
error message can be written to a file instead of the browser.
If you use a container other than Tomcat, check the container
documentation to see how it reports these types of errors.
The actual error message in Figure
9-1 is what is called an exception
stack trace. When something
goes really wrong in a Java method, it typically throws an
exception. An exception is a special Java object, and throwing
an exception is the method's way of saying it doesn't know how
to handle a problem. Sometimes another part of the program can
take care of the problem in a graceful manner, but in many
cases the best that can be done is to tell the user about it
and move on. That's what the Tomcat container does when it
finds a problem with a JSP page during the translation phase;
it sends the exception stack trace to the browser. The stack
trace contains a message about what went wrong and where the
problem occurred. The message is intended to be informative
enough for a user to understand, but the actual trace
information is of value only to a programmer. As you can see
in Figure
9-1, the message is: /ch9/error1.jsp(0,33) Unterminated <%@ tag
The first part of the message is the name of
the JSP page. The numbers within parentheses indicate on which
line and character position in the file the error was found
(both the line and the position are numbered from 0), and then
the message states what the problem is. So this message tells
us that a directive (an element starting with <%@)
on the first line isn't terminated as expected at position 33.
In this case it's both the correct diagnosis and the right
location.
It's not always this easy to interpret the
error message. Example
9-2 shows another version of easy.jsp with a
different syntax error.
Example 9-2. Improperly
terminated action (error2.jsp) <%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<html>
<head>
<title>JSP is Easy</title>
</head>
<body bgcolor="white">
<h1>JSP is as easy as ...</h1>
1 + 2 + 3 = <c:out value="${1 + 2 + 3}" >
</body>
</html>
The syntax error here is almost the same as
the "unterminated tag" in Example
9-1, but now it's the <c:out> action element that's not terminated properly
(it's missing the closing slash required for an empty
element). The message reported by Tomcat in this case is: End of content reached while more parsing required: tag nesting error?
This message isn't really helpful, because
the line and position information is missing, and it gives no
clue about which action element is in error. The error in this
case is that, since the action element doesn't have a body, a
single tag ending with /> should be used, but in
Example
9-2 it's terminated with just >. Because
that's valid syntax for a JSP action that contains a body, the
JSP container can't tell that it's a syntax error at this
point. Instead, it treats it as the opening tag for an element
with a body and complains that it can't find the closing tag
before the file ends. The error message could be a lot more
informative, for instance include the name of the action
element that is missing the closing tag, and maybe even the
position of the opening tag. Let's hope this is fixed in the
Tomcat version you use.
Another common error is a typo in an attribute name. The value
attribute for the <c:out> action is misspelled
in Example
9-3.
Example 9-3. Mistyped
attribute name (error3.jsp) <%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<html>
<head>
<title>JSP is Easy</title>
</head>
<body bgcolor="white">
<h1>JSP is as easy as ...</h1>
1 + 2 + 3 = <c:out valu="${1 + 2 + 3}" />
</body>
</html>
Tomcat reports the problem like this: /ch9/error3.jsp(10,16) According to the TLD attribute value is mandatory
for tag out
In this case, the typo is in the name of a
mandatory attribute, so Tomcat reports it as missing. If the
typo is in the name of an optional attribute, Tomcat reports
it as an invalid attribute name.
Example
9-4 shows a type of error that results in a message that
is hard to figure out unless you know what's going on.
Example 9-4. Missing end
quote in attribute value (error4.jsp) <%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<html>
<head>
<title>JSP is Easy</title>
</head>
<body bgcolor="white">
<h1>JSP is as easy as ...</h1>
1 + 2 + 3 = <c:out value="${1 + 2 + 3} default="Doh!" />
</body>
</html>
If you look carefully at the
<c:out> element, you see that the closing quote
for the value attribute is missing. If another
attribute is specified for the same element, like the
default attribute used here, Tomcat reports the
problem like this: /ch9/error4.jsp(10,56) Attribute Doh! has no value
What's happening is that Tomcat includes
everything up to the second quote as the value of the
value attribute. It then assumes that the next word
(Doh! in this example) is an attribute, and because
it's not followed by an equal sign, it reports that it doesn't
have a value.
Let's close this section with one of the most
frustrating scenarios of all, namely forgetting to include a taglib directive for the tag
library used in the page. This doesn't result in an error
message at all, but all custom action elements are treated as
template text and just added to the response without being
executed. Before pulling all your hair trying to understand
why none of your actions are being executed, make sure you
have included the taglib directive. An easy way to
see if this is the problem is to use the browser's
View Source function: if the source for the
response sent to the browser includes action elements, they
where not processed by the web container, most likely due to a
missing or incorrect taglib directive.
The examples here are the most common ones
for JSP element syntax errors. Tomcat can give you pretty good
information about what's wrong in most of these cases, but
this is still an area where I expect many improvements to be
implemented in later versions of Tomcat as well as in other
JSP containers. The JSP authoring tools that emerge now may
also help. By providing GUI-based interfaces that generate the
action elements automatically, they can eliminate this type of
syntax problem.
9.1.2 JSTL Expression Language
Syntax Errors
How well JSTL EL syntax errors are reported
varies between JSTL implementations and web containers,
because the EL isn't yet part of the JSP specification. The
JSTL Reference Implementation (RI) is doing a pretty good of
job of reporting EL syntax errors. In a web container that
implements an optional JSP feature (described in Chapter
21), it even includes information about the exact line and
column in the JSP source file. Unfortunately, Tomcat 4 doesn't implement this feature
yet, but will hopefully do so in a future version.
We look at a few EL syntax error examples in
this section so you can see what to expect when you use the
JSTL RI and Tomcat 4.0.4. Later versions, and other
implementations may do better (or worse), but these examples
illustrate what to look for.
Example
9-5 shows a page with a subtle syntax error: the curly
braces are missing in the EL expression.
Example 9-5. Missing both
curly braces (error5.jsp) <%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<html>
<head>
<title>JSP is Easy</title>
</head>
<body bgcolor="white">
<h1>JSP is as easy as ...</h1>
1 + 2 + 3 = <c:out value="$1 + 2 + 3" />
</body>
</html>
This is an easy mistake to make, but it's not
recognized as a syntax error at all. To the EL, this means
that the value is a plain-text value, not an expression. When
used with the <c:out> action, it's easy to
figure out what's wrong because the text value is added to the
response as-is instead of the being evaluated: $1 + 2 +
3. But if you make this mistake with an attribute value
that should provide the action with input to process in some
way, the problem may not be so easy to spot. For instance, if
you forget the curly braces for the <c:forEach>
items attribute, it takes it as a text value and
loops once over its body with the text as a single element.
Let's see what happens if you forget only the
end curly brace, as shown in Example
9-6.
Example 9-6. Missing end
curly brace (error6.jsp) <%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<html>
<head>
<title>JSP is Easy</title>
</head>
<body bgcolor="white">
<h1>JSP is as easy as ...</h1>
1 + 2 + 3 = <c:out value="${1 + 2 + 3" />
</body>
</html>
Tomcat 4 and the JSTL RI report this error as
shown in Figure
9-2.
The error message is produced by the JSTL RI
translation-phase validator and contains four pieces of
information:
-
The action name: tag = 'out'
-
The attribute name: attribute = 'value'
-
A generic message that includes the
complete EL expression: An error occurred while parsing custom action attribute "value" with value "${1 + 2 + 3"
-
A more detailed message about the
problem: Encountered "", expected one of ...").
This isn't so bad. The first three pieces of
information make it fairly easy to find the attribute value
that's in error. And the fourth message; well, it makes more
and more sense when you've seen messages like this a few
times. What's missing is the actual line number for the error.
Hopefully Tomcat will implement the optional feature I
mentioned earlier in a future version, so that the error
location can also be included in the report.
Figure
9-2 is a good example of how all true syntax errors are
reported by the JSTL RI (only the detailed messages differ),
but some types of errors can't be found until the request-time
phase, even though they may be regarded as syntax errors. Example
9-7 illustrates one such case.
Example 9-7. Misspelled
property name (error7.jsp) <%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<html>
<head>
<title>Looking for information</title>
</head>
<body bgcolor="white">
<h1>Looking for information</h1>
The Current URI: <c:out value="${pageContext.request.requestUri}" />
</body>
</html>
The problem here is that the property name is
misspelled: it should be requestURI ("URI" in all
caps) instead of requestUri. In this particular
example, the EL could actually figure this out at translation
time, because pageContext is an implicit variable, so
all its properties are known. But the type of an application
variable is known only at request time, so it's not possible
to notice a misspelled property name for the general case. The
JSTL RI has opted for consistency in how to handle this type
of error. The way this error is reported is by throwing an
exception with this message: An error occurred while evaluating custom action attribute "value" with
value "${pageContext.request.requestUri}": Unable to find a value for
"requestUri" in object of class "org.apache.catalina.connector.HttpRequestFacade"
using operator "."
It contains enough details about the error,
such as the attribute name and value, to make it feasible to
match it with its source in the page. Because it's not caught
until request time, it's unfortunately impossible to include
the line number in a JSP 1.2 container.
Example
9-8 shows an almost identical error, but it results in a
completely different result.
Example 9-8. Misspelled
parameter name (error8.jsp) <%@ page contentType="text/html" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
<html>
<head>
<title>Looking for information</title>
</head>
<body bgcolor="white">
<h1>Looking for information</h1>
The missing parameter: <c:out value="${param.misspelled}" />
</body>
</html>
Here it's the name of a request parameter that is misspelled, and it's not
reported as an error. Instead the expression evaluates to
null, which the <c:out> action
converts to an empty string. This is by design, and it makes
it easier to handle the typical case in which a missing
parameter should be handled the same as a parameter with an
empty string as the value. If a missing parameter resulted in
an exception, you would have to do a lot more testing in all
JSP pages, with <c:if> actions and expressions
like this all over the place: <c:if test="${!empty param.someParam}">
<!-- Here it's safe to use the parameter -->
</c:if>
The downside is that it makes it harder to
find parameter-name spelling errors. The EL handles all types
of name/value pair collections, such as the implicit variables
representing scopes (pageScope,
requestScope, sessionScope, and
applicationScope) as well as any application variable
of type java.util.Map, the same way.
|