Design Guidelines

Naming and Namespacing POJOs for Separation of Concerns

When your DTOs, Domain POJOs & Entity classes share a common structure, i.e. the same data flows through all layers, you might evidence a shared POJO used between controller, service and persistence layers.

Modelling these as separate objects although they share a common structure:

  • gives better separation of concerns and flexibility
  • prevents API changes from rippling over to domain/persistence layers
  • aids security by granting control over exposure of sensitive fields in entity/domain objects

DTOs (Presentation/API layer hides internal structures, may be tailored for performance)

  • Namespace: in.<app_name>.controller.dto
  • Naming: Suffix with Request, Response (or Dto), e.g. AuditRequest, AuditResponse

Domain POJOs (business concepts may contain behaviours / be richer than DTOs, for e.g. domain field may be an enum, where DTO has a String)

  • Namespace: in.<app_name>.service.domain
  • Naming: Bare-named, e.g. Audit

Entities (lazy-loaded relationships, ORM-specific annotations best isolated to persistence layer)

  • Namespace: in.<app_name>.persistence.entity
  • Naming: Suffix with Entity, e.g. AuditEntity

Where should you do the mapping?

Map the conversion from Controller DTOs to Domain objects in the Controller layer. The controller serves as the boundary between external inputs and outputs on the one hand and the internal business logic on the other. It delegates all business logic to the service layer and keeps the service layer domain-focused (free from HTTP or external formats) by:

  • deserializing to application’s internal representation (DTO -> Domain conversion)
  • serialize to external data format (Domain -> DTO conversion)

You can convert between DTO and Domain objects either manually or using a mapper model like MapStruct.