--- title: Data Mapper category: Architectural language: en tags: - Decoupling --- ## Intent >Data Mapper is the software layer that separates the in-memory objects from the database. >Its responsibility is to transfer data between the objects and database and isolate them from each other. >If we obtain a Data Mapper, it is not necessary for the in-memory object to know if the database exists or not. >The user could directly manipulate the objects via Java command without having knowledge of SQL or database. ## Explanation Real world example >When a user accesses a specific web page through a browser, he only needs to do several operations to the browser. > The browser and the server will take the responsibility of saving data separately. > You don't need to know the existence of the server or how to operate the server. In plain words >A layer of mappers that moves data between objects and a database while keeping them independent of each other. Wikipedia says >A Data Mapper is a Data Access Layer that performs bidirectional transfer of data between a persistent data store > (often a relational database) and an in-memory data representation (the domain layer). The goal of the pattern is to > keep the in-memory representation and the persistent data store independent of each other and the data mapper itself. > This is useful when one needs to model and enforce strict business processes on the data in the domain layer that do > not map neatly to the persistent data store. **Programmatic Example** >We have the student class to defining Students' attributes includes studentId, name and grade. >We have an interface of StudentDataMapper to lists out the possible behaviour for all possible student mappers. >And StudentDataMapperImpl class for the implementation of actions on Students Data. ```java public final class Student implements Serializable { private static final long serialVersionUID = 1L; @EqualsAndHashCode.Include private int studentId; private String name; private char grade; public interface StudentDataMapper { Optional find(int studentId); void insert(Student student) throws DataMapperException; void update(Student student) throws DataMapperException; void delete(Student student) throws DataMapperException; } public final class StudentDataMapperImpl implements StudentDataMapper { @Override public Optional find(int studentId) { return this.getStudents().stream().filter(x -> x.getStudentId() == studentId).findFirst(); } @Override public void update(Student studentToBeUpdated) throws DataMapperException { String name = studentToBeUpdated.getName(); Integer index = Optional.of(studentToBeUpdated) .map(Student::getStudentId) .flatMap(this::find) .map(students::indexOf) .orElseThrow(() -> new DataMapperException("Student [" + name + "] is not found")); students.set(index, studentToBeUpdated); } @Override public void insert(Student studentToBeInserted) throws DataMapperException { Optional student = find(studentToBeInserted.getStudentId()); if (student.isPresent()) { String name = studentToBeInserted.getName(); throw new DataMapperException("Student already [" + name + "] exists"); } students.add(studentToBeInserted); } @Override public void delete(Student studentToBeDeleted) throws DataMapperException { if (!students.remove(studentToBeDeleted)) { String name = studentToBeDeleted.getName(); throw new DataMapperException("Student [" + name + "] is not found"); } } public List getStudents() { return this.students; } } } ``` >The below example demonstrates basic CRUD operations: Create, Read, Update, and Delete between the in-memory objects > and the database. ```java @Slf4j public final class App { private static final String STUDENT_STRING = "App.main(), student : "; public static void main(final String... args) { final var mapper = new StudentDataMapperImpl(); var student = new Student(1, "Adam", 'A'); mapper.insert(student); LOGGER.debug(STUDENT_STRING + student + ", is inserted"); final var studentToBeFound = mapper.find(student.getStudentId()); LOGGER.debug(STUDENT_STRING + studentToBeFound + ", is searched"); student = new Student(student.getStudentId(), "AdamUpdated", 'A'); mapper.update(student); LOGGER.debug(STUDENT_STRING + student + ", is updated"); LOGGER.debug(STUDENT_STRING + student + ", is going to be deleted"); mapper.delete(student); } private App() { } } ``` Program output: 15:05:00.264 [main] DEBUG com.iluwatar.datamapper.App - App.main(), student : Student(studentId=1, name=Adam, grade=A), is inserted 15:05:00.267 [main] DEBUG com.iluwatar.datamapper.App - App.main(), student : Optional[Student(studentId=1, name=Adam, grade=A)], is searched 15:05:00.268 [main] DEBUG com.iluwatar.datamapper.App - App.main(), student : Student(studentId=1, name=AdamUpdated, grade=A), is updated 15:05:00.268 [main] DEBUG com.iluwatar.datamapper.App - App.main(), student : Student(studentId=1, name=AdamUpdated, grade=A), is going to be deleted This layer consists of one or more mappers (or data access objects) that perform data transfer. The scope of mapper implementations varies. A generic mapper will handle many different domain entity types, a dedicated mapper will handle one or a few. ## Explanation Real-world example > When accessing web resources through a browser, there is generally no need to interact with the server directly; > the browser and the proxy server will complete the data acquisition operation, and the three will remain independent. In plain words > The data mapper will help complete the bi-directional transfer of persistence layer and in-memory data. Wikipedia says > A Data Mapper is a Data Access Layer that performs bidirectional transfer of data between a > persistent data store (often a relational database) and an in-memory data representation (the domain layer). Programmatic example ## Class diagram ![alt text](./etc/data-mapper.png "Data Mapper") ## Applicability Use the Data Mapper in any of the following situations * when you want to decouple data objects from DB access layer * when you want to write multiple data retrieval/persistence implementations ## Tutorials * [Spring Boot RowMapper](https://zetcode.com/springboot/rowmapper/) * [Spring BeanPropertyRowMapper tutorial](https://zetcode.com/spring/beanpropertyrowmapper/) * [Data Transfer Object Pattern in Java - Implementation and Mapping (Tutorial for Model Mapper & MapStruct)](https://stackabuse.com/data-transfer-object-pattern-in-java-implementation-and-mapping/) ## Known uses * [SqlSession.getMapper()](https://mybatis.org/mybatis-3/java-api.html) ## Consequences > Neatly mapped persistence layer data > Data model follows the single function principle ## Related patterns * [Active Record Pattern](https://en.wikipedia.org/wiki/Active_record_pattern) * [Object–relational Mapping](https://en.wikipedia.org/wiki/Object%E2%80%93relational_mapping) ## Credits * [Data Mapper](http://richard.jp.leguen.ca/tutoring/soen343-f2010/tutorials/implementing-data-mapper/)