Framework/Springboot

[Springboot] @ToString.Exclude, @ToString(exclude =" ") 정리 및 오류

웹개발자(진) 2024. 6. 12. 19:57
반응형

 

 

 

잡담

Springboot 프로젝트를 진행도중 Entity를 만드는 과정에서 오류가 발생했습니다. Lombok을 통해 @Tostring을 추가해서 해당 데이터를 출력하는 중이었는데 참조하는 모든 값을 출력하면 정작 필요한 값을 확인하기 힘들기 때문에 Exclude를 사용하는 과정이었습니다.


 

 

 

@ToString. Exclude 사용 예제

import lombok.ToString;

@ToString
public class User {
    private String name;
    private int age;
    @ToString.Exclude
    private String password;

    public User(String name, int age, String password) {
        this.name = name;
        this.age = age;
        this.password = password;
    }
    
    // Getters and Setters 생략
}

위 예제에서 @ToString. Exclude는 password 필드를 toString() 메서드에서 제외합니다. 따라서 다음과 같은 결과를 얻을 수 있습니다.


public class Main {
    public static void main(String[] args) {
        User user = new User("Alice", 30, "secret");
        System.out.println(user.toString());
    }
}

 

출력 결과:

User(name=Alice, age=30)

 


 

@ToString(exclude = "") 사용 예제

@ToString(exclude = "")는 클래스 수준에서 여러 필드를 한 번에 제외할 때 유용합니다.

import lombok.ToString;

@ToString(exclude = {"password", "ssn"})
public class User {
    private String name;
    private int age;
    private String password;
    private String ssn;

    public User(String name, int age, String password, String ssn) {
        this.name = name;
        this.age = age;
        this.password = password;
        this.ssn = ssn;
    }
    
    // Getters and Setters 생략
}

위 예제에서 @ToString(exclude = {"password", "ssn"})는 password와 ssn 필드를 toString() 메서드에서 제외합니다. 따라서 다음과 같은 결과를 얻을 수 있습니다.

public class Main {
    public static void main(String[] args) {
        User user = new User("Bob", 25, "mypassword", "123-45-6789");
        System.out.println(user.toString());
    }
}

 

출력 결과:

User(name=Bob, age=25)

 

정리

  • @ToString. Exclude: 개별 필드를 toString() 메서드에서 제외할 때 사용.
  • @ToString(exclude = {"필드명 1", "필드명 2"}): 여러 필드를 한 번에 toString() 메서드에서 제외할 때 사용.

이 두 애노테이션을 적절히 활용하면 toString() 메서드에서 민감한 정보를 쉽게 제외할 수 있습니다.

 


오류 수정

작성 중이었던 게시판 도메인

package org.zerock.b01.domain;

import jakarta.persistence.*;
import lombok.*;
import org.hibernate.annotations.BatchSize;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Entity
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "imageSet")
public class Board extends BaseEntity{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long bno;

    private String id;
    @Column(length=500, nullable=false)
    private String title;
    @Column(length=2000, nullable=false)
    private String content;
    @Column(length=500, nullable=false)
    private String name;

    @OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @Builder.Default
    @BatchSize(size=20)
    private Set<BoardImage> imageSet = new HashSet<>();

    @OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
    @BatchSize(size=20)
    @ToString.Exclude
    private List<Reply> replies;

    public void change(String title, String content, String name){
        this.title = title;
        this.content = content;
        this.name = name;
    }

    public void addImage(String uuid, String FileName){
        BoardImage image = BoardImage.builder()
                .uuid(uuid)
                .fileName(FileName)
                .board(this)
                .ord(imageSet.size())
                .build();
        imageSet.add(image);
    }

    public void clearImage(){
        imageSet.forEach(boardImage -> boardImage.changeBoard(null));
        this.imageSet.clear();
    }
}

