How do I manage sessions using HttpSession in Jakarta Servlets?

Managing sessions using HttpSession in Jakarta Servlets is a straightforward process. HttpSession is a part of the Jakarta Servlet API which provides a way to handle session management between a client and server during multiple requests.

Here’s a structured guide on using and managing sessions with HttpSession:


1. Introduction to HttpSession

  • The HttpSession interface is used to:
    • Store information about a user’s session (attributes such as user information, preferences, or data specific to each client).
    • Track users across multiple requests (via cookies or URL rewriting).

2. How to Create or Retrieve a Session

You can retrieve or create a session using the HttpServletRequest.getSession() method:

HttpSession session = request.getSession();
  • If a session already exists, this method returns the existing session.
  • If no session exists, it will create a new one.

If you want to retrieve the session but don’t want to create a new one if it does not exist, you can use:

HttpSession session = request.getSession(false); // Returns null if no session exists

3. Adding Attributes to the Session

You can store user-related or application-specific data in the session using the setAttribute method:

session.setAttribute("user", "JohnDoe");
session.setAttribute("cartItems", cartItemList);

4. Retrieving Attributes from the Session

Use the getAttribute method to retrieve values stored in the session:

String user = (String) session.getAttribute("user");
List<String> cartItems = (List<String>) session.getAttribute("cartItems");

Make sure to cast the returned object to the proper type.


5. Removing Attributes from the Session

Use the removeAttribute method to delete specific session attributes:

session.removeAttribute("user");

6. Invalidating or Destroying the Session

When the session is no longer needed (e.g., a user logs out), you can invalidate the session using:

session.invalidate();

This method:

  1. Invalidates the current session and removes all the stored attributes.
  2. Creates a new session on the next request.getSession() call.

7. Setting Session Timeout

You can specify the session timeout (in minutes) using:

session.setMaxInactiveInterval(30 * 60); // 30 minutes

To retrieve the current session timeout:

int timeout = session.getMaxInactiveInterval();

If the user is inactive for longer than the timeout duration, the session will be invalidated automatically.


8. Session ID

Each HttpSession has a unique session ID. You can retrieve it using:

String sessionId = session.getId();

This ID is used to track the session between requests (usually via cookies or URL rewriting).


9. Checking Session Validity

You can verify whether a session is new using:

boolean isNew = session.isNew();

This is particularly useful when you want to check if the session was newly created or reused.


10. Session Tracking Mechanisms

The server manages session tracking using one of the following mechanisms:

  1. Cookies: This is the default method where the session ID is maintained using a cookie (e.g., JSESSIONID).
  2. URL Rewriting: This is a fallback mechanism when cookies are disabled. The session ID is appended to the URL as a query parameter.

For enabling URL rewriting, you can use:

String encodedURL = response.encodeURL("yourUrlHere");

This ensures the session ID is included in the URL if cookies are not supported.


11. Example Code: Using HttpSession

Here’s a full working example:

package org.kodejava.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import java.io.IOException;

@WebServlet("/sessionExample")
public class SessionExampleServlet extends HttpServlet {

  @Override
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
    // Retrieve session, create if none exists
    HttpSession session = request.getSession();

    // Set session attributes
    session.setAttribute("username", "JohnDoe");

    // Get session attributes
    String username = (String) session.getAttribute("username");

    // Display session info
    response.setContentType("text/html");
    response.getWriter().println("<h1>Welcome, " + username + "</h1>");

    // Show session ID
    response.getWriter().println("<p>Session ID: " + session.getId() + "</p>");
  }

  @Override
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
          throws ServletException, IOException {
    // Invalidate session on logout
    HttpSession session = request.getSession(false);
    if (session != null) {
      session.invalidate();
    }
    response.getWriter().write("Logged out successfully!");
  }
}

12. Best Practices for HttpSession

  • Minimize Data Storage: Store only necessary, lightweight data in the session to reduce memory overhead.
  • Secure Session Handling:
    • Ensure cookies are marked as HttpOnly and Secure.
    • Implement proper session timeout.
    • Use HTTPS to protect the session ID during transmission.
  • Invalidate Sessions on Logout: Always invalidate the session to clear sensitive data when users log out.

