Lombok이란?
프로젝트를 하면서 알게 되었던
Lombok에 대해 정리를 한 내용 입니다.
Lombok이란?
Lombok(롬복)은 Java 라이브러리 중 하나입니다.
자바에서 Model을 만들고자 할 때 반복되는 작업을 많이 줄여줍니다.
백문이 불여일견.
예전에 작성했던 예시를 통해서 살펴봅니다.
 public class Movie {
    private String title;
    private String director;
    private int grade;
    private String genre;
    private String summary;
    public Movie() {
    }
    public Movie(String title, String director, int grade, String genre) {
        this.title = title;
        this.director = director;
        this.grade = grade;
        this.genre = genre;
    }
    public Movie(String title, String director, int grade, String genre, String summary) {
        this.title = title;
        this.director = director;
        this.grade = grade;
        this.genre = genre;
        this.summary = summary;
    }
    
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getDirector() {
        return director;
    }
    public void setDirector(String director) {
        this.director = director;
    }
    public int getGrade() {
        return grade;
    }
    public void setGrade(int grade) {
        this.grade = grade;
    }
    public String getGenre() {
        return genre;
    }
    public void setGenre(String genre) {
        this.genre = genre;
    }
    public String getSummary() {
        return summary;
    }
    public void setSummary(String summary) {
        this.summary = summary;
    }
    @Override
    public String toString() {
        return "제목 : "+title+"\n"+"감독 : "+director+"\n"+"평가 : "+grade+"\n"+"장르 : "+genre+"\n"+"평가 : "+summary+"\n";
    }
}
이렇게 Model을 만들다 보면
Getter, Setter, toString 등 을 만들면  코드가 길어집니다.
물론 Generate를 사용하면 그나마 편하게 자동완성이 되기는 하지만
코드가 길다보니 한번에 보기에도 번거롭기도 합니다.
그 과정에서 Lombok을 사용하니 훨씬 간결해진 코드를 확인할 수 있습니다.
package backend.domain.review;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import javax.persistence.*;
@Entity
@Getter @Setter
@NoArgsConstructor
public class ReviewImage {
    @Id
    @GeneratedValue
    private Long reviewImageId;
    @ManyToOne
    @JoinColumn(name = "REVIEW_ID")
    private Review reviewId;
    @Column(columnDefinition = "TEXT")
    private String reviewImage;
    public ReviewImage(Review review, String url) {
        this.reviewId = review;
        this.reviewImage = url;
    }
}
이건 현재 진행중인 프로젝트에서 예시를 가져왔습니다.
JPA를 사용하다보니 컬럼별로 어노테이션이 붙어서 길어보이지만
아무래도 Getter와 Setter같은 것이 없다보니
훨씬 간결해진다는 것을 알 수 있습니다.
처음 예시에서도 @Getter와 @Setter, @ToString 어노테이션 사용한다면
훨씬 간결해질 수 있습니다.
어노테이션 기반으로 하기 때문에 추가적으로 변수를 생성하고 싶다면
변수만 추가해줘도 자동으로 만들어줘서 생산성이 높아집니다.
의존성 주입
사용하기 위해서는 의존성을 주입해줘야 합니다.
Maven과 Gradle 두 가지에 대해서 정리해봤습니다.
버젼은 동일한 버젼, 최신중에서 다운로드 된 횟수가 가장 많은 것을 기준으로 헀습니다.
Maven을 사용하는 경우
- pom.xml에 Dependency 추가
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.12</version>
    <scope>provided</scope>
</dependency>
Gradle을 사용하는 경우
- build.gradle에 Dependency 추가
// https://mvnrepository.com/artifact/org.projectlombok/lombok
providedCompile group: 'org.projectlombok', name: 'lombok', version: '1.18.12'
사용 예제.
[ @Getter @Setter ]
@Getter와 @Setter를 클래스 이름 위에 적용시키면
모든 변수들에 적용이 가능하고, 변수 이름 위에 적용시키면 해당 변수들만 적용 가능합니다.
예를 들기 위해 Project Lombok이라는 공식사이트에서 예시를 가져왔습니다.
첫 번째 예시는 클래스 위에 적용시킴으로써 모든 변수들에 적용하는 예시입니다.
import lombok.Getter;
import lombok.Setter;
@Getter @Setter 
public class GetterSetterExample {
  private int age = 10;
  private String name;
}
특정 변수에 대해서만 적용하고 싶다면 아래와 같이 적용하면 됩니다.
import lombok.AccessLevel;
import lombok.Getter;
import lombok.Setter;
public class GetterSetterExample {
  @Getter @Setter private int age = 10;
  
