Backend/개발

[Spring Boot] List의 null값 처리하기2 - 일급컬렉션, @RequestBody

지수쓰 2022. 5. 15. 16:04
반응형

컨트롤러에서 List로 된 요청을 받아오는 과정에서, null이나 empty List가 왔을 때 처리하는 방법에 대한 글이다.

이전에 올렸던 [Spring Boot]List의 null 값 처리하기1 - CustomConverter로 @RequestParam 에서 좀 애매한 부분이 있었는데, 다른 해결 방안이 될 수 있을 것 같아서 적어본다.

이전 글은 param, List <String>이고 이번 글은 body, List <DtoObject>라 조금 다를 수도 있지만 일단 기록용 ㅎㅎ;;

 

요청으로 받을 DTO를 json파일로 받아와 게임을 등록하는 API가 있었는데, 이 json파일을 리스트로 한번에 받아올 수 있게 하려고 한다.

    public ResponseEntity<RiotReplayDtos> saveGameRecords(
            @RequestBody List<RiotReplayDto> riotReplayDtos) throws IOException {
        if (riotReplayDtos.isEmpty()) throw new MayoException(ErrorCode.INVALID_INPUT_VALUE, "no replays");
		GameRecordDto gameRecordDto = gameRecordV2Service.registerGameRecord(riotReplayDto, mayoId);
        return ResponseEntity.ok(riotReplayDtos);
    }

원래는 이렇게 riotReplayDtos.isEmpty() 또는 riotReplayDtos == null  을 검증해줘야 한다.

 

최근에 컬렉션으로 된 필드 하나만 가지고 포장하는 일급컬렉션을 사용한 리팩터링을 진행해보았어서, 이렇게 컨트롤러에서 받아올 때도 일급 컬렉션을 사용할 수 있을까 싶어 적용해보았다.

    public ResponseEntity<RiotReplayDtos> saveGameRecords(
            @RequestBody @Valid RiotReplayDtos riotReplayDtos) throws IOException {
		GameRecordDto gameRecordDto = gameRecordV2Service.registerGameRecord(riotReplayDto, mayoId);
        return ResponseEntity.ok(riotReplayDtos);
    }
@JsonIgnoreProperties(ignoreUnknown = true)
@Getter
@ToString
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class RiotReplayDtos {

    @ApiModelProperty(value = "리플레이 json파일을 입력해주세요.")
    @NotEmpty(message = "리플레이 json파일을 입력해주세요.")
    private List<RiotReplayDto> riotReplayDtos;

    public RiotReplayDtos(List<RiotReplayDto> riotReplayDtos) {
        this.riotReplayDtos = riotReplayDtos;
    }

    public boolean isEmpty() {
        return riotReplayDtos.isEmpty();
    }
}

 

 

일급 컬렉션을 final로 생성해보려고 했는데 그건 잘 안돼서 일단은 불변성은 처리하지 못했지만, @NotEmpty 조건을 걸어주고 @Valid로 설정해서 테스트를 해보았다.

 

성공 테스트

    @Test
    @DisplayName("게임 등록 -  여러게임 한번에 등록 ")
    void saveGameRecorsTest() throws Exception {
        ObjectMapper mapper = new ObjectMapper();
        RiotReplayDto riotReplayDto = RiotReplayDto.builder()
                .gameId(12L)
                .gameType(GameTypeCode.REGULAR)
                .gameCreationTime(123L)
                .gameLength(123L)
                .statsJson(null)
                .build();
        Map<String, Object> map = new HashMap<>();
        map.put("riotReplayDtos", Lists.newArrayList(riotReplayDto, riotReplayDto));
        MvcResult mvcResult = mvc.perform(post("/api/game/records")
                .contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(mapper.writeValueAsString(map)))
                .andDo(print())
                .andExpect(status().isOk())
                .andReturn();
    }
MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Content-Type:"application/json;charset=UTF-8"]
     Content type = application/json;charset=UTF-8
             Body = {"riotReplayDtos":[{"gameId":12,"gameCreationTime":123,"gameType":"REGULAR","gameLength":123,"statsJson":null},{"gameId":12,"gameCreationTime":123,"gameType":"REGULAR","gameLength":123,"statsJson":null}],"empty":false}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

실패 테스트

@Test
    @DisplayName("게임 등록 - null일 경우 여러게임 한번에 등록 실패 ")
    void saveGameRecorsNullTest() throws Exception {
        ObjectMapper mapper = new ObjectMapper();
       Map<String, Object> map = new HashMap<>();
        map.put("riotReplayDtos", null);
        MvcResult mvcResult = mvc.perform(post("/api/game/records")
                .contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(mapper.writeValueAsString(map)))
                .andDo(print())
                .andExpect(status().isBadRequest())
                .andReturn();
    }

    @Test
    @DisplayName("게임 등록 - empty일 경우 여러게임 한번에 등록 실패 ")
    void saveGameRecorsEmptyTest() throws Exception {
        ObjectMapper mapper = new ObjectMapper();
       Map<String, Object> map = new HashMap<>();
        map.put("riotReplayDtos", Lists.newArrayList());
        MvcResult mvcResult = mvc.perform(post("/api/game/records")
                .contentType(MediaType.APPLICATION_JSON_VALUE)
                .content(mapper.writeValueAsString(map)))
                .andDo(print())
                .andExpect(status().isBadRequest())
                .andReturn();
    }
MockHttpServletResponse:
           Status = 400
    Error message = null
          Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", Content-Type:"application/json;charset=UTF-8"]
     Content type = application/json;charset=UTF-8
             Body = {"status":400,"code":"C001","message":"Invalid input value","errors":[{"field":"riotReplayDtos","value":"null","message":"리플레이 json파일을 입력해주세요."}]}
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

 

 

일급 컬렉션을 이용해서 유효성 검증을 좀 더 편리하게 할 수 있을 것 같다!