By following these steps, you can effectively manage user sessions using HttpSession in your Jakarta Servlets-based application.

Maven dependencies

<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.1.0</version>
    <scope>provided</scope>
</dependency>

Maven Central

How do I read request parameters using HttpServletRequest?

In a Jakarta EE (or formerly Java EE) web application, you can use the HttpServletRequest object to read request parameters sent by a client (e.g., from a form, URL query string, or other mechanisms). Below are the common ways to read the parameters:

1. Using getParameter(String name)

This method is used when you need to retrieve a single request parameter by its name. If the parameter doesn’t exist, it will return null.

package org.kodejava.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebServlet("/myServlet")
public class ExampleServlet extends HttpServlet {

   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
           throws ServletException, IOException {
      // Retrieve a single parameter
      String paramValue = request.getParameter("paramName");

      // Check if the parameter exists
      if (paramValue != null) {
         response.getWriter().println("Value of paramName: " + paramValue);
      } else {
         response.getWriter().println("Parameter 'paramName' not found.");
      }
   }
}

2. Using getParameterNames()

This method allows you to retrieve all parameter names as an Enumeration<String>. You can then iterate through them to get individual values.

package org.kodejava.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.util.Enumeration;

@WebServlet("/myServlet")
public class ExampleServlet extends HttpServlet {

   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
           throws ServletException, IOException {
      Enumeration<String> parameterNames = request.getParameterNames();

      while (parameterNames.hasMoreElements()) {
         String paramName = parameterNames.nextElement();
         String paramValue = request.getParameter(paramName);

         response.getWriter().println(paramName + ": " + paramValue);
      }
   }
}

3. Using getParameterValues(String name)

Use this method if you expect the parameter to have multiple values (e.g., a checkbox group or multiple selections from a dropdown), as it returns an array of String.

package org.kodejava.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;

@WebServlet("/myServlet")
public class ExampleServlet extends HttpServlet {

   @Override
   protected void doPost(HttpServletRequest request, HttpServletResponse response)
           throws ServletException, IOException {
      // Retrieve multiple values for a single parameter
      String[] values = request.getParameterValues("multiParamName");

      if (values != null) {
         response.getWriter().println("Values of multiParamName:");
         for (String value : values) {
            response.getWriter().println(value);
         }
      } else {
         response.getWriter().println("No values provided for 'multiParamName'.");
      }
   }
}

4. Using getParameterMap()

If you need to retrieve all parameters along with their values, you can use getParameterMap(). This returns a Map<String, String[]> where the key is the parameter name, and the value is an array of String containing parameter values.

package org.kodejava.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.util.Map;

@WebServlet("/myServlet")
public class ExampleServlet extends HttpServlet {

   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response)
           throws ServletException, IOException {
      Map<String, String[]> parameterMap = request.getParameterMap();

      for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
         String paramName = entry.getKey();
         String[] paramValues = entry.getValue();

         response.getWriter().println(paramName + ": ");
         for (String value : paramValues) {
            response.getWriter().println("\t" + value);
         }
      }
   }
}

Example Usage Scenarios:

  1. GET Request with Query Parameters:
    URL: `http://localhost:8080/myServlet?param1=value1&param2=value2`

    • request.getParameter("param1") will return "value1"
    • request.getParameter("param2") will return "value2"
  2. POST Request with Form Data:
    If a form submits data like:

    <form method="post" action="/myServlet">
       <input type="text" name="username" value="john123" />
       <input type="password" name="password" value="secret" />
       <input type="submit" />
    </form>
    
    • Use request.getParameter("username") to get "john123".
    • Use request.getParameter("password") to get "secret".

Make sure to handle null values and encode your response properly when writing them back to the client to prevent issues like XSS (Cross-Site Scripting).

Maven dependencies

<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.1.0</version>
    <scope>provided</scope>
</dependency>

Maven Central

How do I handle GET and POST requests in Jakarta Servlets?

