Java Omnibus
OOAD & Architecture / Architectural Styles / Hexagonal / Ports and Adapters Architecture
Hexagonal Ports and Adapters Java Boundary Design
Architectural Styles

Hexagonal architecture matters when the business core should be stable even while databases, HTTP edges, and messaging tools keep changing.

Ports and Adapters, often called Hexagonal Architecture, is a way to keep the application's core logic independent from the delivery and infrastructure mechanisms around it. The core speaks through ports. Adapters implement those ports for web, database, messaging, or external APIs.

Why This Topic Matters

Why it matters in real Java systems

Commerce systems often change payment providers, shipping APIs, persistence strategies, or transport layers over time. Hexagonal architecture helps prevent those changes from reshaping the business core every time an infrastructure choice moves.

Core Explanation

The main architectural idea

In a hexagonal design, the application core depends on business-facing interfaces, often called ports. Adapters live at the edges and implement those ports for real infrastructure. The key benefit is dependency direction: the core does not import frameworks or transport details directly.

This style is especially helpful when teams care about testability, infrastructure independence, and long-lived business logic. It is less useful when the system is small and the extra abstraction would be mostly ceremony.

Concept Breakdown

Key ideas to keep in mind

Concept

Input ports

Use-case entry points such as commands, services, or application APIs the outside world can invoke.

Concept

Output ports

Business-facing contracts for persistence, payments, notifications, or external integrations.

Concept

Adapters

Concrete implementations for HTTP, database, messaging, or third-party APIs.

Diagram in words

Diagram in words

Visualize the shape: the order use case sits in the center, surrounded by ports such as OrderStore, PaymentPort, and NotificationPort. Around those sit adapters like a REST controller, a Postgres repository, a Stripe adapter, and an email adapter. The core points outward only through interfaces.
Java Example

Java example in the Order Management domain

Java example: one use case with ports and adapters
package org.javaomnibus.ecommerce.application;

public interface PaymentPort {
    PaymentReceipt capture(String orderId, Money amount);
}

public interface OrderStore {
    void save(Order order);
}

public final class PlaceOrderUseCase {
    private final PaymentPort paymentPort;
    private final OrderStore orderStore;

    public PlaceOrderUseCase(PaymentPort paymentPort, OrderStore orderStore) {
        this.paymentPort = paymentPort;
        this.orderStore = orderStore;
    }

    public OrderReceipt place(PlaceOrderCommand command) {
        Order order = Order.create(command.customerId(), command.lines());
        paymentPort.capture(order.id(), order.total());
        orderStore.save(order);
        return OrderReceipt.from(order);
    }
}
Code Walkthrough

Step by step

  1. The use case depends on PaymentPort and OrderStore rather than concrete infrastructure classes.
  2. That means the core can be tested without HTTP, a real database, or a real payment gateway.
  3. Adapters implement the ports at the edge of the system.
  4. This is the essence of Ports and Adapters: stable core, replaceable edges.
Real-World Usage

Where this helps in practice

  • Systems with frequent infrastructure changes
  • Applications that need strong test isolation around the core
  • Long-lived business domains where framework churn is expected
Trade-Offs

Trade-offs and when not to overuse it

  • Hexagonal architecture improves separation, but it introduces more interfaces and adapters to maintain.
  • If the system is small and stable, that extra structure may not pay for itself.
Common Mistakes

Frequent mistakes to watch for

  • Creating ports for everything even when no boundary exists
  • Letting adapters leak framework types back into the core
  • Calling the system hexagonal while the core still imports infrastructure details
  • Adding abstraction without a stable application core to protect
Related Pages

Related concepts


What To Read Next