오늘의 목표
parameter binding함수 리팩토링, HandlerMethodArgumentResolver 하나 더 만들기
어제 parameter binding하는 함수를 만들었는데요. 리팩토링은 진행은 하지 못하였습니다. 그래서 오늘 좀 더 깔끔하게 어떻게 구현할 수 있을까 고민하다가 다음과 같이 메서드를 분리하였습니다.
public Object[] bind(Method method, MessageDto messageDto) throws Exception {
Object[] args = new Object[method.getParameterCount()];
Class<?>[] types = method.getParameterTypes();
for (int i = 0; i < args.length; i++) {
args[i] = getInstance(messageDto, types[i]);
}
return args;
}
private Object getInstance(MessageDto messageDto, Class<?> type) throws Exception {
for (HandlerMethodArgumentResolver methodArgumentResolver : methodArgumentResolvers) {
if (methodArgumentResolver.supportsParameter(type)) {
return methodArgumentResolver.resolveArgument(messageDto);
}
}
return type.newInstance();
}
처음엔 Stream API를 사용하여 구현해볼까 고민도 했었는데요. getInstance() 메서드의 경우는 return값을 처리하는데 곤란한 점이 있었습니다. 만약 filter로 걸러내 찾으면 그것을 찾으면 그것을 리턴하면 되지만 없다면 Optional 객체를 이용하여 type.newInstance()
을 리턴해줘야 하는데 마땅한 메서드가 없더라구요. orElseGet()
은 HandlerMethodArgumentResolver
타입으로 캐스팅을 해줘야 하는데 이러면 객체 타입이 바뀌게 되니까요.
그리고 추가적으로 GameRoom
타입을 파라미터로 가질 때 WebSocketSession
의 값을 이용하여 파라미터 바인딩하는 HandlerMethodArgumentResolver도 만들었습니다. 하지만 여기엔 하나의 문제가 있었는데요. GameRoom
객체를 가져오기 위해선 GameRoomRepository
가 필요하다는 것입니다. HandlerMethodArgumentResolver 들에 대해 bean등록 필요성을 못 느꼈었는데(ParameterBinder가 빈등록 되어 HandlerMethodArgumentResolver들이 초기에 싱글턴 객체로 세팅되어 리스트에 넣어지기 때문에) GameRoomRepository
을 가져오기 위해 빈을 등록할 필요성을 느꼈습니다. 클래스가 빈으로 등록되어야 @Autowired
를 사용할 수 있기 때문입니다. GameRoomRepository
도 빈이기 때문에 같은 빈으로 만드는 것이 코드상 더 깔끔하고 메모리 효율도 좋다고 생각했습니다. 어차피 둘다 상태값은 가지지 않기 때문입니다.
@Component
public class GameRoomHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
@Autowired
private GameRoomRepository gameRoomRepository;
@Override
public boolean supportsParameter(Class<?> parameterType) {
return parameterType.equals(GameRoom.class);
}
@Override
public Object resolveArgument(MessageDto messageDto) {
WebSocketSession webSocketSession = messageDto.getWebSocketSession();
String id = WebSocketSessionUtils.getGameRoomIdFromSocket(webSocketSession);
return gameRoomRepository.getGameRoom(id);
}
}
따라서 GameRoomHandlerMethodArgumentResolver
도 빈으로 등록을 하고 이 덕분에 ParameterBinder
에선 더이상 객체를 생성해주지 않아도 되게 되었습니다. 빈 컨테이너를 통해 관리되기 때문입니다. 빈으로 등록하는 덕분에 인스턴스 변수 선언이 이렇게 바뀌었네요!
private final List<HandlerMethodArgumentResolver> methodArgumentResolvers = new ArrayList<>();
@Autowired
private UserHandlerMethodArgumentResolver userHandlerMethodArgumentResolver;
@Autowired
private GameRoomHandlerMethodArgumentResolver gameRoomHandlerMethodArgumentResolver;
public ParameterBinder() {
methodArgumentResolvers.add(new UserHandlerMethodArgumentResolver());
methodArgumentResolvers.add(new GameRoomHandlerMethodArgumentResolver());
}
기존에는 static 변수로 List를 선언해 클래스 로딩 때 작업해놓았습니다. 하지만 이젠 스프링 빈으로 되어 싱글턴 객체로서 빈 컨테이너의 관리대상이 되었습니다.
이때까지 WebSocketSession
과 관련된 테스트를 할 때 이 안의 값을 제대로 있다고 생각하고 데이터를 미리 만들어놓고 테스트를 진행하였습니다. 하지만 제대로 된 테스트는 아니었죠. 그래서 검색해보니 Mockito 프레임워크를 통해 WebSocketSession
도 테스트할 수 있다는 것을 알게되었습니다. 내일부터는 Mockito 프레임워크를 사용하여 제대로 된 테스트케이스를 작성할 수 있도록 노력해야겠습니다.
'TIL' 카테고리의 다른 글
Todays' Dev Notes(2018-03-16) (0) | 2019.03.16 |
---|---|
Todays' Dev Notes(2018-03-15) (0) | 2019.03.16 |
Today's Dev Notes(2019-03-10) (0) | 2019.03.11 |
Today's Dev Notes(2019-03-09) (0) | 2019.03.10 |
Intellij에서 디버깅 사용하기 (0) | 2019.02.24 |