Handling GET and POST requests in Jakarta Servlets involves overriding the doGet() and doPost() methods provided by the HttpServlet class. Here’s a step-by-step guide:


1. Import Necessary Packages

First, ensure you import the jakarta.servlet and jakarta.servlet.http packages in your servlet class.

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

2. Create a Servlet Class

Your servlet class should extend the HttpServlet class. The doGet() method will handle GET requests, while the doPost() method will handle POST requests.


3. Override doGet and doPost Methods

  • Use the HttpServletRequest object to get request data.
  • Use the HttpServletResponse object to send a response to the client.

4. Example Code

Here’s a complete example:

package org.kodejava.servlet;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

@WebServlet("/example")  // Annotation to map this servlet to "/example"
public class ExampleServlet extends HttpServlet {

    // Handles GET requests
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // Set response content type
        response.setContentType("text/html");

        // Get query parameter (e.g., ?name=John)
        String name = request.getParameter("name");

        // Prepare response
        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("<h1>Hello, " + (name != null ? name : "Guest") + "!</h1>");
        out.println("<form method='POST' action='/example'>");
        out.println("<label for='postName'>Enter your name:</label>");
        out.println("<input type='text' id='postName' name='name'>");
        out.println("<button type='submit'>Submit</button>");
        out.println("</form>");
        out.println("</body></html>");
    }

    // Handles POST requests
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        // Set response content type
        response.setContentType("text/html");

        // Get form data (e.g., from POST body)
        String name = request.getParameter("name");

        // Prepare response
        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("<h1>Thank you, " + (name != null ? name : "Guest") + "!</h1>");
        out.println("<a href='/example'>Go back</a>");
        out.println("</body></html>");
    }
}

5. Explanation

  • Annotations: The @WebServlet("/example") annotation maps this servlet to the /example URL.
  • GET and POST
    • The doGet() method handles requests sent as GET, typically used when the client fetches data.
    • The doPost() method handles requests sent as POST, commonly used to send form data to the server.
  • Parameters: Use request.getParameter("paramName") to retrieve parameters from the request.

6. Deploy and Test

  1. Add the servlet to your Jakarta EE web application.
  2. Access the servlet:
    • GET request: Open `http://localhost:8080/your-app-context/example` in a browser.
    • POST request: Submit the HTML form created in doGet() or use a tool like Postman.

7. Keynotes

  • Always handle exceptions (IOException and ServletException) properly in production.
  • Use appropriate HTTP response headers and status codes.
  • Consider character encoding (request.setCharacterEncoding("UTF-8") and response.setCharacterEncoding("UTF-8")) for supporting special characters.

This is how you handle GET and POST requests in a Jakarta Servlet effectively!

Maven dependencies

<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.1.0</version>
    <scope>provided</scope>
</dependency>

Maven Central

How do I deploy a WAR file in Tomcat Servlet Container?

In this post I will show you the step-by-step instructions to deploy a WAR file in Tomcat 11:

1. Build Your WAR File

A WAR file (.war) is a packaged web application. To build it:

  • If you’re using Maven, run the following command in your project directory:
    mvn clean package
    

    This generates a WAR file under the target/ folder.

  • If you’re using other tools (e.g., Gradle, IDE), export the WAR file using the packaging/export option.

2. Install and Configure Tomcat 11

  • Download Tomcat 11 from the official website: Apache Tomcat Downloads
  • Extract the downloaded ZIP/TAR file to a desired directory.
  • Navigate to the conf/ directory and optionally configure the file server.xml to customize ports, define your hostname, or adjust server parameters (optional for default usage).

3. Start Tomcat

  • Navigate to the bin/ directory.
  • Run the startup script as per your operating system:

    • On Windows:
      startup.bat
      
    • On Linux/Mac:
      ./startup.sh
      
  • By default, Tomcat runs on port 8080. Check if it is running by accessing:
    http://localhost:8080/
    

    If Tomcat is running, its welcome page should appear.

4. Deploy Your WAR File

You have two primary ways to deploy the WAR file:

