@RequestParam 사용 시 Null에 대한 고민 정리
RequestParam 애노테이션에서 required = false 인 경우, 값이 없을 때 null 로 채워진다.
RequestParamMethodArgumentResolver 에서 request.getParameterValues(name) 가 null 이고 결국 리턴되는 arg는 null 이 된다.
public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver implements UriComponentsContributor {
@Nullable
protected Object resolveName(String name, MethodParameter parameter, NativeWebRequest request) throws Exception {
...
if (arg == null) {
String[] paramValues = request.getParameterValues(name);
if (paramValues != null) {
arg = paramValues.length == 1 ? paramValues[0] : paramValues;
}
}
return arg;
}
cf) primitive type 이면 "cannot be translated into a null value due to being declared as a primitive type. Consider declaring it as object wrapper for the corresponding primitive type." 메세지와 함께 IllegalStateException 이 발생한다.
그런데 이전 글 에서 설명했듯이 request body를 여러번 읽는 경우 컨트롤러에서 POST + @RequestParam 일 때 form data 를 읽어오지 못하는 문제가 있다.
그러므로 ybs 변수값이 null 이라고 해도 추가적인 확인이 더 필요하다(POST + form data body 인지).
나는 그 작업을 아래와 같이 만들었는데 getYbs 메서드를 통해 정확한 ybs 값을 얻고 기존에 있는 ybs 변수를 재활용 했다(이후 프로세스 호환을 위해).
@RequestMapping(value = "/test10")
public String test(
HttpServletRequest request,
@RequestParam(value = "ybs", required = false) String ybs) {
ybs = getYbs(request, ybs);
return "hello";
}
private String getYbs(HttpServletRequest request, String ybs) {
if (isNotBlank(ybs)) {
return ybs;
}
if ("POST".equalsIgnoreCase(request.getMethod()) &&
request.getContentType().equals("application/x-www-form-urlencoded") &&
request.getContentLength() > 0 &&
isBlank(request.getQueryString())
) {
// body 를 얻고 ybs 값 파싱 해서 리턴
// 방어로직에 걸리면 null 리턴
}
return null;
}
이전에 쓴 메서드 리턴에 대한 고민 글 에서도 한번 다뤘지만, 그동안 나는 메서드에서 null 리턴 보다는 예외나 Optional 리턴을 우선적으로 고려했다. 그런데 지금 같은 상황에서는 null 리턴이 더 자연스럽다고 생각한다. 그 이유는 RequestParamMethodArgumentResolver 에서 애당초 null을 리턴해주기 때문이고, 또 getYbs 메서드 결과를 ybs 변수에 다시 할당하기 때문이다. 물론 다른 변수를 쓸 수 있지만 오히려 그게 더 헷갈리게 한다고 생각한다.