title: How can I prevent duplicate code when converting entity to dto using custom assembler(Without additional libraries)?
body: <p>I have several entities but there are three entities that have relationship on each other(Car,CarCategory,Order)</p>
  <p>Car entity :</p>
  <pre><code>@Entity
  @Table(name = &quot;car_info&quot;)
  @Getter
  @Setter
  public class Car implements Serializable {
      private static final long serialVersionUID = -1473879605284728654L;
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Id
      @Column(name = &quot;carId&quot;, nullable = false)
      private Long carId;
      @Column(name = &quot;numOfPas&quot;)
      private int numOfPas;
      @Column(name = &quot;carState&quot;)
      private String carState;
      @Column(name = &quot;carName&quot;, length = 25)
      private String carName;
      @Column(name = &quot;carImage&quot;)
      @Lob
      private byte[] carImage;
  
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = &quot;carCategory&quot;)
      private CarCategory carCategory;
  
      @OneToMany(mappedBy = &quot;car&quot;, cascade = CascadeType.ALL, orphanRemoval = true)
      private List&lt;Order&gt; orders = new ArrayList&lt;&gt;();
  
  
      @Override
      public boolean equals(Object o) {
          if (this == o) return true;
          if (o == null || getClass() != o.getClass()) return false;
          Car car = (Car) o;
          return Objects.equals(getCarId(), car.getCarId());
      }
  
      @Override
      public int hashCode() {
          return Objects.hash(getCarId());
      }
  
      @Override
      public String toString() {
          final StringBuilder sb = new StringBuilder(&quot;Car{&quot;);
          sb.append(&quot;carId=&quot;).append(carId);
          sb.append(&quot;, numOfPas=&quot;).append(numOfPas);
          sb.append(&quot;, carState='&quot;).append(carState).append('\'');
          sb.append(&quot;, carName='&quot;).append(carName).append('\'');
          sb.append('}');
          return sb.toString();
      }
  }
  </code></pre>
  <p>CarCategory entity :</p>
  <pre><code>@Entity
  @Table(name = &quot;car_category&quot;)
  @Getter
  @Setter
  public class CarCategory implements Serializable {
      private static final long serialVersionUID = -4179236910442782235L;
      @Column(name = &quot;carCategoryName&quot;, nullable = false, length = 15)
      @Id
      private String carCategoryName;
      @Column(name = &quot;costPerOneKilometer&quot;)
      private double costPerOneKilometer;
      @Column(name = &quot;discountPerPrice&quot;)
      private double discountPerPrice;
      @Column(name = &quot;carCategoryImage&quot;)
      @Lob
      private byte[] carCategoryImage;
      @OneToMany(mappedBy = &quot;carCategory&quot;, cascade = CascadeType.ALL, orphanRemoval = true)
      private List&lt;Car&gt; cars = new ArrayList&lt;&gt;();
  
      @Override
      public boolean equals(Object o) {
          if (this == o) return true;
          if (o == null || getClass() != o.getClass()) return false;
          CarCategory that = (CarCategory) o;
          return Objects.equals(getCarCategoryName(), that.getCarCategoryName());
      }
  
      @Override
      public int hashCode() {
          return Objects.hash(getCarCategoryName());
      }
  }
  </code></pre>
  <p>Order entity :</p>
  <pre><code>@Entity
  @Table(name = &quot;user_order&quot;, indexes = {
          @Index(name = &quot;idx_order_userid_carid_unq&quot;, columnList = &quot;userId, carId&quot;, unique = true)
  })
  @Getter
  @Setter
  public class Order implements Serializable {
      private static final long serialVersionUID = -4577879200654802752L;
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      @Id
      @Column(name = &quot;orderId&quot;, nullable = false)
      private Long orderId;
      @Column(name = &quot;userAddress&quot;, length = 60)
      private String userAddress;
      @Column(name = &quot;userDestination&quot;, length = 60)
      private String userDestination;
      @Column(name = &quot;orderCost&quot;)
      private double orderCost;
      @Column(name = &quot;orderDate&quot;, columnDefinition = &quot;DATETIME&quot;)
      private LocalDateTime orderDate;
  
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = &quot;userId&quot;)
      private User user;
  
      @ManyToOne(fetch = FetchType.LAZY)
      @JoinColumn(name = &quot;carId&quot;)
      private Car car;
  
  
      @Override
      public boolean equals(Object o) {
          if (this == o) return true;
          if (o == null || getClass() != o.getClass()) return false;
          Order order = (Order) o;
          return Objects.equals(getOrderId(), order.getOrderId());
      }
  
      @Override
      public int hashCode() {
          return Objects.hash(getOrderId());
      }
  
      @Override
      public String toString() {
          final StringBuilder sb = new StringBuilder(&quot;Order{&quot;);
          sb.append(&quot;orderId=&quot;).append(orderId);
          sb.append(&quot;, userAddress='&quot;).append(userAddress).append('\'');
          sb.append(&quot;, userDestination='&quot;).append(userDestination).append('\'');
          sb.append(&quot;, orderCost=&quot;).append(orderCost);
          sb.append(&quot;, orderDate=&quot;).append(orderDate);
          sb.append('}');
          return sb.toString();
      }
  }
  </code></pre>
  <p>As you can see Order has relationship to car and carCategory has relationship to car</p>
  <p>So for converting to dto I have this assembler which will be used in service layer</p>
  <p>Assembler interface :</p>
  <pre><code>public interface Assembler&lt;E,D &gt;{
      D mergeAggregateIntoDto(E entity);
      E mergeDtoIntoAggregate(D dto);
  }
  </code></pre>
  <p>CarCategoryAssembler :</p>
  <pre><code>@Service
  public class CarCategoryAssembler implements Assembler&lt;CarCategory, CarCategoryDto&gt; {
      @Override
      public CarCategoryDto mergeAggregateIntoDto(CarCategory entity) {
          CarCategoryDto carCategoryDto = new CarCategoryDto();
          carCategoryDto.setCarCategoryName(entity.getCarCategoryName());
          carCategoryDto.setCostPerOneKilometer(entity.getCostPerOneKilometer());
          carCategoryDto.setCarCategoryImage(entity.getCarCategoryImage());
          carCategoryDto.setDiscountPerPrice(entity.getDiscountPerPrice());
          carCategoryDto.setCars(entity.getCars().stream().map(this::mergeAggregateIntoDto).collect(Collectors.toList()));
          return carCategoryDto;
      }
  
      @Override
      public CarCategory mergeDtoIntoAggregate(CarCategoryDto dto) {
          CarCategory carCategory = new CarCategory();
          carCategory.setCarCategoryImage(dto.getCarCategoryImage());
          carCategory.setCarCategoryName(dto.getCarCategoryName());
          carCategory.setDiscountPerPrice(dto.getDiscountPerPrice());
          carCategory.setCostPerOneKilometer(dto.getCostPerOneKilometer());
          carCategory.setCars(dto.getCars().stream().map(carDto -&gt; {
              Car car =mergeDtoIntoAggregate(carDto);
              car.setCarCategory(carCategory);
              return car;
          }).collect(Collectors.toList()));
          return carCategory;
      }
      private CarDto mergeAggregateIntoDto(Car car){
          CarDto carDto = new CarDto();
          carDto.setCarCategory(car.getCarCategory().getCarCategoryName());
          carDto.setCarId(car.getCarId());
          carDto.setCarImage(car.getCarImage());
          carDto.setCarState(car.getCarState());
          carDto.setNumOfPas(car.getNumOfPas());
          carDto.setCarName(car.getCarName());
          return carDto;
      }
  
      private Car mergeDtoIntoAggregate(CarDto dto) {
          Car car = new Car();
          car.setCarId(dto.getCarId());
          car.setCarImage(dto.getCarImage());
          car.setCarName(dto.getCarName());
          car.setCarState(dto.getCarState());
          car.setNumOfPas(dto.getNumOfPas());
          return car;
      }
  }
  </code></pre>
  <p>So if I need OrderAssembler I will have duplicate code when I'm converting Car to Car Dto and back. So how can I prevent duplicate code? Thanks.</p>