ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Lombok 사용시 주의할 점
    Spring 2021. 12. 29. 09:36

     

     

    스프링 프로젝트를 진행하면 lombok 라이브러리의 편리함 때문에 이를 사용하는 경우가 많지만, 

    롬복을 사용시에는 다음과 같은 주의점이 존재한다. 

     

     

     

    @AllArgsConstructor, @RequiredArgsConstructor 의 사용 금지
    @AllArgsConstructor
    public static class Card {
    
    //    private Card(long frontNumber, long backNumber) {
    //    this.frontNumber = frontNumber;
    //    this.backNumber = backNumber;
    //    }
    
        private long frontNumber;
        private long backNumber;
    }
    
    @AllArgsConstructor
    public static class Card {
    
    //    private Card(long backNumber, long frontNumber) {
    //    this.backNumber = backNumber;
    //    this.frontNumber = frontNumber;
    //    }
    
        private long backNumber;
        private long frontNumber;
    }

    @AllArgsConstructor의 경우 위와 같이 생성요소의 위치가 변하는 것 만으로 생성자의 파라미터 순서를 바꿔서 필드 선언에 맞춰서 변경시켜 버린다. 이 경우에는 IDE가 제공해주는 리팩토링이 작동하지 않고 동일한 타입의 파라미터로 오류가 발생하지 않아 개발자도 인식하기가 어려운 인자 값이 바뀌어 들어가게 되는 버그가 발생하게 된다. 이는 @RequiredArgsConstructor도 마찬가지로 버그가 발생할 수 있다. 

     

    위의 어노테이션은 편리하게 생성자를 생성해주는 어노테이션으로 프로젝트 중에서 많이 사용되는 롬복 어노테이션이지만 이것이 치명적인 버그를 생성할 수 있음에 주의해야  한다. 

     

     

    public static class Card {
    
        @Builder
        private Card(long frontNumber, long backNumber) {
        this.frontNumber = frontNumber;
        this.backNumber = backNumber;
        }
    
        private long frontNumber;
        private long backNumber;
    }

    대신에 @Builder (파라미터를 순서가 아닌 인자 이름으로 인식)를 사용 해서 이를 방지하자. 

     

     

     

     

     

    @EqualsAndHashCode의 무분별한 사용 자제
    @EqualsAndHashCode
    public static class Card {
        private int cardId;
        private int number;
     
        public Card(int cardId, int number) {
            this.cardId = cardId;
            this.number = number;
        }
    }
    
    Card card = new Card(2, 8);
     
    Set<Card> cards = new HashSet<>();
    cards.add(card); // Set에 객체 추가
     
    System.out.println("변경전 : " + cards.contains(card)); // true
     
    card.setNumber(10); // number 값 변경
    System.out.println("변경후 : " + cards.contains(card)); // false

    동일한 객체이지만 Set에 저장한 뒤에 필드 값을 변경하면 hashCode가 변경되어 찾을 수 없게 된다. 

     

    따라서, 불변 클래스를 제외하고는 아무 파라미터 없는 @EqualsAndHashCode의 사용은 금지하고, 일반적으로 비교에서 사용하지 않는 Data 성 객체는 equals & hashCode를 따로 구현하지 않아야 한다. (항상 @EqualsAndHashCode(of={"필드명시"})의 형태로 동등성 비교에 필요한 필드를 명시하는 형태로 사용해야 한다. )

     

    온전한 Immutable 필드를 대상으로만 equals & hashCode를 만들기는 매우 어려우므로 최소한 꼭 필요하고 일반적으로 변하지 않는 필드에 대해서만 만들도록 해야 한다. 

     

     

     

     

    @Data 의 사용 금지
    @Data
    public class Card {
    	...
    }
    
    @Getter
    @Setter
    @ToString
    public class Card {
    	...
    }

    @Data는 파라미터 없는 @EqualsAndHashCode와 @RequiredArgsConstructor 등을 포함한 변경가능한 데이터 클래스를 만들어주는 조합형 어노테이션으로 이 때문에 사용을 아예 금지하고 위와 같이 필요한 부분을 명시하여 사용하는 것이 좋다. 

     

    또한 무분별한 @Data 어노테이션을 사용할 경우 양방향 연관관계에서의 순환참조 문제가 발생할 수 있다. @ToString 사용시에는 분명하게 @ToString사용임을 명시하고 @ToString(exclude="...")나 @ToString(of="...")처럼 어노테이션을 사용해서 불필요한 부분은 제외하도록 하자. 

     

     

     

     

    @Value 의 사용 금지
    @Value
    public class Card {
    }
    
    @Getter
    @ToString
    public class Card {
       // private final 로 여러 필드 생성
       // 생성자와 필요한 경우에만 equals, hashCode 직접 작성
    }

    @Value 어노테이션은 변경 불가능한 클래스를 만들어주는 조합 어노테이션이지만 이 또한 @EqualsAndHashCode ( 불변 클래스라 큰 문제는 되지 않는다), @AllArgsConstructor (문제 발생) 를 포함하여 사용을 금지시키고 필요한 부분을 명시하는 것이 좋다. 

     

     

     

    @Builder는 생성자나 static 객체 생성 메서드에 직접 바로 적용
    @Builder
    public static class Card {
    
        private Card(long frontNumber, long backNumber) {
        this.frontNumber = frontNumber;
        this.backNumber = backNumber;
        }
    }
    
    public static class Card {
    
        @Builder
        private Card(long frontNumber, long backNumber) {
        this.frontNumber = frontNumber;
        this.backNumber = backNumber;
        }
    }

    @Builder를 사용하면 객체 생성이 더 명확하고 쉬워지지만 이는 기본적으로 @AllArgsConstructor를 내포하고 있다.생성자를 package private으로 만들기 때문에 외부에서 생성자를 호출하는 일이 쉽게 발생하지 않아 이 자체로는 평상시에 문제가 되지 않지만 해당 클래스의 다른 메소드에서 이렇게 자동으로 생성된 생성자를 사용하거나 할 때 문제가 발생될 수 있다. 

     

    따라서 @Builder 어노테이션은 가급적 클래스 보다는 직접 만든 생성자 혹은 static 객체 생성 메서드에 붙이는 것을 권장한다. 

     

     

     

     

    @Log 의 사용은 @Slf4j로 가급적 사용

    @Log 어노테이션을 이용해 각종 Logger를 자동생성할 수 있다. (기본적으로 private static final로 생성, static 필드 혹은 Logger 객체 이름을 변경하고자 한다면 lombok.config를 사용)

     

    그런데 @Slf4j는 Logger와 같이 field 변수로 만들 필요가 없어 static final로 지정하여 별다른 처리없이 static method 에서도 호출이 가능하므로 가급적 @Slf4j를 사용하자. 

     

     

     

     

     

    Lombok

    따라서 실무 프로젝트에서는 가급적 @Getter, @Setter, @ToString만 사용하도록 하고 그 외의 것들은 사용을 자제하거나 매뉴얼을 보고 보수적으로 사용하도록 하자. (@EqualsAndHashCode는 불변필드만 명시적으로 지정하면서 자제해서 사용하거나 가급적 IDE 코드 제너레이션 등을 통해 코드를 직접 만들어 사용)

     

     

     

     

     

    (참고한 사이트)

    https://kwonnam.pe.kr/wiki/java/lombok/pitfall

     

    java:lombok:pitfall [권남]

     

    kwonnam.pe.kr

    https://bkjeon1614.tistory.com/657

     

    [Lombok] Lombok 사용시 주의사항

    Lombok 사용시 주의사항 (1.16 기준) lombok.config를 통하여 애노테이션 사용금지 및 각종 설정 config.stopBubbling = true lombok.data.flagUsage=error lombok.value.flagUsage=error lombok.val.flagUsage=er..

    bkjeon1614.tistory.com

    https://velog.io/@jsj3282/Lombok

     

    Lombok

    Lombok이란? 은 Java 기반에서 기계적으로 작성하는 VO, DTO, Entity 관련 작업을 손쉽게 하게 해주는 도구이다. 보통 Model 클래스나 Entity 같은 도메인 클래스 등에는 수많은 멤버변수가 있고 이에 대응

    velog.io

     

     

Designed by Tistory.