Thursday, February 10, 2011

#{...} is not allowed in template text

Shortly after starting my adventure with JSP 2.0 I came across the following runtime exception:

org.apache.jasper.JasperException: /index.jsp(13,27) #{...} is not allowed in template text
 org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:40)
 org.apache.jasper.compiler.ErrorDispatcher.dispatch(ErrorDispatcher.java:407)
 org.apache.jasper.compiler.ErrorDispatcher.jspError(ErrorDispatcher.java:102)
 ...
 javax.faces.webapp.FacesServlet.service(FacesServlet.java:313)

My first question was: WTF? All my libs are where they should be, no compilation time errs/warnings, syntax seems to be OK as well. OK, I don't have the jsf/core & jsf/html taglibs imported, but I'm using JSF 2.0, so I don't need the <@ taglib uri="..." prefix="..."/> any more, right? Not exactly.
Quick introduction: as of JSF 2.0 Oracle introduces new technology called Facelets. It's a page declaration language used to build views & templates for JSF-based web applications. Facelets are usually created with conformance to XHTML Transitional DTD, thus the default file extension is *.xhtml. Now, how does this apply to the aforementioned error? One of the advantages of Facelets is that they use XML namespace declaration to import tag libraries. Similar mechanism is used in JSP pages with XML syntax. Example:

Facelets (XHTML) - index.xhtml
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
 xmlns="http://www.w3.org/1999/xhtml"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:h="http://java.sun.com/jsf/html">
 <h:head>
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
  <title>Facelet (JSF 2.0)</title>
 </h:head>
 <h:body>
  Name: <h:outputText value="#{personDetails.name}"/>
 </h:body>
</html>

In the above example, both namespace declarations in <html> tag instruct the container that the page is using standard JSF tag libraries http://java.sun.com/jsf/core & http://java.sun.com/jsf/html, and so they should be automatically imported. Another advantage of the Facelets is that they define their own component tree, so there's no more need to wrap your JSF code into <f:view></f:view> tags, which was mandatory in previous versions of the framework.
So, why did I get the error? Because my file was a *.jsp file (i.e. JSP page) and not an *.xhtml file (default for Facelets), and the container kindly ignored my xmlns declarations.

What about the old JSP pages? We need to import manually all required taglibs. Some examples below (note the *.jsp file extension):

JSP (XHTML, JSP syntax) - index.jsp
<?xml version="1.0" encoding="ISO-8859-1" ?>
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
    pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f"%>
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html
 xmlns="http://www.w3.org/1999/xhtml"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:h="http://java.sun.com/jsf/html">
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
  <title>Insert title here</title>
 </head>
 <body>
  <f:view>
   Name: <h:outputText value="#{personDetails.name}"/>
  </f:view>
 </body>
</html>
JSP (XHTML, XML syntax) - index.jsp
<?xml version="1.0" encoding="ISO-8859-1" ?>
<jsp:root
 xmlns:jsp="http://java.sun.com/JSP/Page"
 xmlns:f="http://java.sun.com/jsf/core"
 xmlns:h="http://java.sun.com/jsf/html" version="2.0">
<html xmlns="http://www.w3.org/1999/xhtml">
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
  <title>JSP (XHTML, XML syntax)</title>
 </head>
 <body>
  <f:view>
   Name: <h:outputText value="#{personDetails.name}"/>
  </f:view>
 </body>
</html>

A little explanation to the last snippet. As mentioned before, JSP pages with an XML syntax use the xmlns namespace declarations of the <jsp:root> tag while importing required tag libraries. What differs from Facelets, is that we still need to specify scope of our JSF code by declaring <f:view></f:view> tags in our JSP file.

6 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Much thanks. This was very helpful in my attempt to start a new JSF 2.0 app with years of 1.1 and 1.2 experience! Now if only Eclipse had a nice designer for this like it did for JSF 1.2!

    ReplyDelete
  3. Strike that about Eclipse. Apparently Web Tools Platform has the JSF Tools baked into it. Seems promising. Thanks again!

    ReplyDelete
  4. so ... 1 year later, I was asking the same thing "WTF"????

    Thanks dude

    ReplyDelete
  5. Thanks, you help me a lot!

    ReplyDelete