How do I determine if a date falls between two dates?

Java provides different ways to determine if a certain date falls within a specified range. In this article, we’ll look at examples using the old java.util.Date and java.util.Calendar classes, as well as the newer Java Date Time API.

Using java.util.Date and java.util.Calendar

Before Java 8, you’d have to use Date or Calendar to work with dates:

package org.kodejava.datetime;

import java.util.Calendar;

public class CheckDateRange {
    public static void main(String[] args) {
        Calendar start = Calendar.getInstance();
        start.set(2024, Calendar.JANUARY, 1);
        Calendar end = Calendar.getInstance();
        end.set(2024, Calendar.DECEMBER, 31);
        Calendar target = Calendar.getInstance();
        target.set(2024, Calendar.JUNE, 15);

        if ((target.after(start) || target.equals(start)) &&
            (target.before(end) || target.equals(end))) {
            System.out.println("The date is within the range.");
        } else {
            System.out.println("The date is not within the range.");
        }
    }
}

The disadvantage with this approach is the excessive verbosity and error-prone copy-pasting necessary for setting up the Calendar instances.

The Java 8 Way – Using java.time.LocalDate

Java 8 introduced the new Java Date Time API, which replaced the inconsistent Date and Calendar classes with the more intuitive LocalDate, LocalTime, LocalDateTime, and ZonedDateTime. Here’s the same task performed using LocalDate:

package org.kodejava.datetime;

import java.time.LocalDate;

public class AnotherCheckDateRange {
    public static void main(String[] args) {
        LocalDate startDate = LocalDate.of(2024, 1, 1);
        LocalDate endDate = LocalDate.of(2024, 12, 31);
        LocalDate targetDate = LocalDate.of(2024, 6, 15);

        if ((!targetDate.isBefore(startDate)) && (!targetDate.isAfter(endDate))) {
            System.out.println("The date is within the range.");
        } else {
            System.out.println("The date is not within the range.");
        }
    }
}

In this code, startDate and endDate define the range of dates. The targetDate is the date you want to check.

The isBefore() method returns true if the targetDate is before the startDate, and the isAfter() method returns true if the targetDate is after the endDate. So, if targetDate is not before the startDate and not after the endDate, it means that the targetDate is between startDate and endDate (inclusive). If the targetDate is exactly the same as startDate or endDate, this condition will also return true.

This simplified API requires significantly less code and eliminates a number of potential bugs and inconsistencies.

Conclusion

The older java.util.Date and java.util.Calendar facilities for working with dates are widely considered difficult to use and error-prone. While they work for simple tasks, the newer Java Date Time API is recommended for all new applications due to its simplicity, consistency, and flexibility. It aligns with ISO standards and covers a comprehensive range of use-cases needed for date-time calculations. Migrating from older APIs to Java 8 Date Time API is likely advantageous for most projects.

How do I create a servlet filter to make secure cookies?

The CookieFilter class in this example is a servlet filter. Servlet filters in Java web applications are used to perform tasks such as request/response modification, authentication, logging, and more. In the context of managing cookies, a CookieFilter can be used to intercept requests and responses to handle cookie-related operations, such as setting secure attributes on cookies or checking cookie values for authentication purposes.

Here’s an example of how you can implement a CookieFilter class in Java:

package org.kodejava.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter("/*")
public class CookieFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // Initialization code, if needed
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
            throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        // Check if a session exists
        HttpSession session = httpRequest.getSession(false);
        if (session != null) {
            // Example: Set secure attribute on session cookie
            sessionCookieSecure(httpRequest, httpResponse);
        }

        // Continue the request chain
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
        // Cleanup code, if needed
    }

    private void sessionCookieSecure(HttpServletRequest request, HttpServletResponse response) {
        // Assuming the session cookie name
        String cookieName = "JSESSIONID"; 
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookie.getName().equals(cookieName)) {
                    // Set the secure attribute on the session cookie
                    cookie.setSecure(true);
                    // Update the cookie in the response
                    response.addCookie(cookie); 
                    break;
                }
            }
        }
    }
}

In this example:

  • The CookieFilter class implements the Filter interface, which requires implementing methods like init, doFilter, and destroy.
  • Inside the doFilter method, it checks if a session exists for the incoming request.
  • If a session exists, it calls the sessionCookieSecure method to set the secure attribute on the session cookie.
  • The sessionCookieSecure method iterates through cookies in the request, finds the session cookie (e.g., JSESSIONID), and sets its secure attribute to true.

