Skip to main content

Java

Complete Guide to Enabling HTTPS on Apache Tomcat

When your web application moves beyond hobby status, the first hardening step is wrapping every byte in TLS. Tomcat makes the process painless once you understand where the moving parts live. In this guide you will create (or import) a certificate, wire it into Tomcat’s connector, and verify that the padlock appears in every browser. Why HTTPS on Tomcat Matters Plain HTTP exposes cookies, credentials, and payloads to anyone on the wire. Search engines penalize insecure sites, browsers now flag non-TLS pages as “Not Secure”, and compliance frameworks such as PCI-DSS simply forbid clear-text traffic. Turning on HTTPS: Encrypts data in transit Proves server identity to clients Unlocks HTTP/2 and modern protocols Keeps Google and your security team happy Prerequisites and Environment Before touching configuration files ensure: Tomcat 9.x or 10.x is installed and starts cleanly on port 8080 JAVA_HOME points to JDK 8+ (keytool comes with the JDK) OpenSSL 1.1+ if you prefer generating private keys externally Server DNS name (e.g. app.ankurm.com) resolves to the VM or container

Log4j2 Logging Levels – Complete Guide

Imagine your application's log file as a constant stream of information. In a production crisis, this stream becomes a firehose. How do you find the single critical error message in a flood of routine status updates? The answer lies in logging levels. These aren't just labels; they are the fundamental control mechanism in Log4j2. They allow developers to filter noise, pinpoint failures, and monitor application health effectively. Mastering this hierarchy is the key to creating logs that are helpful, not overwhelming. This guide explores Log4j2’s levels, from configuration to real-world best practices. The Logging Threshold: How Levels Work Think of logging levels as a gatekeeper's volume knob. Each log message you write (an "event") is assigned a level of importance, or severity. The logger itself is then configured with a threshold level. When a message arrives, the framework compares its severity to the logger's threshold. Only messages at or above the configured threshold are processed and sent to their destination (like a file or the console). This simple mechanism provides fine-grained control over your application's verbosity. You can run the exact same code in different environments and get drastically different log outputs—all without changing a single line of Java. In development, you might set the threshold low to see everything. In production, you set it high to capture only significant errors.

Understanding JUnit 5 @AfterEach Annotation with Practical Examples

This post has been merged into a single, updated guide covering both @BeforeEach and @AfterEach together, with a per-method lifecycle diagram and a JUnit 6 compatibility note: JUnit @BeforeEach and @AfterEach: The Complete Test Lifecycle Guide. Everything that was here…

Compact Strings in Java: Measured with JOL on JDK 25 (plus Compact Object Headers)

Compact Strings measured with JOL on JDK 25: one million strings weigh 89.8 MB, against 132.0 MB with -XX:-CompactStrings (31.9% less), and one euro sign per string makes them 49% bigger. Includes the Latin-1 vs UTF-16 coder byte, byte[] sizes by length, a JMH comparison and compact object headers (opt-in on JDK 25, default on JDK 27).

Java Stream API: How to Get the Last Element

Java Streams provide elegant ways to process collections, but retrieving the last element isn't as straightforward as calling a getLast() method. Since streams are designed for sequential processing without inherent indexing, developers need specific techniques to fetch the final element efficiently. This guide explores practical approaches to solve this common programming challenge. Whether you're processing large datasets or building concise functional pipelines, understanding these methods will help you write cleaner, more maintainable code. The Core Challenge Unlike List or Deque collections, Java Streams don't maintain bidirectional iteration or direct index access. Once elements pass through the pipeline, they're consumed. This design makes operations like stream().last() impossible without workarounds. However, several clever techniques leverage stream reduction and size information to achieve the desired result. Approach 1: Using reduce() Method The reduce() operation processes each element while retaining only the last one seen. This approach works beautifully for both sequential and parallel streams. import java.util.Optional; import java.util.stream.Stream; public class LastElementWithReduce { public static void main(String[] args) { Stream fruitStream = Stream.of("apple", "banana", "cherry", "date"); Optional lastElement = fruitStream.reduce((first, second) -> second); lastElement.ifPresent(element -> System.out.println("Last fruit: " + element) ); } }

