Better Programming

Advice for programmers.

Follow publication

A Quick and Practical Example of Hexagonal Architecture in Java

Software design patterns in action

Sumit Kumar
Better Programming
Published in
4 min readJun 1, 2022

--

Photo by Clark Van Der Beken on Unsplash

1. Overview

Hexagonal Architecture is a software design pattern first introduced by Alistair Cockburn. It provides an opinionated way of designing a web application architecture using Java or Java-related frameworks such as Spring. In this article, we’ll look into the hexagonal architecture in Java and show its usage with the help of a practical example implemented using the Spring framework.

2. Hexagonal Architecture

The main idea behind hexagonal architecture is to have clear segregation of logic via the interface segregation principle. Moreover, the hexagonal architecture creates loosely coupled applications through the concept of ports and adapters. Here the ports refer to the interface and adapters refer to its implementation class (as shown in the figure below).

Hexagonal Architecture

The above diagram shows various endpoints in typical hexagonal architecture. Through the application layer, the user interacts with the core application logic via ports and adapters. The application layer consists of a GUI client, Social media client, HTTP/API calls, etc. Similarly, the other half of the application shows a persistence or infrastructure layer through which the data flows out to other components. The persistence layer contains external components like databases, mailing and messaging queues, etc.

3. Example

To better understand the hexagonal architecture, Let’s consider an example of a pizza service application. In this application we will have the following features:

  • List all the Pizzas available
  • Insert a new Pizza into the database
  • Get the Pizza by Name

4. Domain Object

The domain or entity object is the core part of the hexagonal architecture. It can have both state and behavior. This object doesn’t have any dependency on any of the application components. Any change in domain object will occur if there’s a change in the business requirement itself.

public class Pizza {
private String name;
private int price;
private String[] toppings;
// code for getters & setters
}

5. Ports

Ports in hexagonal architecture refer to the interfaces that allow inbound or outbound flow. An inbound port exposes the core application functionality to the outside world. For example, an API call to the service interface.

Let’s define a PizzaService interface that will expose its functionality to the outside components (like API calls). This is our inbound port.

public interface PizzaService {
public void createPizza(Pizza pizza);
public Pizza getPizza(String name);
public List<Pizza> laodPizza();
}

Similarly, the outbound ports are used to connect to some external repositories like databases.

Let’s define a PizzaRepository that will access the external persistent system (DB).

public interface PizzaRepo {
public void createPizza(Pizza pizza);
public Pizza getPizza(String name);
public List<Pizza> getAllPizza();
}

6. Adapters

Adapters refer to the implementation classes of their respective ports in a hexagonal architecture. They’re the outside part of the application (such as GUI, API calls, Webviews, Dao, etc.) and interact with the application via inbound and outbound ports respectively. In addition, the adapters make it simple to swap out a specific layer of the application. Depending on the required changes, we just need to add an adapter implementing an input or output port.

6.1 Primary Adapters

They’re also known as input or driving adapters as they drive the application by invoking the core part of the application using inbound ports.

Let’s define PizzaRestContoller as a REST controller as our primary adapter. It provides endpoints for creating and fetching pizzas and also implements PizzaRestUI (Webview). In addition to that, it uses PizzaService (inbound port) to invoke different methods.

@RestController
@RequestMapping(value="/pizza")
public class PizzaRestController implements PizzaRestUI {
@Autowired
private PizzaService pizzaService;
@Override
public void createPizza(@RequestBody Pizza pizza) {
pizzaService.createPizza(pizza);
}
@Override
public Pizza getPizza(@PathVariable String name) {
return pizzaService.getPizza(name);
}
@Override
public List<Pizza> listPizza() {
return pizzaService.laodPizza();
}
}

6.2 Secondary Adapters

They are known as output or driven adapters and implement an outbound port interface. These adapters provide an implementation for accessing the secondary components of an application like databases, messaging queues, etc. While the service layer implements the input port, an output port is implemented using the persistence layer.

In our case, PizzaRepoImpl is the outbound adapter that implements PizzaRepo (Outbound port).

@Repository
public class PizzaRepoImpl implements PizzaRepo {
private Map<String, Pizza> pizzaStore = new HashMap<String, Pizza>();
@Override
public void createPizza(Pizza pizza) {
pizzaStore.put(pizza.getName(), pizza);
}
@Override
public Pizza getPizza(String name) {
return pizzaStore.get(name);
}
@Override
public List<Pizza> getAllPizza() {
return pizzaStore.values().stream().collect(Collectors.toList());
}
}

Next, We can test the GET & POST endpoints using any API testing tool like Postman.

We can test the POST endpoint through http://localhost:8080/pizza-service/pizza/

{
"name" : "Margherita",
"price": "25",
"toppings" : ["tomato","onion","cucumber","jalapeno"]
}

Similarly, we can test the GET endpoint through http://localhost:8080/pizza-service/pizza/Margherita

{
"name": "Margherita",
"price": 25,
"toppings": [
"tomato",
"onion",
"cucumber",
"jalapeno"
]
}

7. Benefits

The hexagonal architecture has several advantages over traditional layered architecture such as:

  • It simplifies architecture design by separating the application's internal and external components
  • The core business logic is separated from any external dependencies, resulting in a high degree of decoupling
  • The ports-based architecture allows our application to adapt to new channels or use new communication protocols with ease which is useful in developing domain-driven applications

8. Conclusion

In this article, we've learned about the hexagonal architecture in Java through a simple example implemented in the Spring framework. Furthermore, we've discussed some of the advantages of using hexagonal architecture over traditional layered architecture.

The code for the given example is available over on Github.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Sumit Kumar
Sumit Kumar

Written by Sumit Kumar

Assistant Professor of Computer Science at The NorthCap University, Gurugram, India.

Responses (2)

Write a response