You can modify this filter implementation based on your specific cookie management requirements, such as setting secure attributes on specific cookies or performing additional cookie-related tasks.

How do I configure secure cookies using web.xml?

To configure secure cookies using web.xml, you typically need to set the secure attribute on your cookie definitions. This ensures that the cookie is only sent over HTTPS connections, enhancing security by protecting sensitive information from being transmitted over unencrypted channels. Here’s how you can do it:

1. Define Your Servlet Filter (Optional but Recommended):

If you don’t have a servlet filter for managing cookies, you can create one. This filter can intercept requests and responses to handle cookie-related operations.

<filter>
    <filter-name>CookieFilter</filter-name>
    <filter-class>org.kodejava.servlet.CookieFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CookieFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

Replace org.kodejava.servlet.CookieFilter with the actual class that implements your cookie handling logic.

2. Configure Secure Cookie in web.xml:

Inside your web.xml, you can define cookie configurations using <session-config> and <cookie-config> elements.

<session-config>
   <cookie-config>
      <!-- Recommended to prevent client-side script access -->
      <http-only>true</http-only>
      <!-- Set all cookies to be secure -->
      <secure>true</secure>
    </cookie-config>
</session-config>
  • <secure>true</secure>: This line ensures that all cookies are marked as secure, meaning they will only be sent over HTTPS connections.
  • <http-only>true</http-only>: This line makes cookies accessible only through HTTP headers, preventing client-side scripts (like JavaScript) from accessing them. It adds another layer of security against certain types of attacks.

3. Deploy and Test:

After making these changes, deploy your web application and test it over HTTPS. Verify that cookies are being set with the secure flag by checking your browser’s developer tools (usually under the “Application” or “Storage” tab).

By following these steps, you can configure secure cookies in your Java web application using web.xml.

Notes: Setting the secure attribute in web.xml configures the default behavior for cookies created by the servlet container. However, for custom cookies that your application creates programmatically, you need to explicitly call setSecure(true) on the Cookie object to make them secure.

How do I create a table with multiple header in iText 8?

In the following example we are going to create a table with multiple header. We will create table header with columns that spans in multiple columns and rows.

Here are the steps:

  1. Create a PdfWriter object called writer with the output filename.
  2. Create a PpdfDocument object called pdf, and pass the writer object as parameter.
  3. Using try-with-resource block, create a Document object with the pdf object as constructor argument.
  4. Instantiate a Table object. In this example we define it with five columns, and set the width of the table to take the full page width.
  5. Add table header cell using addHeaderCell() method. We add cell that spans multiple rows or multiple columns using the Cell constructor parameters rowspan and colspan.
  6. Add some rows of data to the table.
  7. Finally, we add the table object to the document.

And here is the full code snippet:

package org.kodejava.itext;

import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.properties.VerticalAlignment;

import java.io.FileNotFoundException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;

public class TableWithMultiHeader {
    public static void main(String[] args) {
        TableWithMultiHeader demo = new TableWithMultiHeader();
        demo.createTable();
    }

