diff --git a/patterns/hexagonal-architecture-example/pom.xml b/patterns/hexagonal-architecture-example/pom.xml
new file mode 100644
index 0000000000..e5439bf8f7
--- /dev/null
+++ b/patterns/hexagonal-architecture-example/pom.xml
@@ -0,0 +1,34 @@
+
+ 4.0.0
+ hexagonal-architecture-example
+ 1.0
+ jar
+
+ com.baeldung
+ patterns
+ 1.0.0-SNAPSHOT
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-jar-plugin
+ 3.2.0
+
+
+
+ true
+ lib/
+ com.baeldung.hexagonal.architecture.example.infrastructure.CocktailsMenuApp
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/adapters/inbound/CommandLineAdapter.java b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/adapters/inbound/CommandLineAdapter.java
new file mode 100644
index 0000000000..4f85639009
--- /dev/null
+++ b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/adapters/inbound/CommandLineAdapter.java
@@ -0,0 +1,46 @@
+package com.baeldung.hexagonal.architecture.example.adapters.inbound;
+
+import java.util.List;
+import java.util.Scanner;
+
+import com.baeldung.hexagonal.architecture.example.application.domain.Cocktail;
+import com.baeldung.hexagonal.architecture.example.application.ports.in.AddCocktailPort;
+import com.baeldung.hexagonal.architecture.example.application.ports.in.AddCocktailPort.AddCocktailCommand;
+import com.baeldung.hexagonal.architecture.example.application.ports.in.GetCocktailsPort;
+
+public class CommandLineAdapter {
+ private AddCocktailPort addCocktailPort;
+ private GetCocktailsPort listCocktailsPort;
+ private Scanner scanner;
+
+ public CommandLineAdapter(Scanner scanner, AddCocktailPort addCocktailPort, GetCocktailsPort listCocktailsPort) {
+ this.addCocktailPort = addCocktailPort;
+ this.listCocktailsPort = listCocktailsPort;
+ this.scanner = scanner;
+ }
+
+ public void addCocktail() {
+ try {
+ System.out.println("Enter the name of the cocktail");
+ scanner.nextLine();
+ String name = scanner.nextLine();
+ System.out.println("Enter the price of the cocktail");
+ double price = scanner.nextDouble();
+ scanner.nextLine();
+ AddCocktailCommand command = new AddCocktailCommand(name, price);
+ addCocktailPort.addCocktail(command);
+ } catch (Exception exception) {
+ System.out.println("Error during adding a new Cocktail");
+ }
+ }
+
+ public void listCocktails() {
+ List cocktailList = listCocktailsPort.getCocktails();
+ System.out.println("Cocktails menu: \n");
+ cocktailList.stream()
+ .forEach(cocktail -> {
+ System.out.println(cocktail.getName() + "\n" +
+ "price: " + cocktail.getPrice() + " $ " + "\n");
+ });
+ }
+}
diff --git a/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/adapters/outbound/CocktailRepository.java b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/adapters/outbound/CocktailRepository.java
new file mode 100644
index 0000000000..8b8e4d1d54
--- /dev/null
+++ b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/adapters/outbound/CocktailRepository.java
@@ -0,0 +1,23 @@
+package com.baeldung.hexagonal.architecture.example.adapters.outbound;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.baeldung.hexagonal.architecture.example.application.domain.Cocktail;
+import com.baeldung.hexagonal.architecture.example.application.ports.out.FetchCocktailsPort;
+import com.baeldung.hexagonal.architecture.example.application.ports.out.SaveCocktailPort;
+
+public class CocktailRepository implements FetchCocktailsPort, SaveCocktailPort {
+
+ private Map store = new HashMap<>();
+
+ public List fetchCocktails() {
+ return new ArrayList<>(store.values());
+ }
+
+ public void saveCocktail(Cocktail cocktail) {
+ store.put(cocktail.getName(), cocktail);
+ }
+}
diff --git a/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/domain/Cocktail.java b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/domain/Cocktail.java
new file mode 100644
index 0000000000..878d667bf6
--- /dev/null
+++ b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/domain/Cocktail.java
@@ -0,0 +1,21 @@
+package com.baeldung.hexagonal.architecture.example.application.domain;
+
+public class Cocktail {
+
+ private String name;
+
+ private double price;
+
+ public Cocktail(String name, double price) {
+ this.name = name;
+ this.price = price;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public double getPrice() {
+ return price;
+ }
+}
diff --git a/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/ports/in/AddCocktailPort.java b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/ports/in/AddCocktailPort.java
new file mode 100644
index 0000000000..49138a2b34
--- /dev/null
+++ b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/ports/in/AddCocktailPort.java
@@ -0,0 +1,24 @@
+package com.baeldung.hexagonal.architecture.example.application.ports.in;
+
+public interface AddCocktailPort {
+
+ void addCocktail(AddCocktailCommand command);
+
+ class AddCocktailCommand {
+ private String name;
+ private double price;
+
+ public AddCocktailCommand(String name, double price) {
+ this.name = name;
+ this.price = price;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public double getPrice() {
+ return price;
+ }
+ }
+}
diff --git a/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/ports/in/GetCocktailsPort.java b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/ports/in/GetCocktailsPort.java
new file mode 100644
index 0000000000..1d46bbd722
--- /dev/null
+++ b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/ports/in/GetCocktailsPort.java
@@ -0,0 +1,9 @@
+package com.baeldung.hexagonal.architecture.example.application.ports.in;
+
+import java.util.List;
+
+import com.baeldung.hexagonal.architecture.example.application.domain.Cocktail;
+
+public interface GetCocktailsPort {
+ List getCocktails();
+}
diff --git a/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/service/AddCocktailService.java b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/service/AddCocktailService.java
new file mode 100644
index 0000000000..81855853e8
--- /dev/null
+++ b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/service/AddCocktailService.java
@@ -0,0 +1,19 @@
+package com.baeldung.hexagonal.architecture.example.application.service;
+
+import com.baeldung.hexagonal.architecture.example.application.domain.Cocktail;
+import com.baeldung.hexagonal.architecture.example.application.ports.in.AddCocktailPort;
+import com.baeldung.hexagonal.architecture.example.application.ports.out.SaveCocktailPort;
+
+public class AddCocktailService implements AddCocktailPort {
+ private SaveCocktailPort saveCocktailPort;
+
+ public AddCocktailService(SaveCocktailPort saveCocktailPort) {
+ this.saveCocktailPort = saveCocktailPort;
+ }
+
+ @Override
+ public void addCocktail(AddCocktailCommand command) {
+ Cocktail cocktail = new Cocktail(command.getName(), command.getPrice());
+ saveCocktailPort.saveCocktail(cocktail);
+ }
+}
diff --git a/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/service/GetCocktailsService.java b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/service/GetCocktailsService.java
new file mode 100644
index 0000000000..a1459f2372
--- /dev/null
+++ b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/application/service/GetCocktailsService.java
@@ -0,0 +1,20 @@
+package com.baeldung.hexagonal.architecture.example.application.service;
+
+import java.util.List;
+
+import com.baeldung.hexagonal.architecture.example.application.domain.Cocktail;
+import com.baeldung.hexagonal.architecture.example.application.ports.in.GetCocktailsPort;
+import com.baeldung.hexagonal.architecture.example.application.ports.out.FetchCocktailsPort;
+
+public class GetCocktailsService implements GetCocktailsPort {
+ private FetchCocktailsPort fetchCocktailsPort;
+
+ public GetCocktailsService(FetchCocktailsPort fetchCocktailsPort) {
+ this.fetchCocktailsPort = fetchCocktailsPort;
+ }
+
+ @Override
+ public List getCocktails() {
+ return fetchCocktailsPort.fetchCocktails();
+ }
+}
diff --git a/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/infrastructure/CocktailsMenuApp.java b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/infrastructure/CocktailsMenuApp.java
new file mode 100644
index 0000000000..a808d1f85e
--- /dev/null
+++ b/patterns/hexagonal-architecture-example/src/main/java/com/baeldung/hexagonal/architecture/example/infrastructure/CocktailsMenuApp.java
@@ -0,0 +1,43 @@
+package com.baeldung.hexagonal.architecture.example.infrastructure;
+
+import java.util.Scanner;
+
+import com.baeldung.hexagonal.architecture.example.adapters.inbound.CommandLineAdapter;
+import com.baeldung.hexagonal.architecture.example.adapters.outbound.CocktailRepository;
+import com.baeldung.hexagonal.architecture.example.application.service.AddCocktailService;
+import com.baeldung.hexagonal.architecture.example.application.service.GetCocktailsService;
+
+public class CocktailsMenuApp {
+ private static final String ADD = "add";
+ private static final String LIST = "list";
+ private static final String EXIT = "exit";
+ private static final String HELP_TEXT = "Enter command \n" +
+ ADD + " - add a new Cocktail to the menu \n" +
+ LIST + " - list cocktails \n" +
+ EXIT + " - exit \n";
+ private static Scanner SCANNER = new Scanner(System.in);
+
+ public static void main(String[] args) {
+ CocktailRepository cocktailRepository = new CocktailRepository();
+ AddCocktailService addCocktailService = new AddCocktailService(cocktailRepository);
+ GetCocktailsService getCocktailsMenuService = new GetCocktailsService(cocktailRepository);
+ CommandLineAdapter commandLineAdapter = new CommandLineAdapter(SCANNER, addCocktailService, getCocktailsMenuService);
+ runWith(commandLineAdapter);
+ }
+
+ public static void runWith(CommandLineAdapter adapter) {
+ String command = null;
+ while (!EXIT.equalsIgnoreCase(command)) {
+ System.out.println(HELP_TEXT);
+ command = SCANNER.next();
+ switch (command.toLowerCase()) {
+ case ADD:
+ adapter.addCocktail();
+ break;
+ case LIST:
+ adapter.listCocktails();
+ break;
+ }
+ }
+ }
+}
diff --git a/patterns/hexagonal-architecture-example/src/test/java/com/baeldung/hexagonal/architecture/example/application/AddCocktailUnitTest.java b/patterns/hexagonal-architecture-example/src/test/java/com/baeldung/hexagonal/architecture/example/application/AddCocktailUnitTest.java
new file mode 100644
index 0000000000..bff8550464
--- /dev/null
+++ b/patterns/hexagonal-architecture-example/src/test/java/com/baeldung/hexagonal/architecture/example/application/AddCocktailUnitTest.java
@@ -0,0 +1,42 @@
+package com.baeldung.hexagonal.architecture.example.application;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import com.baeldung.hexagonal.architecture.example.application.domain.Cocktail;
+import com.baeldung.hexagonal.architecture.example.application.ports.in.AddCocktailPort.AddCocktailCommand;
+import com.baeldung.hexagonal.architecture.example.application.ports.out.SaveCocktailPort;
+import com.baeldung.hexagonal.architecture.example.application.service.AddCocktailService;
+
+class AddCocktailUnitTest {
+
+ SaveCocktailPort saveCocktailPort;
+ AddCocktailService addCocktailService;
+
+ @BeforeEach
+ void setup() {
+ saveCocktailPort = mock(SaveCocktailPort.class);
+ addCocktailService = new AddCocktailService(saveCocktailPort);
+ }
+
+ @Test
+ void whenAddingACocktail_thenTheCocktailIsSaved() {
+ AddCocktailCommand command = mock(AddCocktailCommand.class);
+ when(command.getName()).thenReturn("mockito");
+ when(command.getPrice()).thenReturn(9.50);
+ ArgumentCaptor captor = ArgumentCaptor.forClass(Cocktail.class);
+
+ addCocktailService.addCocktail(command);
+
+ Mockito.verify(saveCocktailPort).saveCocktail(captor.capture());
+ Cocktail cocktailThatSaved = captor.getValue();
+ assertEquals(command.getName(), cocktailThatSaved.getName());
+ assertEquals(command.getPrice(), cocktailThatSaved.getPrice());
+ }
+
+}
diff --git a/patterns/hexagonal-architecture-example/src/test/java/com/baeldung/hexagonal/architecture/example/application/GetCocktailsUnitTest.java b/patterns/hexagonal-architecture-example/src/test/java/com/baeldung/hexagonal/architecture/example/application/GetCocktailsUnitTest.java
new file mode 100644
index 0000000000..5933f71895
--- /dev/null
+++ b/patterns/hexagonal-architecture-example/src/test/java/com/baeldung/hexagonal/architecture/example/application/GetCocktailsUnitTest.java
@@ -0,0 +1,41 @@
+package com.baeldung.hexagonal.architecture.example.application;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import java.util.List;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import com.baeldung.hexagonal.architecture.example.application.domain.Cocktail;
+import com.baeldung.hexagonal.architecture.example.application.ports.out.FetchCocktailsPort;
+import com.baeldung.hexagonal.architecture.example.application.service.GetCocktailsService;
+
+class GetCocktailsUnitTest {
+
+ FetchCocktailsPort fetchCocktailsPort;
+ GetCocktailsService getCocktailsService;
+
+ @BeforeEach
+ void setup() {
+ fetchCocktailsPort = mock(FetchCocktailsPort.class);
+ getCocktailsService = new GetCocktailsService(fetchCocktailsPort);
+ }
+
+ @Test
+ void whenGettingCocktails_thenCocktailsFetchedFromPortAndReturned() {
+ Cocktail cocktail = mock(Cocktail.class);
+ when(cocktail.getName()).thenReturn("zombie");
+ when(cocktail.getPrice()).thenReturn(12.00);
+ when(fetchCocktailsPort.fetchCocktails()).thenReturn(List.of(cocktail));
+
+ List cocktails = getCocktailsService.getCocktails();
+
+ assertEquals(1, cocktails.size());
+ assertEquals(cocktail.getName(), cocktails.get(0).getName());
+ assertEquals(cocktail.getPrice(), cocktails.get(0).getPrice());
+ }
+
+}
diff --git a/patterns/pom.xml b/patterns/pom.xml
index 4c17055231..7631d8bbb0 100644
--- a/patterns/pom.xml
+++ b/patterns/pom.xml
@@ -24,6 +24,7 @@
front-controller
intercepting-filter
solid
+ hexagonal-architecture-example