Tags:

Hãy cẩn thẩn khi dùng annotation @Data của Lombok

@Data là cách dùng nhanh khi bạn muốn thêm tất cả các annotation:

của Lombok vào 1 class.

Để 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>

@Data annotation trong Lombok

Hãy thử xem một ví dụ dưới đây khởi tạo một Persion class với đầy đủ các hàm getter, setter, toString, equals, hashCodeconstructor

import java.util.Objects;

public class Staff {

    private String firstname;
    private String lastname;

    public Person() {
    }

    public String getFirstname() {
        return firstname;
    }

    public String getLastname() {
        return lastname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 17 * hash + Objects.hashCode(this.firstname);
        hash = 17 * hash + Objects.hashCode(this.lastname);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Person other = (Person) obj;
        if (!Objects.equals(this.firstname, other.firstname)) {
            return false;
        }
        if (!Objects.equals(this.lastname, other.lastname)) {
            return false;
        }
        return true;
    }

    protected boolean canEqual(final Object other) {
        return other instanceof Person;
    }

    @Override
    public String toString() {
        return "Person{" + "firstname=" + firstname + ", lastname=" + lastname + '}';
    }

}

Đây rõ ràng là một công việc khá tốn thời gian và lặp đi lặp lại rất nhiều với hình thức đều giống nhau. Mặc dù các IDE hiện tại có hỗ trợ sinh code tự động những method này tuy nhiên nhìn vào một class với 1 mớ code như này thì chán quá nhỉ.

Giờ đây, chúng ta có thể sử dụng @Data để sinh các hàm trên một cách tự động trong quá trình build. Code của chúng ta chỉ vọn vẹn có vài dòng, giúp focus chính vào các thuộc tính và các hàm quan trọng khác của class.

import lombok.Data;

@Data
public class Staff {

    private String firstname;
    private String lastname;
}

Làm cách nào để sử dụng các annotation khác với Lombok, Override các annotation mà @Data đã bao gồm

Giả sử nếu bạn đã sử dụng @Data annotation rồi, nhưng bạn không muốn loại bỏ các getter() method trong class chẳng hạn,  hay muốn thay thế @RequireArgsConstructor bằng @AllArgsConstructor?

Thật may mắn, bạn có thể chỉ đinh những annotation khác mà Lombok cung cấp, nếu có sự xung đột giữa @Data và các annotation khác thì chúng sẽ được ưu tiên sử dụng hơn là của @Data.

Ví dụ

Nếu bạn muốn loại bỏ getter() method: 

import lombok.*;

@Getter(AccessLevel.NONE)
@Data
public class Staff {

    private String firstname;
    private String lastname;
}

Thay thế @RequiredArgsConstructor thành @AllArgsConstructor

import lombok.*;

@AllArgsConstructor
@Data
public class Staff {

    private String firstname;
    private String lastname;
}

Hãy cẩn thận khi dùng @Data

@Data annotation bao gồm hầu hết các annotation mà mình muốn sử dụng nên mình đã sử dụng nó một cách rất tuỳ tiện. Cho đến một ngày gặp StackOverFlowError, thì mới than ôi làm sao.

import lombok.*;

@Data
class Group {
    private String name;
    private Staff staff;
}

@Data
public class Staff {

    private String firstname;
    private String lastname;
    private Group group;

    public static void main(String[] args) {
        Staff staff = new Staff();

        Group group = new Group();

        staff.setGroup(group);
        group.setStaff(staff);

        System.out.println(staff.toString());
    }
}

Đoạn code ở trên nhìn thoáng qua thì không có vấn đề gì, mình chỉ khởi tạo và xuất giá trị ra màn hình. Thế nhưng kết quả thật sự là StackOverFlowError.

 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.

Tương tự với trường hợp gọi hashCode() method:

System.out.println(staff.hashCode());

Cũng sẽ dẫn đến lời gọi hàm vô tận và gây ra lỗi StackOverFlow.

Tóm lược

Như vậy là mình đã giới thiệu xong một số cách dùng của @Data annotation, đây thật sự là một annotation khá hữu dụng với độ linh hoạt và ngắn gọn nó mang lại. Tuy nhiên hãy chú ý khi sử dụng để tránh gặp phải những lỗi hy hữu ở trên nhé.

Nguồn tham thảo

https://stevenmwesigwa.com/blog/9/how-to-use-data-annotation-with-project-lombok-in-java-applications

https://projectlombok.org/features/Data

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