a) Manual Deployment

  1. Copy the WAR file to Tomcat’s webapps/ directory:
    • Navigate to the webapps/ directory inside your Tomcat installation path.
    • Copy your WAR file (e.g., HelloWorld.war) into this folder.
      cp /path/to/HelloWorld.war /path/to/tomcat/webapps/
      
  2. Restart Tomcat:
    • Stop and restart Tomcat for new deployments to take effect, using:
      shutdown.bat/startup.bat (Windows)
      ./shutdown.sh && ./startup.sh (Linux/Mac)
      
  3. Access Your Application:
    • By default, the application will be available at:
      http://localhost:8080/<war-file-name>/
      
    • For example:
      http://localhost:8080/HelloWorld/
      

b) Upload via Tomcat Manager (Web UI)

  1. Go to the Tomcat Manager application at:
  2. Log in with your username and password:
    • Default username: admin
    • Default password: admin (or use the one you set in tomcat-users.xml file under conf/).
      To set new credentials, update the conf/tomcat-users.xml file by adding:

      <role rolename="manager-gui"/>
      <user username="admin" password="admin" roles="manager-gui"/>
      
  3. Scroll to the Deploy section:
    • Under “WAR file to deploy,” choose the WAR file from your system.
    • Click the Deploy button.
  4. Access Your Application:
    • The application URL will be:
      http://localhost:8080/<war-file-name>/
      

5. Check Logs for Errors (if any)

If the application is not working, check Tomcat logs:

  • Log files are located in the logs/ directory of your Tomcat installation.
  • The most relevant logs include:
    • catalina.<date>.log – Main log file for Tomcat.
    • localhost.<date>.log – Logs specific to deployed applications.

6. Stop Tomcat (if needed)

If you wish to shut down Tomcat:

  • Navigate to the bin/ directory.
  • Use the shutdown script:
    • On Windows:
      shutdown.bat
      
    • On Linux/Mac:
      ./shutdown.sh
      

Summary of Key Directories in Tomcat

Directory Purpose
bin/ Contains scripts to start and stop Tomcat.
conf/ Stores configuration files like server.xml.
webapps/ Holds deployed WAR files.
logs/ Contains log files for troubleshooting.

How to build WAR file for Jakarta EE Servlet Container?

To build a WAR file for your Jakarta EE servlet application, the steps will vary depending on the build tool you are using. In this post I will show you how to use Apache Maven, build it in the IDE, or create it manually. Here’s how you can build a WAR file:


1. Using Maven

Maven is a widely used build tool in Java projects. If your project uses Maven, follow these steps:

a) Add WAR Packaging to pom.xml

Your pom.xml file should include these configurations:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.kodejava</groupId>
    <artifactId>helloworld-servlet</artifactId>
    <version>1.0</version>
    <packaging>war</packaging> <!-- Specify that the packaging is WAR -->
    <name>HelloWorldServlet</name>

    <dependencies>
        <!-- Jakarta Servlet dependency -->
        <dependency>
            <groupId>jakarta.servlet</groupId>
            <artifactId>jakarta.servlet-api</artifactId>
            <version>6.1.0</version>
            <scope>provided</scope> <!-- mark as provided since the container will provide the API -->
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- WAR Plugin -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.4.0</version>
                <configuration>
                    <failOnMissingWebXml>false</failOnMissingWebXml> <!-- Optional for Servlet 3.0+ -->
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

b) Directory Structure for WAR Projects

Ensure your project follows the standard Maven directory structure:

src/
└── main/
    ├── java/                     --> Your Java source files
    │   └── org/kodejava/servlet/HelloWorld.java
    ├── resources/                --> (Optional) Resource files
    └── webapp/                   --> Web application files
        ├── WEB-INF/              --> Configuration files
        │   └── web.xml           --> web.xml file (if required)
        └── index.html            --> Static files (Optional)

Important Notes:

  • webapp/WEB-INF/ is the location for configuration files. For modern servlets with annotations like @WebServlet, a web.xml file may not be required.
  • Additional static resources (like HTML, CSS, or JS files) can be placed under webapp/.

c) Build the WAR File

Run the following Maven command:

mvn clean package

