Ini permasalahannya tentang apa ?

Terkadang kita mempunyai 2 class yang strukturnya hampir sama. Misalnya class User dan UserDto. Kita ingin melakukan copy semua attribut dari Objek User ke Objek UserDto secara otomatis.

Lho kok bisa ada 2 class yang hampir sama, kasusnya apa ?

Iya, mungkin saja, karena mungkin saja 2 class ini mempunyai kepentingan yang berbeda. class User adalah class mapping dari database ke object Java. Didalamnya terdapat informasi mengenai pengguna/user. Ada informasi sensitif yang tidak boleh diketahui oleh orang lain. Cukup kode program internal kita saja yang tahu. Misalnya informasi tentang KTP, Tanggal lahir, Status , Pekerjaan, dll.

Sementara itu kita juga mempunyai service yang harus mengembalikan data user ini kepada aplikasi lain atau menampilkannya ketika dipanggil dari web atau antarmuka lainnya. Tentunya kita tidak ingin informasi sentitif tadi ikut ditampilkan dan dikirimkan. Oleh karenanya dibuatlah satu class lagi UserDto yang cuma berisikan data user yang tidak sensitif. Kita namakan class ini class DTO (Data Transfer Object).

Caranya tentu saja dengan melakukan mapping dari objek User ke objek UserDto.

Cara standar adalah dengan melakukan instansiasi objek baru UserDto dan melakukan mapping satu persatu attribut nya.

Contoh :

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
  private String id;
  private String email;
  private String noKtp;
  private String tglLahir;
}

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserDto {
  private String id;
  private String email;
}

// panggil di main program
public static void main(String[] args) {
    // simulasi instansiasi user dari database
    User user = new User("1", "johndoe@mail.com","12345678901234567","2010-10-14");

    // create Dto Object

    UserDto userDto = new UserDto();
    userDto.setId(user.getId());		
    userDto.setEmail(user.getEmail());

    // print ke console
    System.out.println("User ==> " + user);
    System.out.println("User DTO ==> " + userDto);
}

Hasilnya :

User ==> User(id=1, email=johndoe@mail.com, noKtp=12345678901234567, tglLahir=2010-10-14)
User DTO ==> UserDto(id=1, email=johndoe@mail.com)

Code diatas akan berjalan lancar dan sesuai dengan yang kita harapkan. Untuk kasus diatas, attribut lainnya kita abaikan terlebih dahulu untuk kemudahan ilustrasi.

Lalu permasalahannya dimana ?

Tidak ada yang salah dengan code yang diatas, tetapi kita akan melakukan pekerjaan copy attribut secara berulang. Kalau cuma ada 1 atau 2 attribut yang kita copy, maka tidak jadi masalah. Tetapi kalau banyak attributnya, misalnya attribut yang sama antara class User dan class UserDto itu ada 10 attribut, maka ada tambahan 10 line baru untuk melakukan copy attribut tersebut.

Jadi permasalahannya cuma di penulisan code yang lebih banyak dan kemungkinan ada copy attribut yang luput ketika kita tulis satu-persatu seperti diatas.

Apa ada cara yang lebih mudah ? pakai library kah ?

Ya, betul sekali. Ada cara yang lebih mudah dengan menggunakan class BeanUtils

Ada 2 class BeanUtils, yaitu

1.dari apache common lang –> org.apache.commons.beanutils.BeanUtils
2.dari spring framework –> org.springframework.beans.BeanUtils.BeanUtils

Apakah kedua class ini sama fungsinya ?

Betul, kedua class utility ini sama fungsinya, tetapi parameternya berkebalikan, yaitu :

  1. Apache Common : org.apache.commons.beanutils.BeanUtils

Method yang digunakan : BeanUtils.copyProperties(Object destination, Object source);

Parameter pertama adalah destination, yaitu objek yang menjadi tujuan.
Parameter kedua adalah source, yaitu objek yang menjadi sumber.

Contoh :

import java.lang.reflect.InvocationTargetException;
import org.apache.commons.beanutils.BeanUtils;
..
..
public static void main(String[] args) {
    // simulasi instansiasi user dari database
    User user = new User("1", "johndoe@mail.com","12345678901234567","2010-10-14");

    // create Dto Object
    UserDto userDto = new UserDto();
    try {
      BeanUtils.copyProperties(userDto, user);
    } catch (IllegalAccessException | InvocationTargetException e) {
      e.printStackTrace();
    }

    // print ke console
    System.out.println("User ==> " + user);
    System.out.println("User DTO ==> " + userDto);
}

Hasilnya :

User ==> User(id=1, email=johndoe@mail.com, noKtp=12345678901234567, tglLahir=2010-10-14)
User DTO ==> UserDto(id=1, email=johndoe@mail.com)

Catatan :

a. class dari Apache Common ini akan melempar IllegalAccessException atau InvocationTargetException, sehingga harus ditambahkan try catch didalamnya.

b. jangan sampai terbalik menaruh source dengan destinationnya, karena program tetap akan jalan dengan hasil yang tidak diharapkan

  1. Spring Framework : org.springframework.beans.BeanUtils.BeanUtils

Method yang digunakan : BeanUtils.copyProperties(Object source, Object destination);

Parameternya berkebalikan dengan method Apache Common, yaitu :

Parameter pertama adalah source, yaitu objek yang menjadi sumber.
Parameter kedua adalah destination, yaitu objek yang menjadi tujuan.

Sepertinya lebih intuitif untuk memakai BeanUtils dari Spring Framework ini,

Contoh :

import org.springframework.beans.BeanUtils;

public static void main(String[] args) {
    // simulasi instansiasi user dari database
    User user = new User("1", "johndoe@mail.com","12345678901234567","2010-10-14");

    // create Dto Object
    UserDto userDto = new UserDto();
    BeanUtils.copyProperties(user, userDto);

    // print ke console
    System.out.println("User ==> " + user);
    System.out.println("User DTO ==> " + userDto);
}

Hasilnya :

User ==> User(id=1, email=johndoe@mail.com, noKtp=12345678901234567, tglLahir=2010-10-14)
User DTO ==> UserDto(id=1, email=johndoe@mail.com)



Catatan :

a. class dari Spring Framework ini tidak akan melempar Exception, sehingga tidak perlu ditambahkan try catch didalamnya.

b. jangan sampai terbalik menaruh source dengan destinationnya, karena program tetap akan jalan dengan hasil yang tidak diharapkan