Servlet 3.0 – How annotation @WebServlet works

Introducing @WebServlet

If you have had to create Java servlets under the JSR-315 (Servlet 3.0) specification, you have at least seen (if not used) the @WebServlet annotation that now allows servlet mapping to take place in the servlet code versus mapping the servlet via the deployment descriptor (web.xml) file. Here is a simple HelloWorld servlet with the new @WebServlet annotation:
 1: package com.intertech.blog;
   2:  
   3: import java.io.IOException;
   4: import java.io.PrintWriter;
   5:  
   6: import javax.servlet.ServletException;
   7: import javax.servlet.annotation.WebServlet;
   8: import javax.servlet.http.HttpServlet;
   9: import javax.servlet.http.HttpServletRequest;
  10: import javax.servlet.http.HttpServletResponse;
  11:  
  12: @WebServlet("/HelloWorld")
  13: public class HelloWorld extends HttpServlet {
  14:     private static final long serialVersionUID = 1L;
  15:  
  16:     protected void doGet(HttpServletRequest request,
  17:             HttpServletResponse response) throws ServletException, IOException {
  18:         response.setContentType("text/html");
  19:         PrintWriter out = response.getWriter();
  20:         out.println("<html><body>");
  21:         out.println("<h1>Hello, World!</h1>");
  22:         out.println("</body></html>");
  23:         out.close();
  24:     }
  25: }
The @WebServlet annotation on top of the class declares the servlet under the name of com.intertech.blog.HelloWorld with a URL mapping of http://<server>:<port>/<application context>/HelloWorld. If the @WebServlet annotation were not used and web.xml was used instead to declare and map the servlet, the XML below would provide an equivalent configuration.
   1: <?xml version="1.0" encoding="UTF-8"?>
   2: <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   3:     xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   4:     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
   5:     id="WebApp_ID" version="3.0">
   6:     <display-name>TestOverride</display-name>
   7:     <servlet>
   8:         <servlet-name>com.intertech.blog.HelloWorld</servlet-name>
   9:         <servlet-class>com.intertech.blog.HelloWorld</servlet-class>
  10:     </servlet>
  11:     <servlet-mapping>
  12:         <servlet-name>com.intertech.blog.HelloWorld</servlet-name>
  13:         <url-pattern>/HelloWorld</url-pattern>
  14:     </servlet-mapping>
  15: </web-app>

@WebServlet Attributes

The attribute provided to the @WebServlet annotation is the value attribute. The value attribute provides the URI mapping for your servlet. You can make this explicit as shown below.
   1: @WebServlet(value="/HelloWorld")
The only time you need to make the value explicit is when you need to add other attributes to your @WebServlet annotation. You may want to map your servlet to several paths. For this, you’ll need the urlPatterns attribute. The urlPatterns attribute allows you to specify an array of String URL patterns to address the servlet as shown below.
   1: @WebServlet(urlPatterns={"/HelloWorld", "/HiWorld","/ItsASmallWorld"})
   2: public class HelloWorld extends HttpServlet {
   3: }
Either the value or urlPatterns attribute is required in the @WebServlet. However, both cannot be used simultaneously. In fact, if you try, the container (like Tomcat below) with throw an exception when deploying/starting your application.
image
Another of the attributes that can be provided on the @WebServlet is the name attribute. The name attribute is optional. By default, @WebServlet causes your servlet to be declared under the name of the fully qualified class name. In the example above, that means the name of the servlet is com.intertech.blog.HelloWorld. If you wish to override the default name, provide a name attribute with the @WebServlet annotation. Below, the default name is overridden and is now called “JimsWorld.”
   1: @WebServlet(name="JimsWorld", urlPatterns={"/HelloWorld", "/HiWorld","/ItsASmallWorld"})
   2: public class HelloWorld extends HttpServlet {
   3: }

Web.Xml Overriding @WebServlet

While @WebServlet allows the mapping of servlets to occur in the Java code, the deployment descriptor file can still be used to map servlets. In fact, there are still many valid reasons to have a web.xml file in your Web application. Providing a list of welcome pages, defining error pages, and giving filters order are things that can only be done in the deployment descriptor.
When using web.xml file to define and map servlets, you may typically remove the @WebServlet annotation from your code. However, if you still use @WebServlet in your code, then any mapping provided in the deployment descriptor overrides the mappings defined via the @WebServlet provided the servlet name is the same in both the @WebServlet and web.xml. That last clause is important! Remember, by default, the name of a servlet is the fully qualified class name of the servlet if no name attribute is included with @WebServlet annotation. So consider the following class definition and web.xml file.
   1: package com.intertech.blog;
   2: @WebServlet(urlPatterns={"/HelloWorld", "/HiWorld","/ItsASmallWorld"})
   3: public class HelloWorld extends HttpServlet {
   4: }
   1: <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   2:     xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
   3:     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
   4:     id="WebApp_ID" version="3.0">
   5:     <display-name>TestOverride</display-name>
   6:     <servlet>
   7:         <servlet-name>FooBar</servlet-name>
   8:         <servlet-class>com.intertech.blog.HelloWorld</servlet-class>
   9:     </servlet>
  10:     <servlet-mapping>
  11:         <servlet-name>FooBar</servlet-name>
  12:         <url-pattern>/HelloDifferentWorld</url-pattern>
  13:     </servlet-mapping>
  14: </web-app>
In this example, the name (by default) of the servlet in the class definition is com.intertech.blog.HelloWorld. Since the name for the servlet in the web.xml in this example does not match the default name specified via the @WebServlet annotation, the web.xml file does not override the @WebServlet mapping. Instead, it augments the @WebServlet definition. In other words, it defines an additional mapping to the servlet (in this case via /HelloDifferentWorld) to the list of URL mappings defined by the @WebServlet. So now, the HelloWorld servlet can be reached by any of these URLs:
http://<server>:<port>/TestOverride/HelloWorld (via @WebServlet)
http://<server>:<port>/TestOverride/HiWorld (via @WebServlet)
http://<server>:<port>/TestOverride/ItsASmallWorld (via @WebServlet)
http://<server>:<port>/TestOverride/HelloDifferentWorld (via web.xml)
If the name of the servlet is the same in both the @WebServlet and the web.xml file, then the mapping in the web.xml overrides any URL mapping defined in the @WebServlet annotation.
1: <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2: xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
3: xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
4: id="WebApp_ID" version="3.0">
5: <display-name>TestOverride</display-name>
6: <servlet>
7: <servlet-name>com.intertech.blog.HelloWorld</servlet-name>
8: <servlet-class>com.intertech.blog.HelloWorld</servlet-class>
9: </servlet>
10: <servlet-mapping>
11: <servlet-name>com.intertech.blog.HelloWorld</servlet-name>
12: <url-pattern>/HelloDifferentWorld</url-pattern>
13: </servlet-mapping>
14: </web-app>
With the web.xml above in place, the name of the servlet is the same as that defined implicitly with
@WebServlet. So now only one URL can be used to access the servlet.
http://localhost:8080/TestOverride/HelloDifferentWorld  (via web.xml)
Trying to use any of the other URLs defined with @WebServlet results in a 404 error.
image

Wrap Up



Sometimes figuring out the servlet mapping can be a bit confusing when both annotations and web.xml are used. A “best practice” is to try to use one or the other. When circumstances warrant using both, know which has precedence and under what circumstances. See the Servlet 3.0 specification (http://download.oracle.com/otndocs/jcp/servlet-3.0-fr-eval-oth-JSpec/) for more details.

No comments :

Post a Comment