Programming Jakarta Servlets

A Servlet is a web based component, managed by a container, that generates dynamic content. Currently, the latest release of Jakarta Servlets is 5.0 (September 7, 2020).

Jakarta Servlet version 5.0 is only a change of namespaces. Thus, migrating a Servlet 4.0 project to Servlet 5.0 and above, requires the replacement of the namespace javax.* with jakarta.*.
Within this tutorial we will still use the javax namespace for compatibility with Jakarta EE 8.

Within this Servlet tutorial we will learn some basic examples of Servlets using annotations.

A Basic Servlet using annotations

package sample;

import java.io.IOException;
import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;

 
@WebServlet(name="testServlet", urlPatterns={"/hello"},
        initParams={ @WebInitParam(name="simpleParam", value="paramValue") } )
     
public class TestServlet extends HttpServlet {
           
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        String simpleParam = getServletConfig().getInitParameter("simpleParam");
            out.println("Hello World "+simpleParam);
                out.close();
    }
 
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
         doGet(request,response);
    }

}

In the above code we have registered out TestServlet under the urlPatterns “/hello”. Additionally we’ve set an init param named “simpleParam”. No web.xml needed to run this Servlet.

Please note it’s possible to specify multiple urlPatterns for a Servlet as in this example:

@WebServlet(name="MyServlet", urlPatterns={"/foo", "/bar"})
public class SampleServlet extends HttpServlet{

    public void doGet(HttpServletRequest req, HttpServletResponse res) {
        ...
    }
}

Using Filters in Servlets

You can declare as well Filters using annotations, like in this example:

import java.io.*;
import javax.servlet.*;
import javax.servlet.annotation.*;

@WebFilter(urlPatterns={"/*"},
        initParams={ @WebInitParam(name="simpleParam", value="paramValue") })
        public class TestFilter implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {
        StringWriter sw = new StringWriter();
        PrintWriter writer = new PrintWriter(sw);

        writer.println("===============");
        writer.println("Filter intercepted!");
        writer.println("===============");

        // Log the resulting string
        writer.flush();
        filterConfig.getServletContext().
        log(sw.getBuffer().toString());

        chain.doFilter(request, response);

    }

    private FilterConfig filterConfig = null;
    public void init(FilterConfig filterConfig) 
    throws ServletException {
        this.filterConfig = filterConfig;
    }

    @Override
    public void destroy() {    }
}

A filter is a reusable piece of code that can transform the content of HTTP requests, responses, and header information. Filters do not generally create a response or respond to a request as servlets do, rather they modify or adapt the requests for a resource, and modify or adapt responses from a resource
In our example, that filter will intercept all request issued to the Web Context.

Using Listeners in Servlets

Another useful annotation introduced is the @WebListener annotation which can be used to tag a Java Class as WebListener:

package sample;

import javax.servlet.*;

@javax.servlet.annotation.WebListener
public class SessionListener implements ServletContextListener {

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        System.out.println("Context destroyed!");
        
    }

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        System.out.println("Context created!");
    }

     
}

Asynchronous Servlets

Asynchronous processing allows the thread to issue a call to the resource and return back to the container without getting blocked. The thread can perform other tasks, which makes Servlet 3.0’s performance more efficient. Implementing an Asynchronous Servlet requires using the AsyncContext, which can be obtainer from the HTTP request object. Here’s an example:

package sample;

import java.io.IOException;
import java.util.concurrent.ConcurrentLinkedQueue;

import javax.servlet.*;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.*;

import java.util.Queue;


@WebServlet(urlPatterns = {"/synch"}, asyncSupported = true)
public class AsynchServlet extends HttpServlet  {
    private static final Queue queue = new ConcurrentLinkedQueue();

       public void doGet(HttpServletRequest request, HttpServletResponse response) {
           final AsyncContext ac = request.startAsync();
           ac.setTimeout(1 * 60 * 1000);
           queue.add(ac);
           ac.addListener(new AsyncListener() {
           
        @Override
        public void onError(AsyncEvent arg0) throws IOException {
            System.out.println("onError"); 
            
        }
         
        public void onComplete(AsyncEvent event) throws IOException {
            System.out.println("onComplete"); 
            queue.remove(ac);
            }
        public void onTimeout(AsyncEvent event) throws IOException {
            System.out.println("onTimeout"); 
        queue.remove(ac);
        }
        @Override
        public void onStartAsync(AsyncEvent arg0) throws IOException {
            System.out.println("onStartAsync"); 
            
        }
         
           });
           queue.add(ac);
       }

       public void doPost(HttpServletRequest request, HttpServletResponse response) {
          doGet(request,response);
       }

 
}

The Asynch listener interface needs implementing a few callback methods (onComplete, onTimeout, onStartAsync, onError) which are triggered during the lifecycle of the Asynchronous Servlet.

Programmatic Servlets/Filter setup

One of my favourite adds-on is the ability of declare Servlets or Filters programmatically: think about mapping a Servlet with a name collected by an external source:

public void contextInitialized(ServletContextEvent sce) {
    System.out.println("Context created!");
    ServletContext sc = sce.getServletContext();

        // Get it from any resource
        String servletMapping = "/dynamic"

    ServletRegistration sr = sc.addServlet ("DynaServlet","sample.DynamicServlet");
        
    sr.setInitParameter("servletInitName", "servletInitValue");
    sr.addMapping(servletMapping);
}

Web Fragments

To ease Servlet development, in Servlet 3.0 has been introduced the notion of web descriptor fragments. A web fragment is a part or all of the web.xml that can be specified and included in a library or framework jar file.

Here’s an example of web fragment:

<web-fragment>
  <servlet>
    <description></description>
    <display-name>TestServlet</display-name>
    <servlet-name>TestServlet</servlet-name>
    <servlet-class>sample.TestServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>TestServlet</servlet-name>
    <url-pattern>/TestServlet</url-pattern>
  </servlet-mapping>
</web-fragment>

Where to place web fragments ? If a framework is packaged as a jar file and has metadata information in the form of deployment descriptor then the web fragment needs to be placed in the META-INF/ folder of the jar file.

On the other hand, if a framework wants its web-fragment.xml honored in such a way that it augments a web application’s web.xml, the framework must be bundled within the web application’s WEB-INF/lib directory.

Coding a Servlet Deployment Descriptor

The deployment descriptor conveys the elements and configuration information of a web application between Application Developers, Application Assemblers, and Deployers.

For Servlet 5.0, the deployment descriptor is defined in terms of an XML schema document.

Here is a sample web.xml deployment descriptors which shows how to configure the core Servlet components:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
         web-app_5_0.xsd"
         version="5.0">

  <display-name>A Simple Application</display-name>

  <context-param>
    <param-name>Webmaster</param-name>
    <param-value>[email protected]</param-value>
  </context-param>

  <servlet>
    <servlet-name>catalog</servlet-name>
    <servlet-class>com.example.CatalogServlet</servlet-class>
    <init-param>
      <param-name>catalog</param-name>
      <param-value>Spring</param-value>
    </init-param>
  </servlet>

  <servlet-mapping>
    <servlet-name>catalog</servlet-name>
    <url-pattern>/catalog/*</url-pattern>
  </servlet-mapping>

  <session-config>
    <session-timeout>30</session-timeout>
  </session-config>

  <mime-mapping>
    <extension>pdf</extension>
    <mime-type>application/pdf</mime-type>
  </mime-mapping>

  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.html</welcome-file>
  </welcome-file-list>

  <error-page>
    <error-code>404</error-code>
    <location>/404.html</location>
  </error-page>

</web-app>
Found the article helpful? if so please follow us on Socials