@AllArgsConstructor
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Getter
@Builder
public class SaleRegistRequest {
private User seller;
private Long orderHistoryId;
private DealState dealState;
private int discountRate;
private int sellPrice;
private int actualProfit;
private int catchPrice;
@DateTimeFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss")
private LocalDateTime endDate;
private String introduction;
private Boolean isAutoCatch;
private Boolean isCatch;
private Boolean isNego;
private LocalDate catchPriceStartDate;
private String accommodationName;
private Boolean isDeleted;
public Product toEntity(OrderHistory orderHistory,User loginUser) {
return Product.builder()
.seller(loginUser)
.orderHistory(orderHistory)
.dealState(DealState.ONSALE)
.discountRate(discountRate)
.sellPrice(sellPrice)
.actualProfit(actualProfit)
.catchPrice(catchPrice)
.endDate(endDate)
.introduction(introduction)
.isAutoCatch(isAutoCatch)
.isCatch(isCatch)
.isNego(isNego)
.catchPriceStartDate(catchPriceStartDate)
.accommodationName(orderHistory.getAccommodation().getName())
.isDeleted(false)
.build();
}
}
@Entity
@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class Product extends BaseTime {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private User seller;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "orderhistory_id")
private OrderHistory orderHistory;
@Enumerated(EnumType.STRING)
@Column(name = "deal_state")
private DealState dealState;
@Column(name = "discount_rate")
private int discountRate;
@Column(name = "sell_price")
private int sellPrice;
@Column(name = "actual_profit")
private int actualProfit;
@Column(name = "catch_price")
private int catchPrice;
@Column(name = "end_date")
private LocalDateTime endDate;
@Column(name = "introduction")
private String introduction;
@Column(name = "is_auto_catch")
private Boolean isAutoCatch;
@Column(name = "is_catch")
private Boolean isCatch;
@Column(name = "is_nego")
private Boolean isNego;
@Column(name = "catch_price_start_date")
private LocalDate catchPriceStartDate;
@Column(name = "accommodation_name")
private String accommodationName;
@Column(name = "is_deleted")
private Boolean isDeleted;
@OneToOne(mappedBy = "product", fetch = FetchType.LAZY)
private Review review;
}
상품 등록 dto에서 boolean 값을 받아와야하는 경우가 있었다.
위 entity 코드에서 보이는 isNego(네고 가능 여부), isDeleted(삭제 여부) 가 주인공이다. (isAutoCatch,isCatch도 포함)
먼저 코드와 다르게 처음에는 엔티티에서 boolean 타입으로 작성했었는데, 실제 값을 받아오는 것을 확인해보면 보내는 값과는 무관하게 무조건 false로 오게 되었다.
이유를 분석해보니,
Lombok의 @Getter 어노테이션을 사용하는 경우, boolean 타입에 붙는 prefix는 get이 아니라 is로 가져온다.
그렇기에 is+xxx로 변수명을 작성할 경우, 변수명의 is는 생략된 채 is(prefix) + xxx로 getter가 생성되는 것이다.
이를 확인하기 위해 기존에 Boolean으로 작성되어 있는 isNego 필드를 boolean 타입으로 변경한 후, delombok을 통해 getter를 살펴봤다.
deLombok 결과, isNego라는 getter 메서드가 생성된 것이 보인다.
위에 있는 Boolean 타입으로 생성된 변수(getIsCatch)의 경우
get(prefix) + IsCatch(변수명) 으로 getter가 생성된 반면,
boolean 타입으로 생성된 isNego 칼럼의 경우
is(prefix) + Nego(변수명에서 is 생략)으로 getter가 생성된다.
사실 엔티티만 boolean 타입이면 requestbody에서 isNego의 true데이터 받아오는게 큰 문제는 없는데,,
requestDto에서도 boolean 타입을 쓰면 문제가 된다.
내가 isNego라고 변수명을 작성했음에도 불구하고 lombok getter 특징 상 is가 boolean 값의 prefix가 되기 때문에 내가 작성한 변수명이 온전히 사용되지 않기 떄문!!!
즉, requestBody에서 isNego라는 이름에 저장된 값을 가져와도 isNego가 없다는 것으로 인식하는 결과가 나타내게된다...!
(isNego가 아닌 Nego만 볼 것이기 때문에...!)
아래 사진을 보면 requestBody에 isNego 값을 true로 설정하고 Post 요청을 보내봤으나, DB에는 false로 저장된 것을 확인할 수 있다.
이런 문제를 해결하기 위해...?
방법은 2가지가 있다.
1. Boolean 타입을 사용한다. Boolean 타입을 활용할 경우 Lombok getter 어노테이션이 getIsNego 처럼 get을 prefix로 붙여준다.
2. getter를 커스터마이징한다. (좀 귀찮고 코드가 길어지긴 한다)
참고문헌
[Springboot] RequestBody boolean 바인딩 에러
RequestBody로 boolean 타입을 true로 보냈는데 false로 DB에 저장되는 것을 발견했다. @Getter, @Setter 어노테이션을 사용하는 경우 boolean 타입에 붙는 prefix는 get이 아니라 is이기 때문에 @RequestBody에서 찾
velog.io
'Development > Java' 카테고리의 다른 글
객체지향 설계원칙 : SOLID 란? (3) | 2024.02.27 |
---|---|
객체 지향 프로그래밍이란?? 객체 지향의 4가지 특징 Feat.캡상추다 (2) | 2024.02.26 |
KakaoAPI를 활용해 위치기반 장소 검색 Java 애플리케이션을 개발해보자 (0) | 2023.09.04 |
KakaoAPI를 활용해 책을 검색하는 JAVA 애플리케이션을 만들어보자 (2) | 2023.08.31 |