Once the build is successful, the WAR file will be generated in the target/ directory, named as <artifactId>-<version>.war.

For instance: target/helloworld-servlet-1.0.war


2. Using an IDE (IntelliJ IDEA, Eclipse)

Some IDEs let you build a WAR file without using Maven explicitly. For IntelliJ IDEA:

a) Configure Your Project as a WAR

  1. Open your project in IntelliJ.
  2. Go to File > Project Structure > Artifacts.
  3. Click on the + button and choose Web Application: Archive > From Modules with Dependencies.
  4. Select your module and specify the location of your web and META-INF folders.
  5. Apply and save changes.

b) Build the WAR File

  1. Go to Build > Build Artifacts > Build.
  2. The WAR file will be created in the specified output folder.

3. Manually Create a WAR

If you’re not using a build tool and want to manually create a WAR file:

a) Prepare the Required Directory Structure

Manually create a structure similar to this:

project/
└── WEB-INF/
    ├── web.xml           --> Optional (for configurations)
    └── classes/          --> Compiled `.class` files (Java code goes here)
        └── org/kodejava/servlet/HelloWorld.class

Copy all your .class files, resources, and configuration files into their respective folders.

b) Create the WAR File

Navigate to the folder containing the root project directory and run:

jar -cvf HelloWorldServlet.war *

This command will package your project into a .war file.


By following any of these methods, you’ll have a .war file ready for deployment in your Tomcat 11 server.

How to Use the Java 10 JDK Command Line Tools

The Java 10 JDK offers several command-line tools for developers to use. Here’s an overview of some useful tools and related features:

1. JShell (Interactive Java REPL)

The jshell tool allows developers to experiment interactively by evaluating Java expressions, statements, and code snippets without the need to set up a complete program. It was introduced as part of JDK 9 but is also available in Java 10.

You can use JShell via:

  • Command line: Just type jshell in your terminal/command prompt.
  • IntelliJ IDEA: Open the JShell console through Tools > JShell Console in the IDE. This allows trying smaller snippets of code and experimenting interactively [1].

2. Java Compiler (javac)

The javac tool is the standard way to compile Java source code into bytecode. In Java 10, the --release flag can be used to ensure compatibility with earlier JDK releases.

Command:

javac --release <version> FileName.java

To compile your code:

  1. Open a terminal.
  2. Navigate to the directory containing the .java file.
  3. Run the javac command followed by the file’s name.

3. Java Runner (java)

The java tool is used to execute compiled Java applications or scripts. Java 10 also supports temporary files and improved APIs for startup optimizations.

Command example:

java FileName

4. Java Flight Recorder and Other Tools

Java Flight Recorder is useful for profiling and analyzing runtime performance. In JDK 10, you need to enable UnlockCommercialFeatures if using the Oracle JDK.

For example:

java -XX:+UnlockCommercialFeatures -XX:StartFlightRecording=duration=60s,filename=myrecording.jfr MyApplication

This is useful for monitoring or debugging [4].


5. JLink

The jlink tool lets you create runtime images that include all the modules your application requires (introduced in JDK 9). With Java 10, improvements were made for better custom image creation.

Command example:

jlink --module-path <modules-path> --add-modules <module-name> --output <destination-folder>

This tool is handy when distributing lightweight application bundles. IDEs like IntelliJ IDEA also provide options to integrate it into Maven or Gradle builds [5].


6. Managing Executable Scripts

Create and run Java commands or files directly as scripts without needing to compile them. This concept started gaining traction with JDK 11’s “shebang” support but can also apply lightly to Java 10 for executable bundling purposes [6].


7. General IntelliJ IDEA Features for Java 10

IntelliJ IDEA helps users by automatically configuring and detecting Java 10 features, including modular programming. Several integrations for JDK tools like javac, java, and jlink make development smoother [7].


How to Set Up Java 10 and Compile Your First Program

To set up Java 10 and compile your first program, follow these steps. Additionally, you’ll learn about Java 10’s var keyword feature once your setup is complete.


