@EqualsAndHashCode(callSuper = true)
Lombok 라이브러리에서 제공하는 기능으로
부모 클래스의 equals와 hashCode 메서드를 포함하여 자식 클래스의 해당 메서드를 생성하는 역할을 한다.
Lombok 의존성 추가
build.gradle
dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
}
사용 예제
PrivateRequestDto.java
import lombok.Builder;
import lombok.Data;
import org.springframework.web.reactive.function.server.ServerRequest;
@Data
public class PrivateRequestDto {
private String apiKey;
private String secretKey;
private String orderCurrency;
private String paymentCurrency;
@Builder
public PrivateRequestDto(String apiKey, String secretKey, String orderCurrency, String paymentCurrency) {
this.apiKey = apiKey;
this.secretKey = secretKey;
this.orderCurrency = orderCurrency;
this.paymentCurrency = paymentCurrency;
}
위와 같은 api request 값을 매핑하는 dto가 있을 때
apiKey와 secretKey는 다른 요청에서도 중복으로 필요한 컬럼이여서 ApiCredentialsDto로 분리하려 했다.
ApiCredentialsDto.java
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
public class ApiCredentialsDto {
private String apiKey;
private String secretKey;
public ApiCredentialsDto(String apiKey, String secretKey) {
this.apiKey = apiKey;
this.secretKey = secretKey;
}
}
그리고 처음 PrivateRequestDto를 아래와 같이 변경했다.
변경한 PrivateRequestDto.java
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.springframework.web.reactive.function.server.ServerRequest;
@Data
@EqualsAndHashCode(callSuper = true)
public class PrivateRequestDto extends ApiCredentialsDto {
private String orderCurrency;
private String paymentCurrency;
@Builder
public PrivateRequestDto(String apiKey, String secretKey, String orderCurrency, String paymentCurrency) {
super(apiKey, secretKey);
this.orderCurrency = orderCurrency;
this.paymentCurrency = paymentCurrency;
}
public static PrivateRequestDto fromRequest(ServerRequest request) {
return PrivateRequestDto.builder()
.apiKey(request.headers().firstHeader("api-key"))
.secretKey(request.headers().firstHeader("api-secret"))
.orderCurrency(request.queryParam("order-currency").orElse(""))
.paymentCurrency(request.queryParam("payment-currency").orElse(""))
.build();
}
}
이 때 @EqualsAndHashCode(callSuper = true) 어노테이션을 붙이는 이유는
상속받은 필드들까지 포함한 동등성 비교와 해시 코드를 생성하기 위함이다.
테스트를 해보면
import prj.blockchain.bithumb.dto.PrivateTradeRequestDto;
import java.util.HashSet;
import java.util.Set;
public class Test {
public static void main(String[] args) {
PrivateTradeRequestDto dto1 = PrivateTradeRequestDto.builder()
.apiKey("api-key-1")
.secretKey("secret-key-1")
.orderCurrency("BTC")
.paymentCurrency("USD")
.build();
PrivateTradeRequestDto dto2 = PrivateTradeRequestDto.builder()
.apiKey("api-key-1")
.secretKey("secret-key-1")
.orderCurrency("BTC")
.paymentCurrency("USD")
.build();
Set<PrivateTradeRequestDto> set = new HashSet<>();
set.add(dto1);
System.out.println("Contains dto2: " + set.contains(dto2)); // 예상 출력: true, 실제 출력: true
}
}
위의 코드에서는 dto1과 dto2가 동일한 apiKey와 secretKey 값을 가지고 있지만,
hashCode와 equals 메서드가 부모 클래스의 필드를 포함하지 않기 때문에 HashSet은 두 객체를 서로 다른 객체로 인식한다.
고로 예상 되는 출력값은 true였지만 실제론 false 다른 객체라고 나온다.
결론
- @EqualsAndHashCode(callSuper = true)를 사용하면
부모 클래스의 필드들까지 포함하여 equals와 hashCode 메서드를 생성하므로, 상속 구조에서도 올바른 동등성 비교가 가능하다. - 이를 통해 HashSet과 같은 자료구조에서 객체를 정확하게 비교하고, 예상치 못한 동작을 방지할 수 있다.
'PROGRAMMING > SPRING' 카테고리의 다른 글
| [SPRING] AOP를 활용한 로그 중앙화 (feat.@Aspect, @Pointcut) (0) | 2024.08.17 |
|---|---|
| [SPRING] Lombok @Log4j2 log4j-slf4j-impl cannot be present with log4j-to-slf4j 에러 (gradle) (0) | 2024.06.28 |
| [SPRING] Spring boot 3.x에서 QueryDSL 설정 (0) | 2024.05.20 |
| [SPRING] static field에 @Value annotation 적용? (0) | 2024.05.11 |
| [SWAGGER] 프로젝트 API 문서 자동화 (0) | 2022.01.25 |