Tuesday 28 April 2020

UnsupportedOperationException at java.util.AbstractList.add

While working on JAVA assignment, discovered strange error while trying to add an element to list. I am using example code to demonstrate and fix this exception.

Note : Here existing array is converted into list using JAVA API.

Code Sample :
    public static void main(String[] args) {     
        Integer [] array = {1,2,3};
        List<Integer> asList = Arrays.asList(array);
        asList.add(0, 100);
        asList.forEach(s-> System.out.println(s+ " "));
    }

Error : Exception in thread "main" java.lang.UnsupportedOperationException
     at java.base/java.util.AbstractList.add(AbstractList.java:153)
     at com.learning.concepts.PlusOne.main(PlusOne.java:13)

Root Cause : Arrays.asList() method returns a non-resizable list backed by the array. From that method's documentation:
Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.)
Solution : In order to use a resizable list use the following to convert array into list.

List<Integer> asList = new ArrayList<Integer>(Arrays.asList(array));

Thursday 2 April 2020

A quick and practical example of Hexagonal Architecture in Java

1. Overview


In this tutorial, we'll discuss Hexagonal Architecture in Java through a working example.

2. Hexagonal Architecture


The core concept of this pattern is to implement the business logic inside the hexagon and expose it outside through the ports and adapters. 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 or third party integrations.
In terms of programming (implementation), a port is an interface while an adapter is the concrete implementation of a given port.

3. Hexagonal Architecture example in Java


Let's create a simple Spring Boot REST App and try to register/view Student details using the Hexagonal Architecture.

3.1 Define Domain layer


To start with, we'll create an entity named Student. Then, we'll  add StudentService class to keep the core business logic to persist\view data. Here, the Student and StudentService are part of the inside component. Therefore, we'll create ports to expose them.
public class Student { 
    private int studentId; 
    private String name; 
    private int age; 
}

public interface StudentService {
    public List<Student> findAll();
    public void save(Student student);
}
Let's implement StudentService interface now.
@Service
public class StudentServiceImpl implements StudentService {
    private StudentDBPort studentDBPort;

    @Autowired
    public StudentServiceImpl(StudentDBPort studentDBPort) {
        super();
        this.studentDBPort = studentDBPort;
    }

    @Override public List<Student> findAll() {
        return studentDBPort.findAll();
    }

    @Override public void save(Student student) {
        studentDBPort.save(student);
    }
}

3.2 Declare Ports


Then, we'll create the StudentDBPort interface to communicate with the database:
public interface StudentDBPort {
    public List<Student> findAll();
    public void save(Student student);
}

3.3 Implement Adapters


Let's create the StudentControllerAdapter class that  act as a RestController. Therefore, it'll act as an adapter to REST client.
public class StudentControllerAdapter implements StudentRESTPort {
    @Autowired
    private StudentService studentService;
 
    @RequestMapping(method = RequestMethod.POST, value = "/register")
    public Student registerStudent(@RequestBody Student student) {
        studentService.save(student);
        return student;
    }
 
    @RequestMapping(method = RequestMethod.GET, value = "/viewAll")
    public List<Student> getAllStudents() {
        return studentService.findAll();
    }
}
Then, we'll create the StudentServiceDBAdapter class that implements the StudentDBPort interface. So, it'll behave as an adapter to persist data in the database:
public class StudentServiceDBAdapter implements StudentDBPort {
    private EntityManager entityManager;

    @Override
    public List<Student> findAll() {
        Session currentSession = entityManager.unwrap(Session.class);
        Query<Student> theQuery = currentSession.createQuery("from Student", Student.class);
        List<Student> students = theQuery.getResultList();
        return students;
    }

    @Override
    public void save(Student student) {
        Session currentSession = entityManager.unwrap(Session.class);
        currentSession.saveOrUpdate(student);
    }
}
That's it, we've successfully separated our App into the inside and outside components.

4. Benefits


The benefits of this architecture are:
  • Independence : The core layer is independent of outer layers
  • Testability : Each dependent (outer) component could be easily replaced with a stub implementation so that any component can be tested with ease
  • Flexibility : Any number of ports can be added easily to serve multiple functionalities\channels


5. Conclusion


In this article, we've learned how to use Hexagonal Architecture in Java. We've seen the core business logic can be exposed as ports via interfaces and consumed by different adapters through implementation classes.