최근에 새로 자바/스프링을 공부하는 친구들에게 질문을 받았는데, 문득 어? 잘 모르겠는데 싶어서 테스트해보았다.
과연 @RequestBody에 null 값을 받게 되었을 때, wrapper type에서는 null로 매핑되겠지만,
primitive type에서는 NPE가 발생할까? default value인 0이 매핑될까?
1 2 3 4 5 6 7 8 9 10 11 12 13 |
@RestController public class HelloWorldController { @PostMapping("/test") public void test(@Valid @RequestBody TestDto testDto) { System.out.println(">>>" + testDto); } @Data private static class TestDto { private long number; private Long number2; } } |
결과를 확인해보니,
1 2 3 4 5 6 7 8 9 |
POST http://localhost:8070/test Content-Type: application/json { "number": null, "number2": null } >>> HelloWorldController.TestDto(number=0, number2=null) |
primitive type에서는 default value인 0으로 매핑되고, wrapper type에서는 null로 매핑된다.
아마 long, boolean 등의 다른 타입들도 마찬가지일 것이다.
스프링에서는 모든 파라미터는 String 문자열로 일단 받게 된다.
그 이후에 Type Casting을 하게 되는데, 아마 primitive type인 경우 null은 0으로 매핑하나보다.
이것도 찾아봤다. 뭔가 요즘에는 오픈소스로 모든 것이 오픈되어 있어서 편한 점들이 있다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public abstract class ServletRequestUtils { @Nullable public static Integer getIntParameter(ServletRequest request, String name) throws ServletRequestBindingException { if (request.getParameter(name) == null) { return null; } return getRequiredIntParameter(request, name); } public static int getIntParameter(ServletRequest request, String name, int defaultVal) { if (request.getParameter(name) == null) { return defaultVal; } try { return getRequiredIntParameter(request, name); } catch (ServletRequestBindingException ex) { return defaultVal; } } } |
그렇다면 그동안 @NotNull
은 primitive type에 쓸 수 없다고 생각했었는데, 혹시 쓸 수 있을까?
primitive type의 경우에 @NotNull
을 적용해볼 수 있을까? 당연히 테스트로 확인해보았다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@RestController public class HelloWorldController { @PostMapping("/test") public void test(@Valid @RequestBody TestDto testDto) { System.out.println(">>>" + testDto); } @Data private static class TestDto { @NotNull private long number; private Long number2; } } |
결과를 확인해보니,
1 2 3 4 5 6 7 8 9 |
POST http://localhost:8070/test Content-Type: application/json { "number": null, "number2": null } >>> HelloWorldController.TestDto(number=0, number2=null) |
wrapper type인 number2는 당연히 @NotNull
이 적용되어 오류가 발생한다.
하지만 primitive type인 number는 (이미 예전에 알고 있던 것처럼) @NotNull
이 적용되지 않는다.
Parameter Binding하는 순서를 찾아보면 확실하겠지만 (귀찮아서 그냥 대충 직관으로 때운다)
아마도 Request Parameter를 String으로 가져오고, Type Casting을 한 이후에 Validator가 동작하는 것 같다.
그러면 primitive type은 이미 default value인 0이 셋팅되어 있어서 @NotNull
validator가 동작하지 않는다.