jpa에서 Entity 로딩시, Embedded Type이 Null인 현상 (인스턴스화 되지 않는 현상)에 대해서 알아보도록 하겠습니다.
Jpa Entity로딩 시 Embedded Type Null Error
1. 문제환경
UserEntity
name = "user") (
access = AccessLevel.PROTECTED) (
public class UserEntity {
private Long userId;
private String userName;
private Address address;
public UserEntity(String userName, Address address) {
this.userName = userName;
this.address = address;
}
}
문제 상황을 다시 재연하기위해 사용될 UserEntity는 위와 같습니다. userId, userName, address(Embedded Type)
을 가지고 있습니다.
UserAddressService
public class UserAddressService {
private final UserRepository userRepository;
public String getUserFlattenAddress(Long userId) {
UserEntity userEntity = userRepository.findById(userId).get();
Address address = userEntity.getAddress();
return address.getAddress() + address.getZipCode();
}
}
address 서비스는 UserEntity의 Adress Type안의 Field값들을 모두 합쳐 보여주는 간단한 메소드를 가지고 있습니다.
UserController
x
public class UserController {
private final UserRegisterService userRegisterService;
private final UserRepository userRepository;
// User 등록 API
"/users") (
public long register( UserRegisterRequest request) {
System.out.println(request.toString());
return userRegisterService.saveUser(request);
}
private final UserAddressService addressService;
// User Address 조회 API
"/users/{userId}/address") (
public String getUserAddress( ("userId") Long userId) {
return addressService.getUserFlattenAddress(userId);
}
// User Address가 Null인지 확인 하는 메소드
"/users") (
public void getUser() {
UserEntity user = userRepository.findById(1L).get();
if(user.getAddress() == null)
System.out.println("address is null !!");
else
System.out.println("exist !!!");
}
}
UserAPI는 다음의 기능을 제공합니다.
- user를 등록하는 API
- user Adress를 조회하는 API
- user Adress가 nulld인지 확인하는 API
2. 문제상황
여느 때와 같이, jpa를 이용해 프로그래밍을 하고 있었습니다. 근데, Controller에서 Entity를 로딩한후, Entity의 Embedded 타입의 값 안의 데이터를 참조하려고 하는 찰나 null point exception이 나타났습니다.
Adress가 null인지 확인 하는 API를 이용해 보면, 확실하게 Address가 null임을 알 수 있습니다.
3. 원인
https://hibernate.atlassian.net/browse/HHH-7610
위의 hibernate 문서를 보시면 이슈에 대한 원인이 나타나있습니다.
When all of the values in an @Embedded object are NULL, Hibernate sets the field in the parent object to null.
원인은 Hibernate의 동작에 숨어있는데요, Entity를 로딩하는 과정에서 Embedded Type에 담겨있는 모든 Field의 값이 null인 경우, 해당 Embedded Type은 인스턴스화가 되지 않는다고 합니다.
4. 해결방법
Getter를 이용
public Address getAddress() {
return this.address == null ? new Address() : this.address;
}
위와 같이 Embedded Type의 Getter를 별도로 구현하여, null인 경우를 체크하여 새로운 객체를 생성하여 반환하는 방법이 있습니다.
존재한다고 나타나는것을 볼 수 있습니다.
문제점
하지만, 이러한 에러가 발생하는 것을 모르고 사용하는 개발자는 내부의 값이 모두 비어있으므로, 당황하거나, 비어있는것을 확인하지 않는경우 다른 곳에서 문제가 발생할 확률이 존재합니다.
원초적 해결
이 에러를 해결하기 위해서는, Entity의 EmbeddedType을 저장할때 적절한 검증을 통해 모든 필드 값이 null이 되지 않도록 하면 됩니다.