Lombok

<Why? Lombok을 사용하는가>

Java프로그래밍을 어느정도 해본사람들은 Model에 Getter/Setter, toString함수 등을 만들어본 경험이 있을것이다. 프로그램의 규모가 커질수록 이 작업은 매우 귀찮은 일인데 Eclipse나 IntelliJ와 같은 IDE tool에서는 Generate라는 기능으로 자동완성을 할 수 있게 지원하기도 한다.

하지만 Getter/Setter, toString()은 당연히 Model이 갖추어야 할 기능임에도 불구하고 작성하는 수고로움이 있고 코드가 길어짐에따라 가독성이 떨어져서 정작 필요한 부분을 찾아내기가 힘들어진다. 물론 유지보수시에도 변수의 타입이 바뀌는 등의 수정이 생기면 함수의 내용도 매번 바꿔주어야 해서 굉장히 불편하다.

이런 경우 굉장히 유용하게 사용할 수 있는 Lombok 라이브러리를 소개한다.


[목차]
1. Eclipse 설정
2. IntelliJ 설정
3. 자주 쓰이는 Annotation

1. Eclipse 설정

Eclipse에서 사용할 경우 공식홈페이지에서 jar파일을 다운받아서 실행하고 이클립스가 위치한 경로로 지정한 후 설치한다. maven 환경에서 dependency를 가져오기 위해서는 pom.xml에 다음과 같이 명시해주어야 한다.

<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.8</version> <!--본인이 다운받은 버전으로 설정-->
</dependency>


2. IntelliJ 설정

IntelliJ에서의 설치는 Eclipse와는 조금 다르다. 위에서 했던 jar파일의 별도 설치없이 프로젝트 생성시 dependency목록에 Lombok을 추가하면 자동으로 추가된다.

다만 Lombok 최초의 사용에 한해서는 Plug-in을 설치 해주어야한다. Plug-in없이 코딩 시 Lombok라이브러리를 추가하는것은 문제가 없어서 어노테이션은 정상적으로 붙지만 외부에서 Getter/Setter등의 함수를 부를경우 빨간줄이 뜬다.

설치방법은 간단하다. 화면 좌측상단의 File을 누르고 Settings창을 열어서 다음과 같이 Lombok을 검색하여 설치한다.

3. Annotation

위의 설정을 완료했다면 사용법은 동일하다. 코드상에서 필요한 어노테이션을 달아주기만 하면 된다.

자주 쓰이는 어노테이션들은 다음과 같다.

3.1 @Getter, @Setter

간단한 프로그램 작성 시 가장 많이 쓰이게 될 어노테이션이다. 원하는 필드에 선언하면 자동으로 get~(boolean타입이라면 is~)/set~함수를 만들어준다.

< Lombok Code >

 @Getter @Setter
 private String name;
 private boolean connect;

< Java Code >

 private String name;
 private boolean connect;
 
 public String getName(){ return name; }
 public void setName(String name){ this.name = name; }
 public boolean isConnect(){ return connect; }
 public void setConnect(boolean connect){ this.connect = connect; }

또한, 필드 레벨이 아닌 클래스 레벨에 @Getter, @Setter를 선언해줄 경우, 클래스 내부의 모든 필드에 접근자와 설정자가 자동으로 생성된다.

3.2 @ToString

@ToString도 @Getter, @Setter같이 필드 레벨, 클래스 레벨에 선언할 수 있다. 만약 클래스 레벨에 선언할 때 toString함수를 만들고 싶지 않은 필드가 있다면 다음과 같이 exclude속성을 사용하여 제외하는것도 가능하다.

< Lombok Code >

@ToString(exclude = "password")
public class User {
  private Long id;
  private String username;
  private String password;
}

< Java Code >

public class User {
  private Long id;
  private String username;
  private String password;

