경험/이슈

Gradle 버전 이슈로 Lombok이 안 됨

2023. 8. 23.
목차
  1. 문제 상황
  2. 문제 상황 2
  3. 결론
728x90

결론으로 바로 가기

먼저 이 문제는 '스프링 부트와 AWS로 혼자 구현하는 웹 서비스'라는 책을 실습하는 과정에서 마주친 상황이다.

책은 몇 년 전에 지어진 기준이라 자바나 스프링부트의 버전이 낮게 되어있다. 그렇지만 그 당시 버전보다는 지금 상황에서 안정된 최신 버전으로 변경사항은 고치며 해보고 싶어 최신버전으로 진행했다.

  • Spring Boot : 3.1.2
  • Java : 17
  • Gradle : 8.2.1 (Gradle은 신경 못 썼지만 이거 때문에 문제가 있었다..)

 

문제 상황

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.projectlombok:lombok'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'com.h2database:h2'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

처음에는 저렇게 롬복 의존성 라이브러리를 추가해 주었다.

@Getter나 @Setter나 롬복에서 지원하는 어노테이션들은 잘 사용도 되고 자동완성도 됐다.

 

import lombok.Getter;
import lombok.RequiredArgsConstructor;

@Getter
@RequiredArgsConstructor
public class HelloResponseDto {
    private final String name;
    private final int amount;
}

이렇게 인텔리제이에서 수정하라고 노란줄이 표시됐다.

책에서 나온 대로 실습하니 우선 노란 줄로 "Class can be a record"라며 JDK16에서 정식 스펙으로 포함된 record를 사용하라고 권장했다. 처음에는 넘어갔다.

 

import org.junit.jupiter.api.Test;

import static org.assertj.core.api.Assertions.assertThat;

class HelloResponseDtoTest {

    @Test
    public void 롬복_기능_테스트() {
        //given
        String name = "test";
        int amount = 1000;

        //when
        HelloResponseDto dto = new HelloResponseDto(name, amount);

        //then
        assertThat(dto.getName()).isEqualTo(name);
        assertThat(dto.getAmount()).isEqualTo(amount);
    }
}

그런데 테스트 코드를 돌려보니 오류가 났다. error는 "variable name not initialized in the default constructor" 그래서 record를 사용하면 될까 하고 바로 사용해 봤다. (record는 코틀린의 data class와 비슷한 느낌을 받았다.)

 

public record HelloResponseDto(String name, int amount) {
}

record를 사용하면 생성자를 작성하지 않아도 되고 toString, equals, hashCode 메서드에 대한 구현을 자동으로 제공한다고 하여 롬복 어노테이션들은 지워줬다.

 

@Test
public void 롬복_기능_테스트() {
    //given
    String name = "test";
    int amount = 1000;

    //when
    HelloResponseDto dto = new HelloResponseDto(name, amount);

    //then
    assertThat(dto.name()).isEqualTo(name);
    assertThat(dto.amount()).isEqualTo(amount);
}

dto가 변하면서 테스트 로직도 조금 변경됐는데 `getName()`이 아닌 `name()`으로 롬복을 사용하지 않은 모습이다.

 

이렇게 해서 테스트는 성공했지만 지금 보면 근본적으로 해결한 것은 아니었다. 결국 두 번째 문제가 발생한다.

 

문제 상황 2

import jakarta.persistence.*;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
@Entity
public class Posts {

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

    @Column(length = 500, nullable = false)
    private String title;

    @Column(columnDefinition = "TEXT", nullable = false)
    private String content;

    private String author;

    @Builder
    public Posts(String title, String content, String author) {
        this.title = title;
        this.content = content;
        this.author = author;
    }
}

이렇게 생성자 주입을 할 때 롬복의 builder 패턴을 사용해 보는 걸 권장하셨다.

 

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@ExtendWith(SpringExtension.class)
@SpringBootTest
class PostsRepositoryTest {

    @Autowired
    PostsRepository postsRepository;

    @AfterEach
    public void cleanup() {
        postsRepository.deleteAll();
    }

    @Test
    public void 게시글저장_불러오기() {
        //given
        String title = "테스트 게시글";
        String content = "테스트 본문";
        String author = "test";

        postsRepository.save(Posts.builder()
                .title(title)
                .content(content)
                .author(author)
                .build());

        //when
        List<Posts> postsList = postsRepository.findAll();

        //then
        Posts posts = postsList.get(0);
        assertThat(posts.getTitle()).isEqualTo(title);
        assertThat(posts.getContent()).isEqualTo(content);
        assertThat(posts.getAuthor()).isEqualTo(author);
    }
}

그런데 계속 테스트를 하는 과정에서

error: cannot find symbol
        postsRepository.save(Posts.builder()
                                  ^
  symbol:   method builder()
  location: class Posts

이런 에러가 발생했다. 계속 롬복을 인식을 못하는 것이었다. 그래서 스프링부트버전과 자바버전도 다운시켜 보고 다 해봤는데 해결을 하지 못했다. 결국 문제는 Gradle의 버전이었다..

 

결론

Gradle의 버전이 올라가면서 Lombok 의존성을 추가하는 방법이 바뀌었다는 것이다!

 

Gradle 5.x 미만

dependencies {
  implementation 'org.projectlombok:lombok'
}

 

Gradle 5.x 이상

dependencies {
  compileOnly 'org.projectlombok:lombok'
  annotationProcessor 'org.projectlombok:lombok'
}

 

참고

책은 JUnit4를 사용하고 있는데 JUnit5로 넘어오면서 @RunWith는 @ExtendWith로 변환하게 되었다.

@RunWith(SpringRunner.class) ➜ @ExtendWith(SpringExtension.class)

 

 

 

언제나 잘못된 설명이나 부족한 부분에 대한 피드백은 환영입니다🤍

728x90
저작자표시 비영리 변경금지 (새창열림)
  1. 문제 상황
  2. 문제 상황 2
  3. 결론
'경험/이슈' 카테고리의 다른 글
  • 서버 환경 구축 중 만난 이슈 정리
  • Spring Security 버전 이슈로 인한 오류 해결
  • SpringBoot 버전 이슈로 Mustache 한글 깨짐
  • Kotest BehaviorSpec에서 transaction rollback 안 됨
호야_
호야_
안녕하세요😊 아는 것만 보이는 게 아닌, 아는 만큼 보인다고 생각하는 백엔드 개발자입니다.
호야_
개발잠
호야_
전체
오늘
어제
  • 분류 전체보기 (28)
    • 경험 (28)
      • 이슈 (12)
      • 기술 (11)
      • 회고 (5)

블로그 메뉴

  • 깃허브
  • 블로그관리 홈
  • 글쓰기

인기 글

최근 글

최근 댓글

250x250
hELLO · Designed By 정상우.
호야_
Gradle 버전 이슈로 Lombok이 안 됨
상단으로

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.