Hexagonal Architecture in Java
Tags: java, hexagonalarchitecture, programming
Published: 2019-12-15 17:39:10

**1. Overview**

In this quick article, we'll discuss Hexagonal Architecture in Java through a practical example.

**2. What is Hexagonal Architecture?**

In simple words, a Hexagonal architecture separates software in two components - inside and outside, instead of conceptual layers.
The component that remains inside usually consists of application and domain layers, along with the core business logic. Whereas, the component for the outside world consists of layers like UI and Database.

The connection between the inside and outside components realizes via abstractions called ports and implementations called adapters.

**3. Benefits**
* Flexibility - with different adapters, the software can serve multiple channels
* Testability - as mocking code is easy
* Purity - as the core logic remains intact

**4. Hexagonal Architecture in Java**

In Java, interfaces are ports and implementation classes are adapters.
 
Let's create a simple Spring Boot App and try to register/view Employee details using the Hexagonal Architecture.

To start with, we'll create an entity named *Employee*.
Then, the *EmployeeService* class to keep the core business logic to persist data. 

Here, the *Employee* and *EmployeeService* classes are part of the inside component. Therefore, we'll create ports to expose them.

First, let's create the *EmployeeUIPort* interface to communicate with the front-end:

    public interface EmployeeUIPort {
        @PostMapping("register")
        public void register(@RequestBody Employee request);

        @GetMapping("view/{id}")
        public Employee view(@PathVariable Integer id);
    }

Then, we'll create the *EmployeeDBPort* interface to communicate with the database:

    public interface EmployeeDBPort {
        void register(String name);

        Employee getEmployee(Integer id);
    }

Last, we need adapters to connect to the ports - *EmployeeUIPort* and *EmployeeDBPort*.

Let's create the *EmployeeControllerAdapter* class that implements the *EmployeeUIPort* interface and act as a *RestController*. Therefore, it'll act as an adapter to connect with the front-end:

    @RestController
    @RequestMapping("/employee/")
    public class EmployeeControllerAdapter implements EmployeeUIPort {
        @Autowired
        private EmployeeServiceAdapter employeeService;

        @Override
        public void register(@RequestBody Employee request) {
            employeeService.register(request.getName());
        }

        @Override
        public Employee view(@PathVariable Integer id) {
            Employee employee = employeeService.view(id);
            return employee;
        }
    }

Then, we'll create the *EmployeeServiceAdapter* (or *EmployeeService* for simplicity) class that implements the *EmployeeDBPort* interface and keep it as a Spring Service. So, it'll behave as an adapter to persist data in the database:

    @Service
    public class EmployeeServiceAdapter implements EmployeeDBPort {
        @PersistenceContext
        private EntityManager entityManager;
   
        @Transactional
        @Override
        public void register(String name) {
            Employee employee = new Employee();
            employee.setName(name);

            entityManager.persist(employee);
        }

        @Override
        public Employee getEmployee(Integer id) {
            return entityManager.find(Employee.class, id);
        }
    }

That's it, we've successfully separated our App into the inside and outside components. 

As a result, the business logic of the app will be exposed via ports and consumed via adapters from outside.

Similarly, we can create different ports and implement multiple adapters for any core service. 

For instance, Messaging Service and Content Management Service.

**5. Conclusion**

In this quick article, we've explored the concept of Hexagonal architecture in Java. 

We've seen the core business logic (inside component) can be exposed as ports via interfaces and consumed by different adapters (outside component) through implementation classes.

This approach helps in writing clear, readable code with less dependency on external technology. However, I'd suggest using this pattern of ports and adapters selectively, rather than going full hexagonal.