Steps to Set Up Java 10

  1. Download Java 10 JDK:
  2. Install Java 10:
    • Follow the installation wizard to install the JDK.
    • Don’t forget to note the installation path (e.g., C:\Program Files\Java\jdk-10).
  3. Set up the Environment Variables:
    • Add the JDK bin directory to the PATH variable:
      1. Go to System PropertiesAdvancedEnvironment Variables.
      2. Under System Variables, find the Path variable and add the JDK’s bin directory (e.g., C:\Program Files\Java\jdk-10\bin).
    • Verify the setup:
      • Open the command prompt or terminal and type:
        text
        java -version

        You should see the version as Java 10.
  4. Install an IDE or Use a Text Editor:
    • Download and install an IDE like IntelliJ IDEA, Eclipse, or Visual Studio Code (or use a simple text editor).

Compile and Run Your First Java Program

  1. Write the Java Program:
    Create a file named HelloWorld.java with the following content:

    public class HelloWorld {
       public static void main(String[] args) {
           System.out.println("Hello, World! Welcome to Java 10!");
       }
    }
    
  2. Compile Your Program:
    From the command prompt, navigate to the directory containing HelloWorld.java, and run:

    javac HelloWorld.java
    

    This will create a compiled HelloWorld.class file.

  3. Run Your Program:
    Execute the compiled program using:

    java HelloWorld
    

    You should see the output:

    Hello, World! Welcome to Java 10!
    

Using the var Keyword in Java 10

To explore Java 10’s var keyword for local variable type inference, you can enhance your program. Update the HelloWorld class as follows:

package org.kodejava.basic;

import java.util.List;

public class HelloWorld {
   public static void main(String[] args) {
      var message = "Hello, Java 10!";
      var numbers = List.of(1, 2, 3);

      System.out.println(message);
      for (var number : numbers) {
         System.out.println("Number: " + number); // Using 'var' in loop
      }
   }
}
  • Save the changes as HelloWorld.java.
  • Recompile and run using the steps above.

You’ll see the output:

Hello, Java 10!
Number: 1
Number: 2
Number: 3

The var keyword simplifies variable declarations without compromising type safety, ensuring better code readability and brevity.


Conclusion

You’ve successfully set up Java 10, compiled, and executed your first program. Additionally, you explored how to use Java 10’s var keyword for type inference. Keep experimenting with these features to leverage Java 10’s capabilities!

How do I create a basic servlet using the HttpServlet class?

To create a basic servlet using the HttpServlet class in Jakarta Servlet API, follow these steps:

Steps to Create a Basic Servlet:

  1. Create a Java Class Extending HttpServlet:
    • Your servlet class should extend the HttpServlet class provided in the Jakarta Servlet API.
  2. Define Servlet Annotations or Configuration:
    • Use the @WebServlet annotation to define the servlet and map it to a URL pattern. Alternatively, you can configure it in the web.xml file if annotations are not used.
  3. Override doGet or doPost Methods:
    • Override doGet for handling GET requests and doPost for POST requests (based on the type of request you expect).
  4. Set the Content Type in Response:
    • The response content type can be set using response.setContentType().
  5. Write the Response to Output:
    • Use a PrintWriter object received from response.getWriter() to write the response content.

Code Example:

Here’s a sample implementation for a basic servlet:

package org.kodejava.servlet;

import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.io.PrintWriter;

@WebServlet(name = "HelloWorldServlet", urlPatterns = {"/hello", "/helloworld"})
public class HelloWorld extends HttpServlet {

   @Override
   protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
      response.setContentType("text/html");

      PrintWriter writer = response.getWriter();
      writer.println("<html>");
      writer.println("<head><title>Hello World Servlet</title></head>");
      writer.println("<body>Hello World! How are you doing?</body>");
      writer.println("</html>");
      writer.close();
   }
}

Explanation of Code:

  1. @WebServlet Annotation:
    • name: Specifies the servlet name.
    • urlPatterns: Maps the servlet to specific URL patterns (in this example, /hello).
  2. doGet Method:
    • Handles GET requests sent to /hello.
    • Sets the content type for the response to text/html so that the client knows the returned content is HTML.
    • Dynamically writes an HTML page to the response using the PrintWriter.
  3. Response Lifecycle:
    • Any request to http://<server>:<port>/hello is routed to the doGet method based on the @WebServlet mapping.

