Post

롬복 @All/NoArgsConstructor 왜 쓰고 있었지

롬복 @All/NoArgsConstructor 왜 쓰고 있었지

왜 이제 궁금증이 생긴거지…

자바를 이용해서 클래스를 작성할 때 항상 롬복(Lombok)을 사용하여 여러가지 어노테이션들을 추가해서 아래처럼 편리하게 작업을 처리하고 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Entity
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Board{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long bno;

    private String title;

    private String content;

    private String user;

}

@getter/setter@ToString같은 이름 그대로 기능을 하는 어노테이션이나, @Builder어노테이션 또한 간편히 객체를 생성할 수 있는 기능이라 이해하면서 잘 쓰고 있었다.
그런데 여기와 같이 쓰고 있는 @All/NoArgsConstructor 어노테이션은 어떤 역할을 하고 있는지에 대한 인지를 못하고 있었다.
구체적으로 @All/NoArgsConstructor이 어노테이션들은 생성자를 자동으로 생성한다 라는 기능이라는 것은 인지하고 있지만, 그래서 왜 “이 생성자가 있어야 하냐?” 라는 질문에 대한 대답은 알고 있지 않았다.
그래서 한번 그 대답을 한번 짧게 정리하고자 한다.


@NoArgsConstructor / AllArgsConstructor

@AllArgsConstructor기능은 모든 필드를 매개변수로 갖는 생성자를 자동 생성하는 어노테이션이며, 이 어노테이션을 코드로 풀면 이런식으로 나올 것이다.

1
2
3
4
5
6
public Board(Long bno, String title, String content, String user) {
        this.bno = bno;
        this.title = title;
        this.content = content;
        this.user = user;
    }

반면 @NoArgsConstructor기능은 매개변수가 없는 생성자를 자동 생성하는 어노테이션이다.

1
2
3
public Board() {

}

또한 @RequiredArgsConstructor어노테이션은 필드 중 final이나NotNull이 설정된 변수를 매개변수로 갖는 생성자를 자동 생성한다. 예시로 어노테이션을 추가한 클래스에 final이 설정된 변수를 넣어 롬복이 적용된 코드를 살펴보자.

- 롬복 추가한 클래스
1
2
3
4
5
@RequiredArgsConstructor
public class TestService{
    private final ReplyRepository replyRepository;
    private final ModelMapper modelMapper;
}    
- 롬복이 적용된 코드
1
2
3
4
public ReplyServiceImpl(final ReplyRepository replyRepository, final ModelMapper modelMapper) {
        this.replyRepository = replyRepository;
        this.modelMapper = modelMapper;
    }



그럼 생성자는 “왜” 있을까에 대한 대답은 클래스의 객체(인스턴스)가 생성될 때 호출되는 ‘인스턴스 초기화 메서드’이다. 결국 생성자의 목적은 인스턴스 변수를 초기화하고 사용할 수 있도록 준비하는 것이다.
보통 클래스 내에 선언한 변수 앞에 private를 붙이는데 private은 클래스 외부에서 이 변수를 마음대로 접근할 수 없게 된다.
그래서 어떤 객체를 인스턴스로 생성할 때 Board board = new Board(); 이런식으로 생성하여 접근하는 것이다.
그리고 클래스에는 생성자가 최소 1개는 있어야 하고, 별도로 생성자를 생성하지 않았다면 기본 생성자(@NoArgsConstructor)가 자동으로 생성된다.
그렇다면 롬복을 사용하지 않고 위의 엔티티 클래스를 작성할 때 이런식으로 구성할 것이다.

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
@Entity
public class Board{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long bno;

    private String title;

    private String content;

    private String user;

    public Long getBno() {
        return this.bno;
    }

    public String getTitle() {
        return this.title;
    }

    public String getContent() {
        return this.content;
    }

    public String getUser() {
        return this.user;
    }

    public void setBno(final Long bno) {
        this.bno = bno;
    }

    public void setTitle(final String title) {
        this.title = title;
    }

    public void setContent(final String content) {
        this.content = content;
    }

    public void setUser(final String user) {
        this.user = user;
    }

    public Board(Long bno, String title, String content, String user) {
        this.bno = bno;
        this.title = title;
        this.content = content;
        this.user = user;
    }

    public Board() {
    }

    public String toString() {
        Long var10000 = this.getBno();
        return "Board(bno=" + var10000 + ", title=" + this.getTitle() + ", content=" + this.getContent() + ", user=" + this.getUser() + ")";
    }


}

보다시피 코드가 이런식으로 작성하기에는 번거롭기에 롬복으로 @getter/setter@ToString 혹은 위의 생성자 어노테이션 기능들을 추가해 간단하게 생략할 수 있다.


기타 외..

프로젝트를 진행하면서 참고서나 인터넷을 참고할 때 공통적으로 나오는 의견이 엔티티 클래스를 생성할 때 setter를 가급적 만들지 말라고 한다. 그 이유는 해당 클래스의 인스턴스 값들이 언제 어디서 변해야 하는지 코드상으로 명확하게 구분할 수가 없고, 차후 기능 변경 시 정말 복잡해지기 때문이다.
그렇기 때문에 해당 필드의 값 변경이 필요하다면 그 기능을 할 수 있는 메소드를 추가하는 것이다.
예전에 ModelMapperpropertymap으로 매핑을 설정할 때 엔티티에 setter를 주입해줘야 했는데 다음부터는 이러한 점을 유의해야 겠다.

다음으로는 crud 기능이나 이러한 기본적인 view 컨트롤러를 작성하는 구조는 이해되었지만, 이러한 기본적인 프로젝트에 다른 기능(ex-댓글 기능, 첨부 파일 기능)을 추가하고자 엔티티, 서비스, 리포지토리, 컨트롤러를 새롭게 늘려갈 때마다 이들의 연관관계를 어떻게 맺어줘야 할지, 아니면 어디 하나로 병합할 수 있지 않을까 하는 고민이 많아지고 이러한 고민이 생긴 이유가 아직 연관관계나 구조에 대해 개념을 잡지 못한 것이 아닐까 하는 의문이 들었다.
그래서 연휴동안 코드를 다시 작성하기 보다는 이론들을 다시 읽어 재정립하는 시간을 가졌고, 어느정도 새롭게 배운 것도 있어 여러 잘못 생각한 것도 바로 잡고 한번 다음부터 새롭게 다시 코드를 구성 해봐야겠다.

This post is licensed under CC BY 4.0 by the author.