Java

223 posts in this section

Flight Recorder and JVM Monitoring (JEP 328)

What Is Java Flight Recorder? Java Flight Recorder (JFR) is a low-overhead, always-on profiling and diagnostics framework built into the JVM. It was a commercial feature of Oracle JDK until JEP 328 (Java 11) open-sourced it as part of OpenJDK. JFR collects data about JVM internals and application behaviour — method profiling, allocation, GC pauses, thread states, I/O, lock contention — with a typical overhead of 1–2% in production. This makes it fundamentally different from traditional profilers (JProfiler, YourKit): those profilers cause 10–50% overhead, making them impractical for production.

Continue reading »

Foreign Function & Memory API (JEP 412): First Look at Project Panama

Incubator Feature in Java 17 (JEP 412 — First Incubator). Package: jdk.incubator.foreign. Requires --add-modules jdk.incubator.foreign at compile and runtime. This API evolved significantly across Java 18 (JEP 419), 19 (JEP 424), 20 (JEP 434), and was finalized in Java 22 (JEP 454). See the Java 21 article series for the final API. This article covers the Java 17 incubator version and the Project Panama vision. Why Replace JNI? Java Native Interface (JNI) has been the way to call native code from Java since Java 1.

Continue reading »

Foreign Function & Memory API (JEP 442): Calling Native Code Without JNI

Preview Feature in Java 21 — Finalized in Java 22 (JEP 454). The API shown here is the Java 21 preview version; it is nearly identical to the final API. Why Replace JNI? Java Native Interface (JNI) has been the standard way to call native code since Java 1.1. It works but is notoriously painful: Requires writing C wrapper code for every native call Native method signatures must exactly match Java declarations (or you get silent crashes) Memory management is manual — leak native memory once and you have a slow memory leak JNI calls disable JIT optimizations around the call site Debugging native crashes through JNI is extremely difficult The Foreign Function & Memory (FFM) API replaces all of this: call native functions directly from Java, manage native memory safely with automatic lifetime management, and do it without writing a single line of C.

Continue reading »

Form Login Authentication: From Request to Session

Form Login: The Classic Web Authentication Flow Form login is the traditional authentication mechanism for server-rendered web applications. The user fills in a username and password form, the server verifies credentials, creates a session, and returns a session cookie. All subsequent requests carry that cookie. sequenceDiagram participant Browser participant SSF as Spring Security Filters participant AM as AuthenticationManager participant SS as HTTP Session Store participant Controller Browser->>SSF: GET /dashboard (unauthenticated) SSF->>SS: Save original request (RequestCache) SSF-->>Browser: 302 Redirect to /login Browser->>SSF: GET /login SSF-->>Browser: 200 HTML login page Browser->>SSF: POST /login {username, password} SSF->>AM: authenticate(UsernamePasswordToken) AM-->>SSF: Authentication (success) SSF->>SS: Store SecurityContext in session SSF-->>Browser: 302 Redirect to /dashboard\nSet-Cookie: JSESSIONID=abc123 Browser->>SSF: GET /dashboard (JSESSIONID cookie) SSF->>SS: Load SecurityContext from session SSF->>Controller: Request with authenticated user Controller-->>Browser: 200 Dashboard HTML Minimal Configuration @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .

Continue reading »

Functional Interfaces: Predicate, Function, Supplier, Consumer, and More

What Is a Functional Interface? Functional interfaces are the type system bridge that makes lambda expressions work in Java 8. Without them, the compiler would have no way to know what type to assign to a lambda. Once you understand how the 43 built-in interfaces in java.util.function are organised — and when to write your own — you will find that the same patterns (compose, chain, validate, transform) appear everywhere in a Java 8 codebase.

Continue reading »

Garbage Collection: G1GC, ZGC, Epsilon, and AppCDS

GC Changes Across Java 9–11 Release Change JEP Java 9 G1GC becomes the default GC JEP 248 Java 9 Unified GC logging (-Xlog:gc*) JEP 271 Java 10 Parallel Full GC for G1 JEP 307 Java 10 Application Class-Data Sharing (AppCDS) JEP 310 Java 11 Epsilon: No-Op GC JEP 318 Java 11 ZGC: Scalable Low-Latency GC (experimental) JEP 333 G1GC as Default (JEP 248, Java 9) G1 (Garbage-First) replaced Parallel GC as the default on systems with ≥2 CPUs and ≥2 GB heap.

Continue reading »

Generational ZGC (JEP 439): Sub-Millisecond Pauses at Any Scale

Why GC Still Matters in 2024 Even with better APIs and faster hardware, garbage collection pauses remain one of the top causes of latency spikes in Java services. A 200ms GC pause in a payment processing service is a customer-visible failure. A 50ms pause in a trading system is a missed execution window. Java 21 delivers Generational ZGC — the most capable GC Java has ever shipped — as a production-ready, non-preview feature.

Continue reading »

Handling Deserialization Errors Gracefully

The Problem: Poison Pills at Deserialization Time A malformed byte sequence — truncated JSON, wrong Avro schema, corrupt payload — throws an exception during deserialization, before the listener method is called. Without special handling, this record blocks the partition indefinitely: the consumer fetches it, fails to deserialize, and fetches it again on the next poll. sequenceDiagram participant Broker participant Container participant Deserializer loop forever without ErrorHandlingDeserializer Container->>Broker: poll() Broker-->>Container: [good-record, CORRUPT-RECORD, good-record] Container->>Deserializer: deserialize(CORRUPT-RECORD) Deserializer-->>Container: JsonProcessingException 💥 Note over Container: Partition blocked — same record on every poll end ErrorHandlingDeserializer solves this by catching the deserialization exception and wrapping it in a DeserializationException that the listener container can route to the error handler.

Continue reading »

How Spring Security Works: The Big Picture

Why Spring Security Is Hard to Learn Spring Security is not complex because the concepts are complex. Authentication and authorization are straightforward ideas. Spring Security is hard because it hides its machinery: a request comes in, something happens, an endpoint is secured or not — and without knowing the internal architecture, the behaviour feels magical and the configuration feels arbitrary. This article removes the magic. By the end, you will have the mental model needed to understand every other concept in this series.

Continue reading »

HTTP Authorization: Securing Endpoints with requestMatchers

HTTP Authorization: The Last Line of Defense AuthorizationFilter is the last filter in the Spring Security chain. After all authentication filters have run (and either set an Authentication or left it as anonymous), AuthorizationFilter makes the final access decision: allow or deny. The rules you write in authorizeHttpRequests() are evaluated in order, first match wins. flowchart TD Request[HTTP Request] --> Auth[AuthorizationFilter] Auth --> Rules{Evaluate rules\nin order} Rules -->|Rule 1 matches| Decision1{Allowed?

Continue reading »