Deploying the Servlet in Jakarta EE:

  • Place your servlet class in the Java package structure under src/main/java.
  • Ensure your project is configured to use a Jakarta Servlet container like Apache Tomcat or Jakarta EE compatible application server.
  • Deploy the .war file or run directly if your IDE supports it.

To build the .war file you can follow in steps in this post: How to build WAR file for Jakarta EE Servlet Container?.

Maven dependencies

<dependency>
    <groupId>jakarta.servlet</groupId>
    <artifactId>jakarta.servlet-api</artifactId>
    <version>6.1.0</version>
    <scope>provided</scope>
</dependency>

Maven Central

How to Use the var Keyword for Local Variable Type Inference in Java 10

In Java 10, the var keyword was introduced to allow local variable type inference. This means that when you declare a local variable, the compiler automatically infers its type based on the initialization value. This improves readability and reduces boilerplate code, especially when working with complex types, without compromising type safety.

Here’s a guide on how to use the var keyword:


1. Declaring and Initializing Local Variables with var

The var keyword replaces explicitly specifying the type while declaring local variables. However, you must initialize the variable at the time of declaration, as the compiler needs an expression to infer the type.

// Example of using var keyword
var message = "Hello, Java 10!";  // Inferred as String
var number = 10;                 // Inferred as int
var list = List.of("apple", "banana", "orange"); // Inferred as List<String>

Here, the type of each variable is deduced by the Java compiler:

  • message: String
  • number: int
  • list: List<String>

2. Scopes Where var Can Be Used

The var keyword can only be used in specific contexts:

a. Local Variables in Methods

public void demoVarUsage() {
    var name = "John";      // Inferred as a String
    var age = 30;           // Inferred as an int

    System.out.println(name + " is " + age + " years old.");
}

b. Loop Variables (for-each or traditional for-loops)

// for each loop
var items = List.of("A", "B", "C");
for (var item : items) {
    System.out.println(item);  // item inferred as String
}

// traditional for loop
for (var i = 0; i < 10; i++) {
    System.out.println(i);     // i inferred as int
}

c. Local Variables in Lambda Expressions

var lambda = (String x, String y) -> x + y; // Explicit lambda types
System.out.println(lambda.apply("Java", "10"));

3. Restrictions on var Usage

While var is versatile, there are limitations:

  1. Cannot Be Used Without Initialization
    var name; // Compilation error: cannot infer type
    name = "John";
    
  2. Cannot Be Used with Null Initializer
    var something = null; // Compilation error
    
  3. Cannot Be Used as a Method Parameter, Field, or Return Type
    The var keyword is limited to local variables inside methods and blocks, as well as loop variables. It cannot be used:

    • As a return type of method.
    • As a field in a class.
    • As a method parameter.
    public var getName() {    // Compilation error: 'var' is not allowed here
       return "Java";
    }
    
  4. Cannot Mix Explicit Types and var
    var name = "John", age = 30; // Compilation error
    var name = "John";
    var age = 30;               // Declare separately
    
  5. Cannot Infer Ambiguous Types
    var result = process();  // If `process()` returns Object, type can't be narrowed.
    

4. Advantages of Using var

  • Improved Code Readability: Reduces verbosity for complex types.
    var map = new HashMap<String, List<Integer>>(); // Cleaner than HashMap<String, List<Integer>>
    
  • Consistent with Type Inference: Makes Java more modern and closer to languages like Kotlin, Scala, or C#.


5. Best Practices

  • Avoid overusing var to ensure code remains understandable.
  • Use meaningful names for variables to compensate for the lack of explicit type.
  • Use var only when the type is obvious from the context.

Example Code:

package org.kodejava.basic;

import java.util.List;

