Browse Java Design Patterns & Enterprise Application Architecture

Implementing Adapter Pattern in Java

Implement Java adapters by keeping the target interface narrow, preferring object adapters, and isolating translation logic at the dependency boundary.

Adapter: A wrapper that translates one interface into another so existing client code can depend on the contract it actually wants.

In Java, the strongest adapters are boring. They do not invent new workflow. They do not become policy objects. They just translate between a target interface the application wants and an adaptee interface a dependency already exposes.

Start With The Target Interface

Define the contract your application should depend on first:

1public interface PaymentProcessor {
2    Receipt charge(Money amount, String token);
3}

That interface should reflect application language, not vendor language.

Prefer Object Adapters

Composition is usually the default Java implementation:

 1public final class LegacyGatewayAdapter implements PaymentProcessor {
 2    private final LegacyGateway gateway;
 3
 4    public LegacyGatewayAdapter(LegacyGateway gateway) {
 5        this.gateway = gateway;
 6    }
 7
 8    @Override
 9    public Receipt charge(Money amount, String token) {
10        LegacyResponse response =
11            gateway.makePayment(amount.toMinorUnits(), token);
12
13        return new Receipt(
14            response.reference(),
15            response.approved()
16        );
17    }
18}

This keeps three responsibilities in one place:

  • call the dependency
  • translate argument shape
  • translate result shape

That is enough for most adapters.

Keep Business Rules Out Of The Adapter

An adapter may perform format conversion, type conversion, or error translation. It should not quietly become:

  • a retry policy engine
  • an authorization service
  • a validation layer for unrelated business rules
  • a place where half the workflow logic lives

If those concerns matter, keep them in separate collaborators around the adapter.

Class Adapters Are Rare In Java

Java can implement a class adapter by extending one type and implementing another interface, but that approach is constrained by single inheritance and tends to couple the adapter tightly to a concrete adaptee. Unless the inheritance relationship is clearly worth it, object adapters are easier to evolve and easier to test.

A Good Adapter Makes Dependency Churn Smaller

The biggest practical payoff is not elegance. It is churn control. If the vendor SDK changes from:

  • makePayment(long cents, String token)

to:

  • submitCharge(BigDecimal amount, CardToken token)

the application should not need to care beyond the adapter boundary.

Design Review Questions

When reviewing a Java adapter, ask:

  • Is the target interface owned by the application?
  • Is the translation logic small and explicit?
  • Would callers notice if the dependency API changed?
  • Is the adapter hiding remote latency or failure semantics that should stay visible?

Adapter is strong when it localizes mismatch. It is weak when it becomes a dumping ground for everything the integration team did not know where else to place.

Loading quiz…
Revised on Thursday, April 23, 2026