Installing Java 25 Option 1: SDKMAN! (Recommended) SDKMAN! is the easiest way to install and switch between Java versions on macOS and Linux. # Install SDKMAN! if you don't have it curl -s "https://get.sdkman.io" | bash source "$HOME/.sdkman/bin/sdkman-init.sh" # List available Java 25 distributions sdk list java | grep "25" # Install Eclipse Temurin 25 (open-source, most common) sdk install java 25-tem # Set as default globally sdk default java 25-tem # Verify java -version # openjdk version "25" 2025-09-16 Switch between versions per project:
Continue reading »Java
223 posts in this section
Structured Concurrency (JEP 505): Preview 5 — What Changed?
Note: JEP 505 is a preview feature in Java 25 (5th preview). Enable with --enable-preview. The API has been stable for several rounds and is expected to finalize in Java 26. The Problem with Unstructured Concurrency Classic Java concurrency with ExecutorService is unstructured: you submit tasks, and those tasks have no formal relationship with the code that submitted them. This causes three recurring problems: Problem 1: Partial failure leaves orphaned tasks ExecutorService exec = Executors.
Continue reading »@MappedSuperclass: Sharing Fields Without Inheritance Tables
Introduction Almost every entity in a real application shares a few common fields: id, createdAt, updatedAt, and perhaps version. Writing these in every entity class is repetitive and error-prone. @MappedSuperclass lets you define them once in a base class that all entities extend — without creating a parent table or any inheritance mapping in the database. What Is @MappedSuperclass? @MappedSuperclass marks a class whose field mappings are inherited by subclass entities.
Continue reading »@SendTo and @KafkaHandler: Chaining Consumers and Multi-Type Dispatch
@SendTo — Chaining Listeners @SendTo on a @KafkaListener method automatically sends the return value to another Kafka topic. This is how you build event pipelines without manually calling KafkaTemplate.send() in your listener. flowchart LR T1["orders\n(OrderPlacedEvent)"] T2["orders-confirmed\n(OrderConfirmedEvent)"] T3["inventory-events\n(StockReservedEvent)"] T1 -->|"@KafkaListener\n@SendTo"| L1["confirmOrder()"] L1 --> T2 T2 -->|"@KafkaListener\n@SendTo"| L2["reserveStock()"] L2 --> T3 Basic @SendTo @KafkaListener(topics = "orders", groupId = "confirmation-service") @SendTo("orders-confirmed") public OrderConfirmedEvent onOrder(OrderPlacedEvent event) { // Return value is automatically sent to "orders-confirmed" return new OrderConfirmedEvent( event.
Continue reading »@Transactional in Depth: Propagation, Isolation, and Rollback
What @Transactional Does @Transactional tells Spring to wrap the annotated method in a database transaction. Spring opens the transaction before the method starts and commits (or rolls back) when it ends. The annotation works via an AOP proxy — understanding this proxy model is essential for avoiding the most common @Transactional bugs. The AOP Proxy Model Spring creates a proxy around your bean. When code outside the bean calls a @Transactional method, the call goes through the proxy, which manages the transaction:
Continue reading »Actuator Security and Production Hardening
The Actuator Security Problem Spring Boot Actuator exposes endpoints that reveal sensitive information about your application — environment variables, configuration properties, heap dumps, thread dumps, and the ability to shut down the application remotely. An exposed /actuator/env endpoint can leak database passwords, API keys, and JWT signing secrets. An exposed /actuator/shutdown is a denial-of-service button. Actuator security is not optional in production. Actuator Endpoints and Their Risk Level Endpoint Exposes Risk /actuator/health Application health Low — often public /actuator/info App metadata Low /actuator/metrics JVM/HTTP metrics Medium — business data /actuator/env All configuration properties (including secrets) Critical /actuator/configprops All @ConfigurationProperties values Critical /actuator/loggers Log levels (writable) High /actuator/heapdump Full JVM heap as a file Critical /actuator/threaddump Thread state Medium /actuator/mappings All URL mappings Medium — reveals API surface /actuator/shutdown Kills the JVM Critical /actuator/auditevents Security events High Step 1: Expose Only What You Need By default, only health is exposed over HTTP.
Continue reading »Advanced Streams: flatMap, Collectors, Grouping, and Partitioning
flatMap in Depth The Collectors API covers perhaps 90% of real-world aggregation needs, but the moment you need something beyond grouping, partitioning, or joining, the custom Collector is there. Understanding flatMap and the full Collectors toolkit — including when to write your own — separates competent Java 8 developers from those who still reach for a for loop whenever a problem gets slightly unusual. flatMap is the most powerful transformation in the Streams API.
Continue reading »Auditing: @CreatedDate, @LastModifiedBy, and Hibernate Envers
Why Auditing Matters Production systems must answer: “Who changed this? When? What did it look like before?” Without auditing infrastructure, you add created_at, updated_at, created_by, updated_by columns manually to every entity — dozens of lines of boilerplate repeated everywhere. Spring Data JPA auditing fills these fields automatically. Hibernate Envers goes further: it captures every revision of every entity in separate audit tables. Spring Data JPA Auditing Enable Auditing @Configuration @EnableJpaAuditing(auditorAwareRef = "auditorProvider") public class JpaAuditingConfig { @Bean public AuditorAware<String> auditorProvider() { return () -> Optional.
Continue reading »AuthenticationManager, AuthenticationProvider, and UserDetailsService
The Authentication Delegation Chain Spring Security separates requesting authentication from performing authentication. A filter receives a username and password — but it does not check them itself. It passes the request to AuthenticationManager, which delegates to one or more AuthenticationProvider instances: flowchart LR F[Authentication Filter\nForm Login / Basic / JWT] -->|UsernamePasswordToken| AM[AuthenticationManager\nProviderManager] AM -->|try each provider| AP1[DaoAuthenticationProvider\nfor DB users] AM -->|try each provider| AP2[LdapAuthenticationProvider\nfor LDAP users] AM -->|try each provider| AP3[Custom Provider\nfor API key] AP1 -->|if supported| UDS[UserDetailsService\nloadUserByUsername] UDS --> DB[(Database)] AP1 -->|verify password| PE[PasswordEncoder] AP1 -->|success| Token[Authenticated Token] Token --> F This chain is the core of Spring Security’s extensibility — you can plug in any number of authentication mechanisms without touching the filter or the rest of the framework.
Continue reading »Avro Serialization with Confluent Schema Registry
Why Avro and Schema Registry? JSON has no schema enforcement — a producer can change a field name and silently break every consumer. Avro + Schema Registry solves this: Avro gives you a compact binary format with a schema definition Schema Registry stores and versions schemas, enforces compatibility rules, and prevents breaking changes from reaching consumers flowchart LR subgraph Producer["Order Service"] E["OrderPlacedEvent"] -->|"KafkaAvroSerializer"| SR["Schema Registry\n(register/lookup schema)"] SR --> Bytes["[schema_id (4 bytes)] + [avro payload]"
Continue reading »