Get Year, Month, Day from Date in Java

Extracting individual date components like year, month, and day is a common requirement in Java applications. Whether you're working with legacy Date objects or modern date-time APIs, this guide will show you multiple approaches to accomplish this task efficiently. 1. Using Calendar Class (Legacy Approach) Before Java 8, the Calendar class was the standard way to extract date fields from a Date object. While it's still supported, this approach is considered outdated and less intuitive than modern alternatives. import java.util.Calendar; import java.util.Date; public class DateExtractor { public static void main(String[] args) { Date currentDate = new Date(); Calendar calendar = Calendar.getInstance(); calendar.setTime(currentDate); int year = calendar.get(Calendar.YEAR); int month = calendar.get(Calendar.MONTH) + 1; // Months are 0-based int day = calendar.get(Calendar.DAY_OF_MONTH); System.out.println("Year: " + year); System.out.println("Month: " + month); System.out.println("Day: " + day); } } Note: The Calendar.MONTH field returns values from 0 (January) to 11 (December), so you need to add 1 to get the standard 1-12 month numbering.

GraalVM Native Images for Spring Boot 4.1: The Reflection Trap, the Fix, and the Trap Inside the Fix

GraalVM native-image compiles a Spring Boot 4.1 app into a binary that starts in 0.09 seconds instead of 3.5 -- but only after a real ClassNotFoundException, a fix using the tracing agent, and a metadata-collision trap that silently undoes that fix. Rewritten with verified Boot 4.1.1 and current GraalVM versions, honest costs, and where Project Leyden fits as the non-native alternative.

Solved: Bean property ‘configurationClass’ is not writable or has an invalid setter method

Every developer has those moments where a seemingly simple task turns into a head-scratching puzzle. This error, encountered while trying to configure a custom LocalSessionFactoryBean in Spring Boot, is a perfect example of a subtle type mismatch causing a cryptic failure. The Scenario and the Error The goal was to set up a custom SessionFactory bean using Spring's LocalSessionFactoryBean. The initial, problematic configuration was: @Configuration public class HibernateConfig { @Bean public LocalSessionFactoryBean sessionFactory() { LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); // … set data source, hibernate properties … // This line caused the error! sessionFactory.setConfigurationClass(org.hibernate.cfg.Configuration.class); return sessionFactory; } } This configuration resulted in the following exception upon application startup: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory': Bean property 'configurationClass' is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?

Demystifying Thread Safety in Java: A Practical Guide

Imagine you’re collaborating on a Google Doc. You write a sentence, and at the exact same moment, your colleague deletes the paragraph it’s in. The result? Chaos. A corrupted document, lost work, and confusion. This is precisely what can happen inside your Java application when multiple threads—independent paths of execution—try to access and modify the same data simultaneously. Welcome to the world of concurrency and the critical concept of thread safety. An object or a piece of code is considered “thread-safe” if it continues to function correctly, without causing data corruption or unexpected behavior, even when accessed by multiple threads at the same time. Getting this right is the difference between a robust, predictable application and one that suffers from mysterious, hard-to-reproduce bugs. The Villain of Our Story: The Race Condition The most common concurrency problem is the race condition. It occurs when multiple threads “race” to access and change a shared resource, and the final outcome depends on the unpredictable order in which they execute.

Solved: java.lang.NoClassDefFoundError: org/hibernate/cache/CacheProvider

Encountering a java.lang.NoClassDefFoundError can be one of the most frustrating issues when working with Java applications. This particular error — org/hibernate/cache/CacheProvider — is a common stumbling block for developers upgrading or mixing Hibernate versions. Let's break down what it means and how to fix it. Understanding the Error The NoClassDefFoundError occurs when the JVM tries to load a class by its fully qualified name but cannot find its definition at runtime — even though the class existed at compile time. In this case, org.hibernate.cache.CacheProvider was the standard interface for Hibernate second-level cache integration in Hibernate 3.x. It was deprecated in Hibernate 4 and completely removed in Hibernate 5+, replaced by org.hibernate.cache.spi.RegionFactory.