Search code examples
javaspringdesign-patternsdtomodelmapper

How can i avoid code duplication in spring data transfer objects (dto)


I need your recommendations. I'm writing project in Spring Boot. I have one entity and two DTOs on below.

entity DeviceReservation.java

@Entity
@SQLDelete(sql = "UPDATE device_reservation SET deleted='Y' WHERE id=?")
public class DeviceReservation extends SoftDeleteSupport {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @ManyToOne
    private User user;

    @ManyToOne
    @JsonIgnore
    private Device device;

    private OffsetDateTime startTime;
    private OffsetDateTime endTime;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    private OffsetDateTime updateTime;
    @JsonInclude(JsonInclude.Include.NON_NULL)
    private String updateReason;

    public DeviceReservation() {
    }

    public DeviceReservation(User user, Device device, OffsetDateTime startTime, OffsetDateTime endTime, OffsetDateTime updateTime, String updateReason) {
        this.user = user;
        this.device = device;
        this.startTime = startTime;
        this.endTime = endTime;
        this.updateTime = updateTime;
        this.updateReason = updateReason;
    }

 // getters and setters
}

dto1 DeviceReservationDTO.java

public class DeviceReservationDTO {

    private Long id;
    private String username;
    private String deviceId;
    private OffsetDateTime startTime;
    private OffsetDateTime endTime;
    private OffsetDateTime updateTime;
    private String updateReason;

     public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getDeviceId() {
        return deviceId;
    }

    public void setDeviceId(String deviceId) {
        this.deviceId = deviceId;
    }

    public OffsetDateTime getStartTime() {
        return startTime;
    }

    public void setStartTime(OffsetDateTime startTime) {
        this.startTime = startTime;
    }

    public OffsetDateTime getEndTime() {
        return endTime;
    }

    public void setEndTime(OffsetDateTime endTime) {
        this.endTime = endTime;
    }

    public OffsetDateTime getUpdateTime() {
        return updateTime;
    }

    public void setUpdateTime(OffsetDateTime updateTime) {
        this.updateTime = updateTime;
    }

    public String getUpdateReason() {
        return updateReason;
    }

    public void setUpdateReason(String updateReason) {
        this.updateReason = updateReason;
    }
}


I don't want this two fields in my response: updateTime and updateReason. The dto above is used in too many places so I don't want to edit this dto (dto1 DeviceReservationDTO.java). I created the dto below, without this two fields.

dto2 DeviceReservationResponseDTO.java

public class DeviceReservationResponseDTO {

    private Long id;
    private String username;
    private String deviceId;
    private OffsetDateTime startTime;
    private OffsetDateTime endTime;

    public DeviceReservationResponseDTO() {
        // Do nothing
    }


    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getDeviceId() {
        return deviceId;
    }

    public void setDeviceId(String deviceId) {
        this.deviceId = deviceId;
    }

    public OffsetDateTime getStartTime() {
        return startTime;
    }

    public void setStartTime(OffsetDateTime startTime) {
        this.startTime = startTime;
    }

    public OffsetDateTime getEndTime() {
        return endTime;
    }

    public void setEndTime(OffsetDateTime endTime) {
        this.endTime = endTime;
    }
}

Problem is starting now. Sonarqube is showing to me this error for duplications: Sonar Error

I say it again, I don't want this two fields in my response: updateTime and updateReason.

There is my question: How can i avoid code duplication? What is correct approach? How can i design this code? Should I edit all DeviceReservationDTO.java used places? Should i stop this rule in sonarqube?

If you need to see other related codes:


public List<DeviceReservationResponseDTO> getReservationByDeviceId(@PathVariable Long deviceId) {
        return reservationService
                .getReservationsByDeviceId(deviceId)
                .stream()
                .map(this::convertToReservationResponseDTO)
                .collect(Collectors.toList());
}


private DeviceReservationResponseDTO convertToReservationResponseDTO(DeviceReservation deviceReservation) {
        modelMapper = new ModelMapper();
        TypeMap<DeviceReservation, DeviceReservationResponseDTO> typeMap = modelMapper
                .createTypeMap(DeviceReservation.class, DeviceReservationResponseDTO.class);

        typeMap.addMappings(m -> m.map(src -> src.getUser().getUserName(), DeviceReservationResponseDTO::setUsername));
        return modelMapper.map(deviceReservation, DeviceReservationResponseDTO.class);
}


Solution

  • In my opinion, whether you need these two dtos depends on your application design. Dose these two dtos have their own purpose? Like DeviceReservationDTO is for transferring data between layers in application and DeviceReservationResponseDTO is for web response. If so I suggest keep these two dtos for loose coupling.

    There is indeed a way to make your code clean. Try Lombok(already in springboot) and Mapstruct.