잡담
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 |