  @java.lang.Override
    public java.lang.String toString() {
        return "User(id=" + id.toString() +
            ", username=" + username + ")";
    }

출력 방식은 아래와 같이 클래스명(필드1명=필드1값,필드2명=필드2값,...) 의 형태이다. exclude속성으로 제외했던 password는 포함되지 않은것을 확인할 수 있다.

@ToString(exclude = "password")
public class User {
  User user = new User();
  user.setId(1L);
  user.setUsername("guest");
  user.setUsername("12345");
  System.out.println(user);
}
User(id=1, username=12345)


3.3 @NonNull

@NonNull은 클래스 레벨에서는 사용이 불가능하며, 클래스 내의 필요한 필드에 직접 사용해야 한다. @NonNull을 사용하면 @Setter로 생성되는 setter 메서드에 전달되는 parameter에 @NonNull이 붙게 된다. 하지만 해당 setter 메서드에 null을 넘기도록 코드를 작성 할 수도 있다. 컴파일 시점에 적용되지 않고 runtime시에 Null Check를 하여 Exception이 발생하도록 하는 것이다. @NonNull을 멤버 변수에 붙인 경우에는 그 필드를 꼭 받도록 생성자가 수정된다.

< Lombok Code >

@Getter @Setter @NonNull
private List<Person> members;

< Java Code >

@NonNull
private List<Person> members;
public Family(@NonNull final List<Person> members) {
    if (members == null) throw new java.lang.NullPointerException("members");
    this.members = members;
}

@NonNull
public List<Person> getMembers() { return members; }

public void setMembers(@NonNull final List<Person> members) {
    if (members == null) throw new java.lang.NullPointerException("members");
    this.members = members;
}


3.4 생성자 자동 생성

@NoArgsConstructor: parameter가 없는 기본 생성자를 생성

@AllArgsConstructor: 모든 필드 값을 parameter로 받는 생성자를 생성

@RequiredArgsConstructor: final이나 @NonNull인 필드 값만 parameter로 받는 생성자를 생성

3.5 @EqualsAndHashCode

@EqualsAndHashCode은 코드에서 객체 비교 등의 용도로 사용되는 equals(), hashCode() 메소드의 코드를 생성해준다. @toString과 마찬가지로 exclude속성을 통해 특정 필드를 제외할 수도 있다.

< Lombok Code >

@EqualsAndHashCode(callSuper=true,exclude={"address","city","state"})
public class Person extends SentientBeing {
    enum Gender { Male, Female }
    @NonNull private String name;
    @NonNull private Gender gender;

    private String address;
    private String city;
    private String state;
}

< Java Code >

public class Person extends SentientBeing {
    enum Gender {
        /*public static final*/ Male /* = new Gender() */,
        /*public static final*/ Female /* = new Gender() */;
    }
    @NonNull
    private String name;

    @NonNull
    private Gender gender;
    private String address;
    private String city;
    private String state;
    
    @java.lang.Override
    public boolean equals(final java.lang.Object o) {
        if (o == this) return true;
        if (o == null) return false;
        if (o.getClass() != this.getClass()) return false;
        if (!super.equals(o)) return false;

        final Person person = (Person)o;
        if (this.name == null ? other.name != null : !this.name.equals(person.name)) return false;
        if (this.gender == null ? other.gender != null : !this.gender.equals(person.gender)) return false;

        return true;
    }

    @java.lang.Override
    public int hashCode() {
        final int PRIME = 31;
        int result = 1;

        result = result * PRIME + super.hashCode();
        result = result * PRIME + (this.name == null ? 0 : this.name.hashCode());
        result = result * PRIME + (this.gender == null ? 0 : this.gender.hashCode());
        return result;
    }
}


3.6 @Data ☆☆☆☆☆

@Data는 위에서 설명한 @Getter, @Setter, @RequiredArgsConstructor, @ToString, @EqualsAndHashCode을 한꺼번에 설정해주는 매우 유용한 어노테이션이다. 가장 기본적인 기능들을 모두 포함하고 있어서 @Data한개만 쓰는 경우도 굉장히 많다.

3.7 Etc

위에 언급한 6가지 이외에도 @Value, @Synchronized, @Builder, @Log등 유용하고 편리한 기능들이 있으므로 추가적으로 더 공부해보는것을 추천한다.

[참고 사이트]

https://ijbgo.tistory.com/6

https://projectlombok.org/features/