I want to create an example application where we use a strict domain-driven design and layering (controller, service, repository). Most notably, we have a clear distinction between the domain and the persistence layer. See my example below:
Domain
public class Customer {
private Long id;
private String name;
}
public class CustomerOrder {
private Long id;
private String productName;
private int quantity;
private Customer customer;
}
Entity
@Entity
public class CustomerEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
@Entity
public class CustomerOrderEntity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String productName;
private int quantity;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "customer_id")
private CustomerEntity customer;
}
DTO
@Data
public class CustomerOrderRequestDTO {
private Long customerId;
private String productName;
private int quantity;
}
@Data
public class CustomerOrderResponseDTO {
private Long orderId;
private String productName;
private int quantity;
private Long customerId;
private String customerName;
}
Controller layer
@RestController
@RequestMapping("/api/orders")
@AllArgsConstructor
public class CustomerOrderController {
private final CustomerOrderService customerOrderService;
@PostMapping
public ResponseEntity<CustomerOrderResponseDTO> createOrder(@RequestBody CustomerOrderRequestDTO requestDTO) {
CustomerOrderResponseDTO responseDTO = customerOrderService.createOrder(requestDTO);
return ResponseEntity.ok(responseDTO);
}
}
Service layer
@Service
@AllArgsConstructor
public class CustomerOrderService {
private final CustomerRepository customerRepository;
private final CustomerOrderRepository customerOrderRepository;
private final Mapper mapper;
public CustomerOrderResponseDTO createOrder(CustomerOrderRequestDTO requestDTO) {
CustomerEntity customerEntity = customerRepository.findById(requestDTO.getCustomerId())
.orElseThrow(() -> new IllegalArgumentException("Customer not found"));
Customer customer = mapper.map(customerEntity);
CustomerOrder customerOrder = mapper.map(requestDTO, customer);
//maybe do some validation on the domain instances
CustomerOrderEntity customerOrderEntity = mapper.map(customerOrder);
customerOrderRepository.save(customerOrderEntity);
CustomerOrderResponseDTO responseDTO = mapper.map(customerOrder);
return responseDTO;
}
}
Repository layer
Just some default JpaRepostories.
Question
In this example, the service layer does a lot of mappings. Is this layer indeed responsible for all those mappings? If not, how would you change the application?