실전예제6 - 값 타입 매핑
Address라는 값 타입 컬렉션을 만들어서 추가해보자. Delivery와 Member가 사용하고 있다.
package jpashop.domain;
import jakarta.persistence.Embeddable;
import lombok.Getter;
import java.util.Objects;
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
public String getCity() {
return city;
}
public String getStreet() {
return street;
}
public String getZipcode() {
return zipcode;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Address address)) return false;
return Objects.equals(city, address.city) && Objects.equals(street, address.street) && Objects.equals(zipcode, address.zipcode);
}
@Override
public int hashCode() {
return Objects.hash(city, street, zipcode);
}
}
위는 인텔리제이의 도움을 받아 생성한 게터와 equals()오버라이딩, 그리고 hashCode()오버라이딩한 값 타입이다. equals()의 오버라이딩 메서드에서 눈여겨 볼 것 들이 있다.
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Address address)) return false;
return Objects.equals(city, address.city) && Objects.equals(street, address.street) && Objects.equals(zipcode, address.zipcode);
}
우선 instanceof연산자를 이용해 1차적으로 걸러주고 있다. 이건 인텔리제이가 프록시 객체가 인자로 들어오는 상황을 대비해 알아서 instanceof연산자를 사용해준 것이다. 왜 instanceof를 써야하는지 지난 시간 배웠다.
⚠️ 반면 인텔리제이가 잡아주지 못한 부분도 있다.
return Objects.equals(city, address.city) && Objects.equals(street, address.street) && Objects.equals(zipcode, address.zipcode);
equals를 비교하기 위해서 필드값 자체를 비교하고 있다. 그런데 만약 프록시객체가 equals의 대상이었다면 필드값 자체는 텅텅비어있어서 제대로된 equals()가 일어나지 않는다. 이 경우에는 반드시 getter를 이용한 비교로 바꿔줘야 한다.
return Objects.equals(getCity(), address.getCity()) && Objects.equals(getStreet(), address.getStreet()) && Objects.equals(getZipcode(), address.getZipcode());
이렇게 getter를 이용해 비교하면 프록시더라도 getter가 원본 필드를 참조하도록 되어있어 제대로된 equals()비교가 된다.
이는 hashCode()도 마찬가지이다.