This is a good one and a fundamental design issue with JSP. The question
is: How many different types of errors can one get when using JSP? For
example, because the JSP Servlet is auto generated from a .jsp text file
and then compiled with a compiler, what happens when there is a
generation/parsing error or a compile error? The unnecessary complexity
of JSP actually increases the number of ways to get errors!
The ugliest aspect of all of this is the fact the errors are reported
via two different mechanisms. The parser can throw its own set of errors
and the javac compiler can throw a whole different set of errors and
as a result of the layers of generation, errors from the compiler generally
do not make any sense whatsoever. For example, can you tell me what
this error is from?
|
|
|
|
org.apache.jasper.JasperException: Unable to compile class: Invalid type
expression.
out.println("JSP is great!")
^
: Invalid declaration.
out.write("\r\n\r\n\r\n");
^
2 errors
|
|
|
|
|
If you guessed that the error was a result of a missing ;
after the first out.println(), you were correct! Now, put yourself in
the shoes of someone who has never written or seen a line of Java code.
Do you think that person could have figured out the error quickly and
easily? Compound that with the fact that if the error had been on a less
deterministic part of the file, it is now much harder to find the source
of the error because there is a level of abstraction from the original
.jsp file and because there is an intermediate .java file that gets
generated.
Again, Velocity does not suffer from these same problems because there
is no intermediate step and no layers of abstraction.
|
|
|
|
<%@ page errorPage="/error.jsp" %>
|
|
|
|
|
JSP also allows one to define an error page that is used if an Throwable
exception is thrown during the processing of a page. Doesn't this again
break the MVC model? In other words, shouldn't the application framework
be responsible for dealing with error messages
|
|
|
|
<% throw new Exception("oops"); %>
|
|
|
|
|
In order to throw an Exception somewhere in a JSP page, one needs to
first embed it within a statement. Note: that in this specific case, if
optimizations are turned on in the compiler, chances are that the entire
exception would be compiled out. Therefore, a more concrete object must
be used instead of the "true". This can actually prove difficult if
using a strict MVC model because instantiation of objects breaks the
View.
|
|
|
|
<%
if (true) {
throw new Exception("oops");
}
%> |
|
|
|
|
The reason is that JSP will generate an additional out.println
("\r\n");
after the Exception. When javac attempts to compile the
page, another hard to debug error will be reported:
|
|
|
|
org.apache.jasper.JasperException: Unable to compile class for
JSPC:\engines\jakarta-tomcat\work\localhost_8080%2Fjsp\
_0002ferrorMaker_0002ejsperrorMaker_jsp_3.java:75:
Statement not reached.
out.write("\r\n");
^ |
|
|
|
|
Taking a direct quote out of Jason's book (I couldn't say it better myself):
|
|
|
|
In fact, there are many such "gotchas" when using scriptlets with JSP.
If you accidentally write a scriptlet instead of an expression (by
forgetting the equal sign), declare a static variable inside a scriptlet
(where statics aren't allowed), forget a semi-colon (they're not needed
in expressions but are needed in scriptlets), or write anything but
perfect Java code, you're likely to get a confusing error message
because the compiler is acting on the generated Java code, not on the
JSP file. To demonstrate the problem, picture if <%= name %> were
replaced by <% name %> in errorTaker.jsp. Tomcat generates this error:
org.apache.jasper.JasperException: Unable to compile class for
JSPC:\engines\jakarta-tomcat\work\localhost_8080%2Fjsp\
_0002ferrorTaker_0002ejsperrorTaker_jsp_6.java:91:
Class name not found.
name
^
Debugging an error like this often requires a programmer to look at the
generated code to reconstruct what caused the error. |
|
|
|
|
Velocity does not have of these same problems because it does not allow
the author to place any Java code within a template. The only things allowed
in the template are Velocity Template Language (VTL) and method calls.
Everything else is considered 'text' for literal output by the parser.
The only place where one could run into trouble within Velocity is if
there is a call to a method which throws an exception during runtime.
For example, this VTL defines a String $foo
and then
attempts to call its substring()
method on it would throw
an IndexOutOfBoundsException
:
|
|
|
|
#set ($foo = "bar")
#set ($bar = $foo.substring(0,10))
|
|
|
|
|
When the exception is thrown, the parser will stop processing and throw
that exception up the stack tree where it can be caught in the method
that caused the parser to execute. At that point, the exception can be
handled gracefully. Yes, this is something that is probably not easily
debugged by a Designer without Java knowledge, it is easily debugged by
a Template Engineer who has at least limited Java knowledge.
This is one of the benefits of using Turbine combined with Velocity
because of Turbine's design it easy to deal with Exceptions in a
consistent manner. It is also possible to get this same functionality
with by using Velocity's included VelocityServlet. The Exception will
contain the line number and column number in the .vm file of where the
error happened. Because there is no abstraction like with JSP, the line
number and column matches up to the error. Also, the only tool that will
throw the exception is the parser and that exception will contain the
location and error information pertinent to your actual template, not an
intermediary file. No need to try to debug the cryptic javac messages
which are a result of generated .java code. Note: one commercial
application server offers better handling of matching the line number in
the JSP file to the error.
You make the decision.
[ Generation? <- Previous |
Next -> JavaBeans ]