    private void createTable() {
        try {
            PdfWriter writer = new PdfWriter("multi_header_table.pdf");
            PdfDocument pdf = new PdfDocument(writer);

            try (Document document = new Document(pdf)) {
                Table table = new Table(5);
                table.setWidth(UnitValue.createPercentValue(100));

                table.addHeaderCell(new Cell(2, 1)
                        .setVerticalAlignment(VerticalAlignment.MIDDLE)
                        .setTextAlignment(TextAlignment.CENTER)
                        .add(new Paragraph("No")));
                table.addHeaderCell(new Cell(2, 1)
                        .setVerticalAlignment(VerticalAlignment.MIDDLE)
                        .setTextAlignment(TextAlignment.CENTER)
                        .add(new Paragraph("Name")));
                table.addHeaderCell(new Cell(1, 2)
                        .setTextAlignment(TextAlignment.CENTER)
                        .add(new Paragraph("Date: " + LocalDate.now()
                                .format(DateTimeFormatter.ofPattern("dd-MMM-yyyy")))));
                table.addHeaderCell(new Cell(2, 1)
                        .setVerticalAlignment(VerticalAlignment.MIDDLE)
                        .setTextAlignment(TextAlignment.CENTER)
                        .add(new Paragraph("Activity")));
                table.addHeaderCell(new Cell(1, 1)
                        .setTextAlignment(TextAlignment.CENTER)
                        .add(new Paragraph("Start Time")));
                table.addHeaderCell(new Cell(1, 1)
                        .setTextAlignment(TextAlignment.CENTER)
                        .add(new Paragraph("End Time")));

                table.addCell(new Cell()
                        .setTextAlignment(TextAlignment.RIGHT)
                        .add(new Paragraph("1")));
                table.addCell(new Cell().add(new Paragraph("Alice")));
                table.addCell(new Cell()
                        .setTextAlignment(TextAlignment.CENTER)
                        .add(new Paragraph("10:00")));
                table.addCell(new Cell()
                        .setTextAlignment(TextAlignment.CENTER)
                        .add(new Paragraph("11:00")));
                table.addCell(new Cell().add(new Paragraph("Learn ukulele basic")));

                table.addCell(new Cell()
                        .setTextAlignment(TextAlignment.RIGHT)
                        .add(new Paragraph("2")));
                table.addCell(new Cell().add(new Paragraph("Bob")));
                table.addCell(new Cell()
                        .setTextAlignment(TextAlignment.CENTER)
                        .add(new Paragraph("09:00")));
                table.addCell(new Cell()
                        .setTextAlignment(TextAlignment.CENTER)
                        .add(new Paragraph("11:00")));
                table.addCell(new Cell()
                        .add(new Paragraph("Learn piano basic")));

                document.add(table);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }
}

Running the code will give you the result shown in the image below:

Multi-header Table

Maven Dependencies

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-core</artifactId>
    <version>8.0.3</version>
    <type>pom</type>
</dependency>

Maven Central

How do I add Image to a Table in iText 8?

In this example you’ll see how to add Image to a Table when creating a PDF document using iText 8. We start by finding the image resource using getResource() method and pass the absolute path to the resource name. The getResource() method return a java.net.URL object.

With this URL object in hand we then create the ImageData object using the ImageDataFactory.create() method. To the create() factory method we pass the URL object as a parameter. Finally, we create the Image object by calling the constructor of this class and passes the ImageData object as a parameter.

Here is the complete code snippet. Below we create a Premier League Ladder table showing club current position from position 1 to 10.

package org.kodejava.itext;

import com.itextpdf.io.image.ImageData;
import com.itextpdf.io.image.ImageDataFactory;
import com.itextpdf.kernel.colors.DeviceGray;
import com.itextpdf.kernel.pdf.PdfDocument;
import com.itextpdf.kernel.pdf.PdfWriter;
import com.itextpdf.layout.Document;
import com.itextpdf.layout.borders.Border;
import com.itextpdf.layout.element.Cell;
import com.itextpdf.layout.element.Image;
import com.itextpdf.layout.element.Paragraph;
import com.itextpdf.layout.element.Table;
import com.itextpdf.layout.properties.TextAlignment;
import com.itextpdf.layout.properties.UnitValue;
import com.itextpdf.layout.properties.VerticalAlignment;

import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import static com.itextpdf.kernel.colors.DeviceGray.makeLighter;

public class TableExample {
    public static void main(String[] args) throws Exception {
        TableExample demo = new TableExample();
        demo.createTable();
    }

    private void createTable() throws Exception {
        String destination = "premier-league-ladder.pdf";
        PdfWriter writer = new PdfWriter(destination);
        PdfDocument pdf = new PdfDocument(writer);

        String[] headers = {"Position", "Club", "Played", "Won", "Drown", "Lost", "GF", "GA", "GD", "Points"};

        try (Document document = new Document(pdf)) {
            Table table = new Table(headers.length + 1);
            // Set table width to span the entire page
            table.setWidth(UnitValue.createPercentValue(100));

            URL plLogoFile = TableExample.class.getResource("/epl/pl-main-logo.png");
            ImageData plImageData = ImageDataFactory.create(Objects.requireNonNull(plLogoFile));

            table.addHeaderCell(new Cell().setBorder(Border.NO_BORDER)
                    .add(new Image(plImageData).scaleToFit(50, 50)));
            table.addHeaderCell(new Cell(1, 11).setBorder(Border.NO_BORDER)
                    .setVerticalAlignment(VerticalAlignment.MIDDLE)
                    .add(new Paragraph("Premier League Ladder").setFontSize(16).setBold()));

            for (String header : headers) {
                if (header.equals("Club")) {
                    table.addHeaderCell(new Cell(1, 2)
                            .setBackgroundColor(makeLighter(DeviceGray.GRAY))
                            .setBorderLeft(Border.NO_BORDER).setBorderRight(Border.NO_BORDER)
                            .setWidth(UnitValue.createPercentValue(28))
                            .add(new Paragraph(header)));
                } else {
                    table.addHeaderCell(newCell()
                            .setBackgroundColor(makeLighter(DeviceGray.GRAY))
                            .setWidth(UnitValue.createPercentValue(8))
                            .add(new Paragraph(header).setTextAlignment(TextAlignment.CENTER)));
                }
            }

            int position = 1;
            for (Club club : getTableData()) {
                String fileName = club.name().replace(' ', '_').toLowerCase() + ".png";
                URL logoFile = TableExample.class.getResource("/epl/logo/" + fileName);
                ImageData imageData = ImageDataFactory.create(Objects.requireNonNull(logoFile));

                table.addCell(newCell().add(newCenteredParagraph(String.valueOf(position++))));
                table.addCell(newCell().setWidth(UnitValue.createPercentValue(1))
                        .setVerticalAlignment(VerticalAlignment.MIDDLE)
                        .add(new Image(imageData).scaleAbsolute(16, 16)));
                table.addCell(newCell().setWidth(UnitValue.createPercentValue(27))
                        .add(new Paragraph(club.name())));
                table.addCell(newCell().add(newCenteredParagraph(String.valueOf(club.played()))));
                table.addCell(newCell().add(newCenteredParagraph(String.valueOf(club.won()))));
                table.addCell(newCell().add(newCenteredParagraph(String.valueOf(club.drawn()))));
                table.addCell(newCell().add(newCenteredParagraph(String.valueOf(club.lost()))));
                table.addCell(newCell().add(newCenteredParagraph(String.valueOf(club.goalsFor()))));
                table.addCell(newCell().add(newCenteredParagraph(String.valueOf(club.goalsAgainst()))));
                table.addCell(newCell().add(newCenteredParagraph(String.valueOf(club.goalDifference()))));
                table.addCell(newCell().add(newCenteredParagraph(String.valueOf(club.points()))));
            }

            document.add(table);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private Cell newCell() {
        return new Cell().setBorderLeft(Border.NO_BORDER).setBorderRight(Border.NO_BORDER);
    }

    private Paragraph newCenteredParagraph(String text) {
        return new Paragraph(text).setTextAlignment(TextAlignment.CENTER);
    }

    private List<Club> getTableData() {
        List<Club> clubs = new ArrayList<>();
        clubs.add(new Club("Arsenal", 20, 4, 4, 70, 24));
        clubs.add(new Club("Liverpool", 19, 6, 2, 64, 25));
        clubs.add(new Club("Man City", 19, 5, 3, 62, 27));
        clubs.add(new Club("Aston Villa", 17, 4, 6, 59, 37));
        clubs.add(new Club("Tottenham", 15, 5, 6, 55, 39));
        clubs.add(new Club("Man United", 15, 2, 11, 39, 39));
        clubs.add(new Club("West Ham", 12, 6, 9, 43, 47));
        clubs.add(new Club("Wolves", 12, 5, 11, 42, 44));
        clubs.add(new Club("Newcastle", 12, 4, 11, 57, 45));
        clubs.add(new Club("Brighton", 10, 9, 8, 49, 44));
        return clubs;
    }

    record Club(String name, int won, int drawn, int lost, int goalsFor, int goalsAgainst) {
        public int played() {
            return won + drawn + lost;
        }

        public int goalDifference() {
            return goalsFor - goalsAgainst;
        }

        public int points() {
            return (won * 3) + drawn;
        }
    }
}

And here is the output of the generated PDF table:

Premier League Ladder Table

In the example above you can also see how to expand the width of the table to take the full width of the page.

table.setWidth(UnitValue.createPercentValue(100));

To span a table Cell to take multiple columns you can create a Cell object and specify the rowspan and colspan parameter.

table.addHeaderCell(new Cell(1, 2));

To remove the vertical border of the Cell you can set the left and right border by calling the setBorderLeft() and setBorderRight() method and passes Border.NO_BORDER as parameter.

new Cell().setBorderLeft(Border.NO_BORDER).setBorderRight(Border.NO_BORDER);

The data of the table is encapsulated using a record, this feature is introduced in Java 14, prior to this version you will create a simple POJO, which is a Java object with properties and related getters and setters method.

public record Club(String name, int won, int drawn, int lost, int goalsFor, int goalsAgainst) {}

Maven Dependencies

<dependency>
    <groupId>com.itextpdf</groupId>
    <artifactId>itext-core</artifactId>
    <version>8.0.3</version>
    <type>pom</type>
</dependency>

Maven Central