  @Setter(AccessLevel.PROTECTED) private String name;
}
[ @NoArgsConstructor, @AllArgsConstructor ]
@NoArgsConstructor는 파라미터가 없는 기본 생성자를 자동완성 시켜줍니다.
@AllArgsConstructor는 모든 파라미터를 사용하는 생성자를 자동완성 시켜줍니다.
이번 예제는 공식사이트 내용이 보기 복잡해보여서
진행 중인 프로젝트에서 일부 수정해서 예를 만들었습니다.
@NoArgsConstructor
@AllArgsConstructor
public class ChallengeDto {
    private Long challengeID;
    private String challengeName;
    private String challengeDesc;
    private UserDto challengeOwner;
    private String categoryName;
    private HashtagDto hashtags;
    ...
이렇게 한다면 아래와 같은 생성자가 추가로 만들어집니다.
    public ChallengeDto() {
    }
    public ChallengeDto(Long challengeID, String challengeName, String challengeDesc...){
    this.challengeID = challengeID;
    this.challengeName = challengeName;
    this.challengeDesc = challengeDesc;
    ...(생략)
}
[ @RequiredArgsConstructor ]
@RequiredArgsConstructor는
특정 변수만을 활용하는 생성자를 자동완성 시켜주는 어노테이션입니다.
생성자의 인자로 추가할 변수에 @NonNull 어노테이션을 붙여서
해당 변수를 생성자의 인자로 추가할 수 있습니다.
아니면 해당 변수를 final로 선언해도 의존성을 주입받을 수 있습니다.
위의 Dto를 예시로 했을 때
@RequiredArgsConstructor
public class ChallengeDto {
    private Long challengeID;
    @NonNull
    private String challengeName;
    @NonNull
    private String challengeDesc;
    private UserDto challengeOwner;
    private String categoryName;
    private HashtagDto hashtags;
    ...
이렇게 된다면 challengeName과 challengeDesc에 대한 인자를 받는 생성자가
자동으로 완성됩니다.
    public ChallengeDto(String challengeName, String challengeDesc){
    this.challengeName = challengeName;
    this.challengeDesc = challengeDesc;
}
[ @ToString ]
@ToString 어노테이션을 활용하면
클래스의 변수들을 기반으로 ToString 메소드를 자동으로 완성시켜 줍니다.
출력을 원하지 않는 변수에 exclude를 작성해 출력을 제외할 수 있습니다.
import lombok.ToString;
@ToString(exclude = "password")
public class User {
  private Long id;
  private String username;
  private String password;
  private int[] scores;
}
[ @EqualsAndHashCode ]
@EqualsAndHashCode 어노테이션을 활용하면
클래스에 대한 equals 함수와 hashCode 함수를 자동으로 생성해줍니다.
@EqualsAndHashCode(callSuper = true)
public class User extends Domain {
  private String username;
  private String password;
}
callSuper 속성을 통해 equals와 hashCode 메소드 자동 생성 시
부모 클래스의 필드까지 감안할지 안 할지에 대해서 설정할 수 있습니다.
즉, callSuper = true는 부모 클래스 필드 값들도 동일한지 체크하며,
callSuper = false는 자신 클래스의 필드 값들만 고려합니다.
[ @Data ]
@Data 어노테이션을 활용하면
@ToString, @EqualsAndHashCode, @Getter, @Setter,
@RequiredArgsConstructor를 자동완성 시켜줍니다.
그러나 실무에서는 이것을 지양한다고 합니다.
아무래도 Setter는 객체를 언제든지 변경할 수 있는 상태가 되어서
객체의 안전성이 보장받기 힘듭니다.
때문에 @Data의 활용을 지양한다고 합니다.