이 코드는 Board라는 이름의 엔티티 클래스를 정의하고 있습니다. 이 클래스는 데이터베이스의 테이블과 매핑되는 JPA 엔티티로, 게시판의 게시글 정보를 저장합니다. 


문제 발생

    @Test
    public void testInsertWithImage(){
        Board board = Board.builder()
                .id("tester01")
                .title("Image test")
                .content("첨부파일 테스트")
                .name("tester01")
                .build();

        for(int i=0; i<3; i++){
            board.addImage(UUID.randomUUID().toString(), "file"+i+".jpg");

        }

        boardRepository.save(board);
    }

게시판에 파일을 업로드하는 코드를 작성 중이었었기 때문에 테스트 코드를 통해 게시판 엔티티 클래스를 정의하고 임의의 파일을 추가하고 있었는데 오류가 발생했습니다.

 

@ToString(exclude = "imageSet") // 여기!
public class Board extends BaseEntity{

해당 코드를 통해서 imageSet 필드를 제외한 나머지 필드에 대해 toString 메서드를 자동으로 생성합니다. 순환 참조를 방지하기 위해 imageSet를 제외하는데요. 더 아래에 있는 코드를 보면

 

@OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@BatchSize(size=20)
@ToString.Exclude // 여기!
private List<Reply> replies;

@ToString. Exclude를 통해서 해당 필드를 제외한 나머지 필드에 대해서 ToString을 자동 생성하게 했습니다.

해당 Lombok은 따로따로 쓸 때는 동작하는데 막상 한 코드에 두 가지를 다쓰려니 에러가 발생하였습니다.

 


해결방법

해결 방법은 정말 간단했습니다. 결론부터 말하면 같이 안 쓰면 됩니다. 하나는 구버전이고 하나는 신버전인데 둘 다 지원하기 때문에 어떤 방법을 써도 사용가능합니다. 동시에 두 개를 같이 쓰지만 않으면 가능합니다.

@ToString(exclude = {"imageSet","replies"}) // 여기!
public class Board extends BaseEntity{

위와 같이 중괄호에담아아서 두 가지의 필드를 동시에 제외시키는 방법이 있고


 

@OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@BatchSize(size=20)
@ToString.Exclude // 여기!
private List<Reply> replies;
@OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@Builder.Default
@BatchSize(size=20)
@ToString.Exclude // 여기!
private Set<BoardImage> imageSet = new HashSet<>();

위의 코드처럼 제외하고 싶은 필드 위에 @ToString. Exclude Lombok을 각각 적어 주면 문제가 해결됩니다.


 

글을 마치며

최신 업데이트 내용 발췌

Lombok의 업데이트 내용을 살펴보면, @ToString. Exclude는 더 나중에 추가된 기능입니다. 이 기능은 코드의 가독성을 높이고, 클래스 레벨에서 제외할 필드를 한꺼번에 관리하는 대신, 각 필드에 개별적으로 적용하여 더 명확하게 관리할 수 있도록 도입되었습니다.

따라서, 최신 업데이트와 함께 추가된 기능은 @ToString. Exclude입니다. 기존의 클래스 레벨에서 필드를 제외하는 방식인 @ToString(exclude = "")는 오래된 방법이라고 할 수 있습니다.

결론

  • 오래된 방법: @ToString(exclude = "")
  • 최신 업데이트 방식: @ToString.Exclude

이제 두 가지 방법 중 최신 업데이트와 함께 도입된 방식이 @ToString. Exclude임을 알 수 있습니다. 이를 통해 각 필드에 대해 보다 명확하고 세밀하게 제어할 수 있습니다.

반응형

'Framework > Springboot' 카테고리의 다른 글

[Springboot] thymeleaf 조건문 if  (0) 2024.05.31
[Springboot] Session이란?  (0) 2024.05.30
[Springboot] Scope란?  (0) 2024.05.30
[Springboot] DB설정 / JPA  (0) 2024.05.09
[Springboot] Controller (get / post)  (0) 2024.05.09