Spring JPA에서 Controller에서 @RequestBody
를 통해 요청받은 DTO 객체에서 특정 필드의 값만 요청되었을 때 나머지 필드는 null
이기 때문에 특정 필드를 제외한 필드는 null로 변경되는 대참사가 벌어진다.
특정 필드만 바꾸는 방법은 없을까? 찾아보던 중 다음과 같은 답을 얻을 수 있었다.
@RequestMapping(value = "/rest/user", method = RequestMethod.PUT, produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ResponseEntity<?> updateUser(@RequestBody User user) {
User existing = userRepository.read(user.getId());
copyNonNullProperties(user, existing);
userRepository.save(existing);
// ...
}
public static void copyNonNullProperties(Object src, Object target) {
BeanUtils.copyProperties(src, target, getNullPropertyNames(src));
}
public static String[] getNullPropertyNames (Object source) {
final BeanWrapper src = new BeanWrapperImpl(source);
java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();
Set<String> emptyNames = new HashSet<String>();
for(java.beans.PropertyDescriptor pd : pds) {
Object srcValue = src.getPropertyValue(pd.getName());
if (srcValue == null) emptyNames.add(pd.getName());
}
String[] result = new String[emptyNames.size()];
return emptyNames.toArray(result);
}
위와 같이 Spring에서 제공하는 BeanUtils 클래스의 copyProperties() 메서드를 활용하면 DTO와 Entity를 파라미터로 받아 비교하여 null이면 기존 필드 값을 유지하고 null이 아닌 경우에만 필드 값을 변경하는 로직을 구현할 수 있다.