본문 바로가기
Java & Kotlin

Generic 타입 추론시 주의할 점! (super type token 문제)

by 향로 (기억보단 기록을) 2016. 7. 20.
반응형

요즘 박재성(a.k.a자바지기)님의 강의를 들으며 부쩍 TDD를 사용하려고 노력중이다.

그래서 회사일을 하면서도 최대한 테스트 코드를 적용중이다.

진행 도중 기존 코드에서 인자값으로 받는 API 주소와 리턴타입만 다른 여러 메소드들이 있어 이를 리팩토링 하는 과정에서 테스트 코드를 작성하다가 이상함을 발견하였다. 의도한 바와 다르게 데이터 형변환이 되는 것이다.


회사 코드를 직접 올린순 없어서 대충 비슷하게 코드를 작성해 보았다. 블로그에는 사진으로 코드를 설명하겠다.

(자세한 코드는 Github에 올려놓았다.)


아래와 같은 json 데이터가 있다고 가정하자.


위 데이터를 받아서 처리 하기 위해 2개의 POJO를 만들었다.

 

그리고 이를 시험할 테스트 코드는 아래와 같다.


보다시피 DataResponse<Book>이냐 DataResponse<다른 타입의 POJO> 냐의 차이라서 당연히 Book 자리를 제네릭 T가 들어가야할 자리라고 생각하여 코드를 작성하였는데..... 테스크 코드가 실패하는것이였다.

으잉? 왜 실패하는지 궁금하여 debug 모드로 전환하여 확인해보았다.

실패의 원인은 놀랍게도 result의 타입이 LinkedHashMap으로 되어있는 것이다



이게 좀 이해가 안되서 여러방법들을 다 사용해보았는데 내가 원하는대로 Book으로 형변환이 되지 않았다.

고민고민하다가 부끄럽지만 dosaTv 슬랙에 질문을 올렸다. 채널의 Jace Shim 님과 이것저것 얘기하면서도 뭔가 풀리지가 않아 고민고민 하고 있었는데!! 바로 그때!! 

토비님(토비의 스프링의 그 토비님이 맞으십니다!!) 께서 아주아주 친절하게 그 원인과 해결책을 알려주셨다!!!

영광입니다 ㅠㅠㅠ



즉, 제네릭은 소거자(effective java 번역에선 소거자 라고 표현하더라 원문에선 erasure)에 의해 구현되어 컴파일시에만 자신의 타입 제약을 지키게 하고 런타임시에는 자신의 타입정보를 소거해버린다. 이로인해 런타임시에 기존의 코드로는 T 타입이 뭔지 알수없어서 Object로 판정 후 json 데이터의 여러 속성들을 보고 Map으로 추론해버려서 형변환을 시킨것이다.

이를 해결하려면 컴파일시에 어떤 타입이 될지 명시해주면 된다. 


아래는 해결한 코드다


사실 요즘 리우 올림픽이라는 아주아주 빅 이벤트가 코앞에 다가와서 일정 압박이 장난아니다.

그래서 기존에 익숙하지 않은 테스트코드 작성 & 제네릭을 사용해볼까 말까 고민이 정말 많았다.

망설인 이유는 당연히 일정을 못지킬까봐이긴 한데 (실제로 위 테스트 코드때문에 반나절 넘게 사용했었다. 개발 진행에 크게 많은 부분을 차지하지도 않는 부분인데 말이다)

그래도 해보길 잘했다.

거의 자정이 다되서 토비님이 답변주신것 보고 어서빨리 회사가서 테스트코드 수정해보고 싶다는 생각밖에 없었다.

배우는 맛이 뭔지 하루하루 느끼고 있다. 



반응형