Cách sử dụng annotation @ToString của lombok

Annotation @ToString giúp chúng ta tự hàm toString(), một method thường được sử dụng khi chúng ta muốn kiểm tra tất cả các giá trị của các thuộc tính trong object, nó cũng có thể là công cụ để giúp chúng ta gỡ lỗi.

Để sử dụng Lombok trong project Maven, chúng ta phải thêm dependency:

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version>
</dependency>

@ToString annotation Lombok

@ToString annotation là một class-level annotation, được đặt ở đầu class cho phép lombok tự sinh toString().

Mặc định, nó sẽ in tên class, sau đó đến tên và giá trị của từng thuộc tính theo thứ tự được khai báo được ngăn cách bởi dấy phẩy.

Ví dụ mình tạo một class Staff gồm 2 thuộc tính age, name. Sử dụng @ToString annotation để in giá trị của staff object.

import lombok.ToString;

@ToString
public class Staff {

    public Staff(int age, String name) {
        this.age = age;
        this.name = name;
    }
    private int age;
    private String name;

    public static void main(String[] agrs) {
        Staff staff = new Staff(19, "nth");
        System.out.println(staff.toString());
    }
}
Output: Staff(age=19, name=nth)

Cách sử dụng IncludeFieldNames với @ToString annotation

Phụ thuộc vào trường hợp của chúng ta, có thể không muốn tên của các thuộc tính xuất hiện trong kết quả trả về của toString(), sử dụng IncludeFiledNames trong trường hợp này.

Mặc định giá IncludeFiledNames true đồng nghĩa với việc tên của tất cả các thuộc tính non-static với giá trị của nó sẽ được trả về trong kết quả của hàm toString(). Gán giá trị IncludeFiledNames = false sẽ khiếm lombok loại bỏ tên của các thuộc tính non-static trong kết quả trả về.

import lombok.ToString;

@ToString(includeFieldNames = false)
public class Staff {

    public Staff(int age, String name) {
        this.age = age;
        this.name = name;
    }
    private int age;
    private String name;

    public static void main(String[] agrs) {
        Staff staff = new Staff(19, "nth");
        System.out.println(staff.toString());
    }
}
Output:Staff(19, nth)

Loại bỏ một số thuộc tính với @ToString.Exclude

Trong trường hợp chúng ta muốn loại bỏ một số thuộc tính trong kết quả trả về của toString(), chúng ta có thể sử dụng @ToString.Exclude để đánh dấu các thuộc tính đó.

Ví dụ với Staff class, mình muốn loại bỏ thuộc tính age trong kết quả trả về của toString().

import lombok.ToString;

@ToString
public class Staff {

    public Staff(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @ToString.Exclude
    private int age;

    private String name;

    public static void main(String[] agrs) {
        Staff staff = new Staff(19, "nth");
        System.out.println(staff.toString());
    }
}
Output: Staff(name=nth)

Chỉ định các thuộc tính với @ToString.Include

Một cách thay thế khác là bạn có thể chỉ định các thuộc tính xuất hiện trong kết quả trả về của toString() bằng cách @ToString(onlyExplicitlyIncluded = true) và đánh dấu các thuộc tính với @ToString.Include(name = “some name”).

import lombok.ToString;

@ToString(onlyExplicitlyIncluded = true)
public class Staff {

    public Staff(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @ToString.Include(name = "Staff age")
    private int age;

    private String name;

    public static void main(String[] agrs) {
        Staff staff = new Staff(19, "nth");
        System.out.println(staff.toString());
    }
}
Output: Staff(Staff age=19)

Cách sử dụng doNotUseGetters Lombok

Giá trị mặc định của lombok.toString.doNotUseGettersfalse, nếu true lombok sẽ truy cập trực tiếp giá trị của thuộc tính mà không thông qua getter() method.

Ví dụ nếu doNotUseGetters = true

@ToString(doNotUseGetters = true)
public class Staff {
...
}

Thì hàm toString() được sinh ra bởi lombok sẽ có dạng như sau

public String toString() {
    return "Staff(age=" + this.age + ", name=" + this.name + ")";
}

Ngược lại thì toString() sẽ có dạng sau

public String toString() {
    return "Staff(age=" + this.getAge() + ", name=" + this.getName() + ")";
}

Note: Tuy nhiên với doNotUseGetters = false thì chúng ta cần cung cấp getter() method cho class, nếu không thì nó sẽ tự động truy cập trực tiếp giá trị của thuộc tính giống trường hợp doNotUseGetters = true.

StackOverflowError trong toString()

Hãy cẩn thận khi sử dụng toString(), nếu không sẽ dẫn đến StackOverflowError. Lỗi này thường gặp trong mapping database, khi 2 Entity có mối quan hệ 2 chiều, mỗi Entity class đều được mark @ToString annotation thì khi bạn gọi đến hàm toString() sẽ nhận được lỗi này. 

Lấy ví dụ StaffGroup có mối quan hệ với nhau, trong Staff có một thuộc tính Group và ngược lại.

import lombok.ToString;

@ToString
class Group {
    public Group(String name, Staff staff) {
        this.name = name;
        this.staff = staff;
    }

    private String name;
    private Staff staff;
}


@ToString
public class Staff {

    public Staff(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public void setGroup(Group group) {
        this.group = group;
    }
    private int age;

    private String name;

    private Group group;


    public static void main(String[] agrs) {
        Staff staff = new Staff(19,"nth");
        Group group = new Group("RND", staff);
        staff.setGroup(group);
        System.out.println(staff.toString());
    }
}

Khi bạn thực thi đoạn code trên sẽ gây ra lỗi StackOverFlowError. Điều này được giải thích như sau.

toString() method mặc định sẽ lấy tất cả các thuộc tính của class để trả về. Nếu thuộc tính là một object thì nó sẽ gọi đến hàm toString() của object đó để nhận lại giá trị.

Chính vì vậy, khi chúng ta gọi staff.toString() nó sẽ gọi đến group.toString(), group.ToString() lại gọi đến staff.toString(), cứ như vậy lời gọi hàm trở nên vô tận.

Làm sao để tránh lỗi này? Cách đơn giản nhất là bạn có thể loại bỏ các thuộc tính trong mối quan hệ 2 chiều trong kết quả trả về của toString() với @ToString.Exclude. 

import lombok.ToString;

@ToString
class Group {
    ...
    @ToString.Exclude
    private Staff staff;
}


@ToString
public class Staff {
   ...
    @ToString.Exclude
    private Group group;
    ...
}

Tóm lược

Như vậy là mình đã giới thiệu xong @ToString annotation trong lombok, cứ tưởng sử dụng nó đơn giản, thế nhưng mà nó cung cấp rất nhiều tính năng phục vụ cho rất nhiều nhu cầu của chúng ta phải không nào. Nếu các bạn muốn tìm hiểu sâu hơn, có thể tham khảo link chính thức của lombok mình để ở bên dưới nha.

Nguồn tham khảo

https://projectlombok.org/features/ToString

0 0 vote
Article Rating
Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x