Head First Servlets and JSP - Errata by Bryan Basham, Kathy Sierra, Bert Bates This errata page lists errors outstanding in the most recent printing. If you have technical questions or error reports, you can send them to
[email protected]. Please specify the printing date of your copy. This page was updated March 1, 2007. Here's a key to the markup: [page-number]: serious technical mistake {page-number}: minor technical mistake <page-number>: important language/formatting problem (page-number): language change or minor formatting problem ?page-number?: reader question or request for clarification Confirmed errors: {xxvi} 2nd bullet point; http://jakarta.apache.org/site/bin/index.cgi SHOULD BE http://jakarta.apache.org/site/binindex.cgi (6) bottom of page; (FYI: HTTP stands for HyperText Transport Protocol.) should read (FYI: HTTP stands for HyperText Transfer Protocol.) (15) Request line description; There is a discrepancy between the request line description in the middle of the page: GET /select/selectBeerTaste.jsp and in the "cloud callout" of the web browser at the bottom left of the page: /select/selectBeerTaste.html it should say: /select/selectBeerTaste.jsp (21) 2nd para - last sentence; The last sentence reads... And even if it did, the POP3 server doesn't known anything....
it should be: And even if it did, the POP3 server doesn't know anything.... (26) 1st paragraph - line 3; "exist before the request). and the ..." should be "exist before the request) and the ..."
[30] the first line of web.xml; the first line of the web.xml file should be:
[30] Step 3 - within the xml code for the DD; the third and fourth lines of xml read: xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee web-app_2_4.xsd" This should be combined into one line, and a forward slash should be inserted between the "j2ee" and the "web-app_2_4.xsd": xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" (35) 2nd bullet point; "... server gives back and HTTP response..." should be: "... server gives back an HTTP response..." (48) second paragraph to the last on the bottom; This is the what the client... should be: This is what the client... (58) First bullet point, last sentence; The text ends with "so that you can concentrate of your own business logic". it should be: "so that you can concentrate on your own business logic".
{58} 3rd bullet point; The 3rd bullet point reads... "A typical servlet is a class that extends HttpServletRequest" should be: "A typical servlet is a class that extends HttpServlet" [62] The 4th hand-written note "Gets the response from the container" should read "Container generates the HTTP response stream from the data in the response object" in the column marked "Container" (65) 1st paragraph; "it incorporates other specifcations,..." should be "it incorporates other specifications,..." {71} Figure edit (per author): In the top figure, labeled "Web Server," move the form.html file into the Container box. (77) 2rd paragraph; and save it in your deployment environment under .... should be and save it in your development environment under .... (78) handwritten comment; ...to the URL of the page its on. should be: ...to the URL of the page it's on. {82} 2nd paragraph; - Its directory structure should be /WEB-INF/classes/com/model should have been - Its directory structure should be /WEB-INF/classes/com/example/model {84} Addition of new code ; The code for servlet version three on page 89 shows the following line as commented out:
// out.println("
Got beer color " + c); However, that line never appeared in the servlet version two code and should be added (uncommented out and in bold) just above the following line on page 84: BeerExpert be = new BeerExpert(); AUTHOR: This is how I would reorganize these two code examples in a future printing of the book. First, on pg 84 move all of the code that (a) retrieves the 'color' parameter and (b) retrieve the results of the beer search from the BeerExpert to the top of the doPost method. Put the code to (a) set content type, (b) retrieve the Writer, and (c) generate the response at the bottom of the doPost method. Second, on pg 89, reproduce the code structure from above, but now comment out the bottom half which is being replaced by the code to (a) set the 'styles' attribute, (b) create the RequestDispatcher, and (c) forward to the view ReqDisp. (90) first sentence following "Deploying and testing the web app"; "redploy" should be: "redeploy" (90) Last picture at bottom of page; try: Jack's Pale Ale should read: try: Jail Pale Ale (94) Coverage notes, 4th paragraph; "because the questions requires additional knowledge" Should read: "because the questions require additional knowledge" {100} Thought bubble at top left.; The final sentence says: "So each time my doGet() or doPost() runs, it's in a separate method"
SHOULD READ "So each time my doGet() or doPost() runs, it's in a separate thread." {106} ServletResponse interface; ServletResponse Interface shown has two setContentType() methods. One of them should be getContentType() {106} ServletRequest interface; The line: "getParameter()" should be: "getParameter(String)" (114), the answer to the "Sharpen your pencil" exercise "The HTTP 1.1 spec declares GET, HEAD, and PUT as idempotent, even though you CAN write a non-idemptotent doGet() method should be: "The HTTP 1.1 spec declares GET, HEAD, and PUT as idempotent, even though you CAN write a non-idempotent doGet() method the term "non-idemptotent" should read "non-idempotent" {114,116} Answer to Sharpen your pencil at bottom of page 114; "POST is considered idempotent by the HTTP 1.1 spec." should be: "POST is not considered idempotent by the HTTP 1.1 spec." (118) last paragraph (prefixed with "A:"); The "...if this request doesn't need to do post things..." wording is confusing given the question is in regards to supporting *both* GET and POST. Suggesting rewording: "A: Developers who want to support both methods usually put logic in doGet(), and then have the doPost() implementation delegate to that doGet():"
{123} 2nd paragraph; The Input stream from request.getInputStream() will only contain the body, not the header
(132) Last Paragraph; Information at the bottom of the page labeled 'fiy' should be 'FYI'
[136] 3 changes on this page; Third hand-written note from the top should read: The forward slash at the beginning means "relative to the root of the web container." The last paragraph (and code) should read: The Container builds the complete URL relative to the web container itself, instead of relative to the original URL of the request. So the new URL will be: http://www.wickedlysmart.com/foo/stuff.html Fourth hand-written note from the top should read: See... the "myApp/cool" part of the path isn't here this time.
{154} TestInitParams source code; The source code for the TestInitParams servlet is missing an import. Add: import java.util.*; Without the import the code won't compile because the Enumeration class is used.
[154] the first line of web.xml; the first line of the web.xml file should be:
(158) in the deployment descriptor section; <servlet-name> BeerParamTests <servlet-name> it should be like this: <servlet-name> BeerParamTests
{162} ServletContext interface; "setAttribute(String)" should read: "setAttribute(String, Object)" (177) Last line; URL pattern mapped to this the servlet: ListenTest.do should read: URL pattern mapped to the servlet: ListenTest.do (182) "Scenario" column, 5th row of grid; "will stored " should be "will be stored " {189} top right paragraph; enumeration getAttributeNames() should be: Enumeration getAttributeNames() {189} ServletRequest interface box; ServletRequest interface box shows method name of getContextType(), where it should be getContentType(). {189} HttpSession interface Column; In the list of methods for HttpSession Interface, the setMaxInactiveInterval is shown without arguments. setMaxInactiveInterval() should instead be written as setMaxInactiveInterval(int interval) (199) 2nd paragraph; 'Are they are safe?' should be: 'Are they safe?' {200} 7th line of code; out.println("test context attributes
"); should be:
out.println("test session attributes
"); (206) second column 5th row; Lifecycle event related to ServletRequest: Method: SessionDestroyed() should be requestDestroyed() {211, 217} 1st paragraph; Which statements about listeners defined in the javax.servlet package are true? should be: "Which statements about listeners are true?" [213] Q 12 - item D; ServletRequest should be: HttpServletRequest (213) Question 12, answer E; In the last option (E) of question 12, the test states: 'The servlet to which a request is forwarded may access the original query string by calling getAttribute("javax.servlet.forward.query_string") on the' This statement is not finished on the next line or the next page. "ServletRequest" should be added to the last sentence of option E. [215] Answer to question 1; Option C should also be checked. [214 + 220] Q 13; this option is worded poorly. I would rephrase it as: "If the servlet implements javax.servlet.SingleThreadModel, the container may use one instance for each simultaneous request." [219] Q12 Answer D; Answers D and E are checked, but only E should be. getQueryString() returns the dispatcher request path's query string, not the original query string.
(231) 2nd handwritten paragraph from the top starting with "(This method..." - 2nd sentence starting wih "Now, there's still..."; "Now, there's still not guarantee the client will ACCEPT the cookie..." should read: "Now, there's still no guarantee the client will ACCEPT the cookie..." (235) diagram of HTTP response; the closing angle bracket for the anchor tag 'a href="http://wick.."' is missing {238} point 4 on the Bullet Poins; out.println("
Click Me"); (242) second column, fifth row; the parenthetical expression reads: (for example, after the client does a shopping check-out or logs). it should be (for example, after the client does a shopping check-out or logs out) {245} Example 2; delete the line: String foo = (String) session.getAttribute("foo"); out.println("Foo: " + foo); should read: out.println("Foo: " + session.getAttribute("foo")); {251} source code; There should be a if (cookies!=null) { } after
Cookie[] cookies = request.getCookies(); [254] Standout titled "You do NOT configure session binding listeners in the DD!; Standout reads: "You do NOT configure session binding listeners in the DD! ... But this is NOT true for the other session related listeners on the previous page. HttpSessionListener, HttpSessionAttributeListener, and HttpSessionActivationListener must be registered in the DD, since they're related to the session itself, rather than an individual attribute placed in the session." Should read: ""You do NOT configure session binding listeners OR SESSION ACTIVATION LISTENERS in the DD! ... But this is NOT true for the other session related listeners on the previous page. HttpSessionListener and HttpSessionAttributeListener must be registered in the DD, since they're related to the session itself, rather than an individual attribute placed in the session." {258} Serialization box at bottom of page; "...can also choose to implement a readObject() method, called by the VM whenever an object is serialized, and a writeObject() method, called when an object is deserialized." Should read: "...can also choose to implement a writeObject() method called by the VM whenever an object is serialized, and a readObject() method, called when an object is deserialized." {261} Bang box: The Bang! box on pg 261 is erroneous and should be dropped altogther. (262) 2nd column, 4th row; HttpSessionAtrributeListener should be HttpSessionAttributeListener (265 and 272)Question 1: public class MyServlet extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException {
// request.getSession().setAttribute("key", "value"); // request.getHttpSession().setAttribute("key", "value"); // ((HttpSession)request.getSession()).setAttribute("key", "value"); // ((HttpSession)request.getHttpSession()).setAttribute("key", "value"); } } Should be: public class MyServlet extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws IOException, ServletException { // req.getSession().setAttribute("key", "value"); // req.getHttpSession().setAttribute("key", "value"); // ((HttpSession)req.getSession()).setAttribute("key", "value"); // ((HttpSession)req.getHttpSession()).setAttribute("key", "value"); } } change "request" to "req" to make it consistent! {274} Q7, Answer C; Answer C left off a vital part of the sentence when it was copied from the Servlet specification. The Servlet specification says: 'Any object bound into a session is available to any other servlet that belongs to the same ServletContext and handles a request identified as being a part of the same session.' Answer C leaves off the final part of the sentence: 'and handles a request identified as being a part of the same session.' Without this answer C is not correct. [276] Question 12, Option C; Rewrite item C as: "When a session is moved from one JVM to another, objects within the session that implement HttpSessionActivationListener will be notified." (287) black box at bottom; AS IS: <%= becauseThisIsAnArgumentToWrite() %> SHOULD BE:
<%= becauseThisIsAnArgumentToPrint() %> WHY THIS IS IMPORTANT: There is also an error on page 343, which gets out.print() and out.write() mixed up. Combined, these two errors confuse this point: JSP expressions become out.print() in the _jspService() method and plain old template text becomes out.write() in the _jspService() method. (288) 6th 'sharpen your pencil' question; <%= newString[3]) %> should be: <%= newString[3] %> (288) 7th 'sharpen your pencil' question; <% = 42*20; %> should be: <% = 42*20 %> (293), in both of the code snippets, ... extends HttpServlet { is misleading, the snippets should have continued to use the same pseudo-code as the snippet on page 291, ... extends SomeSpecialHttpServlet { [296] Implicti Object table; based on JSP 2.0 specification implicit variable exception is of type java.lang.Throwable and not javax.servlet.jsp.JspException JSP specification page 78 table JSP.1-7 Implicit Objects Available in Error Pages (297) Heading; This should be labelled a "Be the Container" exercise. (In order to be consistent with text on page 300 where the answer to p. 297 appears. {307} 2nd Paragraph; Yes, you CAN get servlet init parameters from a servlet.... should read:
Yes, you CAN get servlet init parameters from a JSP... [308] The DD at the top part of the page; This DD does not work to allow the JSP to obtain the servlet init params. The proper DD for this is: <servlet> <servlet-name>MyTestInit <jsp-file>/TestInit.jsp
<param-name>email <param-value>[email protected] <servlet-mapping> <servlet-name>MyTestInit
/TestInit.jsp {322} Exercise no. 2.; "...OR place a checkmark in the ignored column if scripting will be treated like other template text." should be: "...OR place a checkmark in the error column if scripting will cause a translation error." And change the "ignored" column title to "error". (323 *and* 326) code magnets; The code magnet should read <jsp:include page="foo.html"/> *not* <jsp:include file="foo.html"/> (325) Exercise 2; change the "ignored" column title to "error". (327) 3rd handwritten note; AS IS: Expressions turn into write() statements in the service method.
SHOULD BE: Expressions turn into out.print() statements in the service method.
{343} 3rd handwritten note; AS IS: (Remember: scripting expressions are ALWAYS the argument to the out.write() method.) SHOULD BE: (Remember: scripting expressions are ALWAYS the argument to the out.print() method.) [353] Has this result title; Has this result java.lang.InstantiationError: foo.Person should be Has this result java.lang.InstantiationException: foo.Person {368} Paragraph under Using the dot(.) operator to access...title; The first variable is either ..., and the thing to the right of the dot is either a map value(if the first variable is a map) ... should be The first variable is either..., and the thing to the right of the dot is either a map key(if the first variable is a map) ... (372) Under title In a Servlet; says: favoriteFood.add("chai ice chream"); possible change: favoriteFood.add("chai ice cream"); (386) above the line divider; ${cookie.userName.valu} should be ${cookie.userName.value} (391) 2nd paragraph (first A: block); (a JSP supposed to be ... should read (a JSP is supposed to be ...
(393) 3rd item of "What prints for each of these?"; ${requestScope[integer] ne 4 and 6 le num || false} should read: ${requestScope["integer"] ne 4 and 6 le num || false} (399) First hand-written comment on top left; Says "This is the same as it was on the previous page..." should say: "This is the HTML content that we want on every page in our webapp." {400} 1st paragraph; The <jsp:include> standard action appears to do the same thing as the include standard action. should be: The <jsp:include> standard action appears to do the same thing as the include directive. [404] The bottom diagram; in the diagram, the translated file name is Contact_jsp.java and the compiled file name is Contact_jsp.class it should be Header_jsp.java and Header_jsp.class
(405) In the top left BANG! box; In the sentence "To help you remember, the include directive <% include file="foo.jsp"> is used only at translation time (as with all directives)." It should read "To help you remember, the include directive <%@ include file="foo.jsp"%> is used only at translation time (as with all directives)."
{405} last sentence in bottom-right comment; Sentence should end "but that's more obvious with the include directive.", not "page directive."
{407} whole page; As the .jspf convention is not supported by default in Tomcat, the following mapping needs to be added to the application's web.xml for the example to work correctly:
<servlet-mapping> <servlet-name>jsp
*.jspf [407] section 1 and section 2; Section 2 Contact.jsp; <%@ include file="Header.jsp" %> should be <%@ include file="Header.jspf" %> (407) Section 3 The Footer file; The heading for section 3: 3 The Footer file ("Footer.jsp") should be: 3 The Footer file ("Footer.html") [416] Be the Container Answers; The third example will not work for the same reason that the first example doesn't work, because the attribute is at Request Scope, and the default scope is Page scope. The handwritten comment for bullet #3 should be the same as for bullet #1. {420, 428} Question 6, option F; "${list[list['listIdx']]}" should read: "${list[list[listIdx]]}" [432] Question 17, Option C; option C is invalid and should not be checked. {434} Installing JSTL 1.1; The instructions indicate just jstl.jar file is required to run JSTL in Tomcat. You also need standard.jar from the webapps/jsp-examples/WEB-INF/lib/ directory. {446} Bottom "Bang!" box.; ... "target" attribute in the tag seems like it should work like "id" in the <jsp:setProperty>. should be: ... "target" attribute in the tag seems like it should work like "id" in the <jsp:useBean>.
{447} Answer to second q&a; Answer talks about using 'scope' attribute for c:set for 'var' or 'target'. Scope attribute is only meaningful for 'var'. Answer needs to be rewritten to remove any reference to the 'target' attribute. {448} 2nd handwritten comment; The scope is optional, and like always - page is the default scope. should be: The scope is optional, and when not specified the attribute is removed from all scopes. {452} first section; The JSP with the <jsp:include> last line