public class VarExample {
   public static void main(String[] args) {
      // Using var for various local variable declarations
      var name = "Alice";                        // String
      var age = 25;                              // int
      var fruits = List.of("Apple", "Banana");  // List<String>

      System.out.println(name + " likes " + fruits);

      for (var fruit : fruits) {
         System.out.println(fruit);  // Inferred as String
      }

      var sum = add(10, 20);  // Inferred as int
      System.out.println("Sum: " + sum);
   }

   private static int add(int a, int b) {
      return a + b;
   }
}

Output:

Alice likes [Apple, Banana]
Apple
Banana
Sum: 30

The var keyword is a helpful addition, especially for simplifying local variables with inferred types, keeping code concise and readable while retaining type safety!

How do I chain operations using map and flatMap in Optional?

In Java, the Optional class provides methods like map and flatMap to enable functional-style transformations and chaining of operations without explicitly checking for null. Here is an explanation of when and how to use these methods effectively.

1. map

  • The map method is used when you want to transform the value inside the Optional if it is present.
  • It takes a function (Function<? super T, ? extends U>) as an argument and applies it to the value inside the Optional, returning a new Optional<U>.
Optional<String> optionalName = Optional.of("John");

// Use map to transform the value
Optional<Integer> nameLength = optionalName.map(String::length);

System.out.println(nameLength); // Output: Optional[4]

2. flatMap

  • The flatMap method is used when the mapping function itself returns an Optional. This helps avoid creating nested Optional<Optional<U>>.
  • It is commonly used in scenarios where the result of the transformation step is another Optional.
Optional<String> optionalName = Optional.of("John");

// Use flatMap when the mapping function returns Optional
Optional<String> upperCaseName = optionalName.flatMap(name -> Optional.of(name.toUpperCase()));

System.out.println(upperCaseName); // Output: Optional[JOHN]

How to Chain map and flatMap

You can chain map and flatMap when transforming optional values or resolving optional dependencies step-by-step.

Example: Chaining map and flatMap

Imagine you have a class Person that contains an Optional<Address> and an Address that has an Optional<String> representing a zip code. You want to extract the zip code directly from the Person, if it exists.

package org.kodejava.util;

import java.util.Optional;

class Person {
    private Optional<Address> address;

    public Person(Optional<Address> address) {
        this.address = address;
    }

    public Optional<Address> getAddress() {
        return address;
    }
}

class Address {
    private Optional<String> zipCode;

    public Address(Optional<String> zipCode) {
        this.zipCode = zipCode;
    }

    public Optional<String> getZipCode() {
        return zipCode;
    }
}

public class OptionalExample {

    public static void main(String[] args) {
        // Create nested Optional structure
        Optional<String> zipCode = Optional.of("12345");
        Address address = new Address(zipCode);
        Person person = new Person(Optional.of(address));

        // Chain map and flatMap to get the zip code
        Optional<String> zipCodeResult = person.getAddress()
                .flatMap(Address::getZipCode); // Unwrap address and zipCode

        System.out.println(zipCodeResult); // Output: Optional[12345]
    }
}

In this example:

  • person.getAddress() returns an Optional<Address>.
  • flatMap(Address::getZipCode) ensures the zip code is directly returned as an Optional<String> instead of Optional<Optional<String>>.

Comparison of map and flatMap

Method When to Use Output Type
map When the mapping function returns a value (non-Optional). Optional<U>
flatMap When the mapping function returns an Optional. Optional<U> (avoids nesting)

Why the Difference?

The distinction ensures that Optional doesn’t wrap nested Optional values.

  • Using map with a function that returns Optional would result in Optional<Optional<U>>.
  • flatMap flattens this into a single Optional<U>.

Common Mistake:

// Incorrect: results in Optional<Optional<String>>
Optional<Optional<String>> zipCodeResult = person.getAddress()
    .map(Address::getZipCode);

// Correct: use flatMap to avoid nesting
Optional<String> correctZipCodeResult = person.getAddress()
    .flatMap(Address::getZipCode);

Key Takeaways

  1. Use map for simple transformations where the result is a direct value.
  2. Use flatMap where the result of the mapping is itself an Optional.
  3. Chain them together for complex operations on nested optionals, avoiding null checks.