티스토리 뷰

같이 스터디했던 동생이 사전과제에 대한 평가에 DTO에 Lombok Setter가 무분별하게 사용을 했다는 피드백을 받았다.

그러다가 좋은 DTO는 무엇일까? 라는 고민을 하다가 ... 엉뚱하게 Lombok으로 화제가 변하게 되어 정리를 해봤다. [출처 : https://kwonnam.pe.kr/wiki/java/lombok/pitfall]


개발을 하다보면 Lombok을 많이 사용하게 된다. 특히, @Data를 많이 사용하고 있다. 이 5글자만 있으면, constructor, getter, setter, toString, equals, hashcode 메소드를 자동으로 

생성해주기 때문에 코드가 굉장히 간결해보이게 만들어준다. 하지만 이 간결함 뒤에는 Reflection이 존재한다.

이렇게 편리한 Lombok을 사용할 때, 주의해야할 점은 무엇이 있을까?! 아래 블로그의 내용을 간단히 정리했다. 더 자세한 내용은 해당 블로그를 참조하면 좋을거 같다!

단지 해당 블로그의 내용이 너무 좋아서, 이 내용을 오랫동안 간직하고 싶어 블로그로 정리하는 것이다! [출처 : https://kwonnam.pe.kr/wiki/java/lombok/pitfall]


@AllArgsConstructor, @RequiredArgsContstructor 사용 금지

 - @AllArgsConstructor : 객체 내부의 인스턴스멤버들을 모두 가지고 있는 생성자를 생성하는 Lombok 어노테이션

 - @RequiredArgsConstructor : 객체 내부의 final, @Notnull 이 붙은 인스턴스멤버들을 가지고 있는 생성자를 생성하는 Lombok 어노테이션


두 어노테이션은 인스턴스 멤버의 순서가 중요하다. 왜냐하면 인스턴스 멤버의 순서가 생성자의 파라미터의 순서와 동일하기 때문이다. 

그렇기 때문에 Person이라는 객체를 생성하기 위해서는 'Person person = new Person("LEE", "DOBY); 로 생성을 해야한다.

그러나 만약, 리팩토링을 하면서 혹은 타인에 의해 해당 인스턴스 멤버의 순서가 바뀌어버리면 어떻게 될까?! 두 인스턴스 멤버는 동일한 타입이기 때문에 컴파일 시, 오류는 발생하지 않는다. 오류가 발생하지 않기 때문에 그냥 지나칠 수 있다. 하지만, 나는 성과 이름이 바뀌게 된다. 그래서 되도록이면, @Builder 어노테이션을 이용하는 것을 권장한다.

그리고 @Builder를 이용해서 객체를 생성하면 코드를 읽을 때, 객체에 대한 대략적인 파악도 가능하고 순서에 의존적이지 않기 때문에 @Builder를 권장한다.

@AllArgsConstructor
public class Person {

    private String lastName;
    private String firstName;

}


무분별한 @EqualsAndHashCode 사용금지

 - @EqualsAndHashCode : equals 메소드와 hashcode 메소드를 생성하는 Lombok 어노테이션


해당 객체가 불변객체라고 한다면, 사용해도 좋다. 하지만 그렇지 않다면 사용을 하지 않는 것이 좋다.

아래 코드처럼 동일한 객체이지만 해당 인스턴스 멤버의 값이 변경되어 문제가 발생할 수 있다. 왜냐하면 Set은 인스턴스 멤버의 값을 해시코드로 변경해서 해당 객체가 동일한 

객체인지를 판단하기 때문에 객체 내부 인스턴스 멤버의 값이 바뀌면 안된다.그렇기 때문에 권장하지 않는다.

그리고 @EqualsAndHashCode (of = {"필드명1, 필드명2 ..."})를 통해서 동등 비교를 할 대상을 선택할 수 있다. 이 옵션을 이용해서 불변필드만 대상으로 하는것도 나쁘지 않다!

하지만 이것 또한 문제가 발생할 수 있다. 필드명1, 필드명2가 문자열로 들어간다. 만약 리팩토링을 하는 과정에서 변수명을 변경했다면, 해당 옵션도 변경해야 한다.

그렇지 않으면 ... 누군가 한명은 울고 있을 것이다. 주변을 둘러봐라! 근데 그게 너다! 모니터 속에 비친 너의 모습을 보아라!

   @Test
    public void name() {
        Set people = new HashSet<>();

        Person person = new Person("LEE", "DOBY");
        people.add(person);
        assertTrue(people.contains(person));

        person.setLastName("FREE");
        assertFalse(people.contains(person));
    }


@ToString 사용시 StackOverflowError가 발생할 수 있다.

 - @ToString : toString 메소드를 생성해주는 Lombok 어노테이션


toString 메소드에서 StackOverflowError가 어떻게 발생할 수 있을까? 라는 의문이 들 수 있다. 하지만 아래와 같은 상황이 있다면 가능하다.

물론 아래와 같은 코드는 좀 억지스러울 수 있다. 그런데, 그런 경우가 발생하더라 ... 특히, JPA에서 객체간의 양방향 관계일때 이런 경우가 발생했다.

두 객체가 서로를 인스턴스 멤버로 가지고 있기 때문에 서로를 서로 참조하다보니 Overflow가 발생한다. 양방향 관계에서 toString을 조심하자!

 
@Data
public class Person {

    private MyName name;
    private int age;

}         

 
@Data
public class MyName {

    private String firstName;
    private String lastName;

    private Person person;

}         
    
 @Test
 public void name() {
     MyName myName = new MyName();
     myName.setFirstName("LEE");
     myName.setLastName("DOBY");
     Person person = new Person();
     person.setName(myName);
     myName.setPerson(person);

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


결국은 제일 나쁜 것은 내가 제일 많이 사용하는 @Data 어노테이션이다. @Data 어노테이션에서는 하지말라는 것이 포함되어 있다.

@Data = @NoArgsConstructor + @Getter + @Setter + @ToString + @EqualsAndHashCode 이다. 하지말라는 것, 조심해야하는 것이 포함되있다.


그러면 해당 클래스에 필요한 Lombok 어노테이션을 사용하는 것이 좋을까?! 개인적으로 Lombok은 개인의 취향인거 같다!

그런데 만약, 처음 해당 프로젝트를 컴파일한 사람이 Lombok 플러그인을 설치하지 않고, 컴파일했을 때, 붉은줄이 쫙쫙 처진다면... 

해당 프로젝트에 대한 첫인상이 굉장히 불편할거 같다 :D 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함