We know that combining a domain entity, a DTO, and a REST API serialization class into one won't pass code review:
@JsonInclude(JsonInclude.Include.NON_NULL) @Data @Builder @Entity @Table(name = "users") public class UserEntity { ... I can justify investing the time to separate such a class into distinct @Entity and DTO classes, ensuring each has a clear, single responsibility.
But how about taking it one step further: separating the DTO for internal use (domain or application logic) from a dedicated class designed specifically for REST API serialization? This could simplify version-specific serialization and make the layers of the application more maintainable.
For example, the following minimal code sample demonstrates separation of concerns by using JPA, Lombok, and Jackson annotations on different classes representing the same conceptual object:
Entity Class (JPA):
import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name = "users") public class UserEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; private String username; private String password; private String email; // Getters and setters } DTO Class (Lombok):
import lombok.Data; import lombok.Builder; @Data @Builder public class UserDTO { private String username; private String email; } JSON Representation Class (Jackson):
import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonInclude; @JsonInclude(JsonInclude.Include.NON_NULL) public class UserJson { @JsonProperty("user_name") private String username; @JsonProperty("email_address") private String email; // Getters and setters } Service Class to Convert Between Entity and DTO:
public class UserService { public UserDTO convertToDTO(UserEntity userEntity) { return UserDTO.builder() .username(userEntity.getUsername()) .email(userEntity.getEmail()) .build(); } public UserJson convertToJson(UserDTO userDTO) { UserJson userJson = new UserJson(); userJson.setUsername(userDTO.getUsername()); userJson.setEmail(userDTO.getEmail()); return userJson; } } When is it advisable to separate DTO from JSON?
For example, when we need to maintain multiple versions of our API, separate JSON classes allow us to handle version-specific serialization without affecting your internal DTOs, right? Is there a better approach to that?
Or... when there's significant data transformation between our internal representation (DTO) and the API contract (JSON), separating them can make these transformations more manageable. Does this make sense? Or does it point at fundamental flaw in the system design?