티스토리 뷰
Item33에서는 type safe heterogeneous container pattern에 대해 알아보는데
Parameterized Type Key를 넣는 게 과연 무슨 의미인가 궁금해졌다
너무 복잡한데 비해 실제로 만들어 본 상황이 거의 없으니 이걸 왜 쓰지? 라는 생각이 들었다
읽다보니 동적 형 변환에도 타입 안전성을 보장하기 위함이고 jackson과 같은 라이브러리에서 요긴하게 쓰고 있는 것 같다
기본적인 것들은 모두 이해했다고 가정하고 책의 예시에서 등장한 Favorites 클래스의 두 번째 제약에 대해 더 알아보려 한다
List<String>과 같은 제네릭 타입은 실체화 불가 타입이다
즉 List<String>.class 와 같이 쓸 수 없고 타입 안전 이종 컨테이너를 만들더라도 제네릭 타입은 사용 불가하다는 얘기다
이 제약을 해결하려는 것이 바로 슈퍼 타입 토큰이다
닐 개프터의 블로그에 올라온 예시다, 이해가 되는가? 난 안 된다
이해가 될 때까지 찾아가보자
같은 형태로 작성된 코드를 스프링이 제공해준다
처음 들러야 할 곳은 org.springframework.core의 ParameterizedTypeReference<T>다
protected로 막아둔 생성자의 두 번째 줄에서 getGenericSuperclass()를 호출하는 곳을 찍어보는 걸로 시작하자
나도 전부 이해하지 못하고 의식의 흐름 기법으로 찾고 이해한 내용까지다
이 내용은 간략하게 정리했기 때문에 내가 찾아본 과정까지는 맨 아래에 정리해두었다
간단한 요약본은 아래와 같다
제일 먼저 ParameterizedTypeReference에서 getGenericSuperclass()를 호출한다
이 과정에서 SignatureParser를 통해 시그니처 분석 후 제네릭 정보를 ClassRepository에 넘기고
얘에서 ParameterizedType을 땡겨오는 것이다
ClassRepository에서 TypeParameters를 가져오는 과정은
ClassRepository의 상위 클래스이자 추상 클래스인 GenericDeclRepository에서 getTypeParameters()로 수행된다
이 과정에서 Reifier 클래스를 이용하는데 이름만 봐도 실체화 시켜주는 놈인 것을 알 수 있다
스프링에서는 SyntheticParameterizedType을 사용하고 getActualTypeArguments()를 호출한다
Type 배열로 가져오는데 반드시 결과는 하나여야 하고 이 과정에서 가져온 Type은 제네릭 타입이고
ParameterizedType의 type 인스턴스 필드에 할당된다
요런 방식으로 제네릭 타입을 넘겨도 실체화된 타입으로 저장해놓고 꺼내와서 형 변환해주는 것이다
List<String>을 넘겨도 ParameterizedTypeReference에서 실체화 시킨 타입으로 가져와서 형 변환 후 우리에게 건네준다
그래서 objectMapper.readValue(값, 타입) 형식으로 입력해도 야무지게 형 변환돼서 결과를 얻을 수 있는 것!
심연 가는 길
그냥 흐름만 보기 위해 따라가 봤을 뿐.. 굳이 추천하지는 않는다
그래도 가고 싶다면 내 기준으로 가본 거라 ParameterizedTypeReference<T>를 찾아 직접 가보는 것이 낫겠다
Type type = parameterizedTypeReferenceSubclass.getGenericSuperclass();
java.lang.Class로 오게 되는데 getGenericInfo()에서
네이티브 메서드 getGenericSignature0()를 호출해 제네릭 정보를 얻는다
ClassRepository info = getGenericInfo();
다음 sun.reflect.generics.repository.ClassRepository 찍고 가보면
문자열의 raw signature를 받아서 ClassRepository를 생성해 반환하는데
생성자에서는 super를 호출해 올라간다
parse는 abstract 메서드로 따라서 ClassRepository의 parse로 반환된 결과를 tree에 할당한다
genericInfo = ClassRepository.make(signature, getFactory());
return SignatureParser.make().parseClassSig(s);
여기까지 시그니처 분석 후 아래부터는 실체화시켜 가져오는 과정이다
return info.getSuperclass();
'Java > Effective Java' 카테고리의 다른 글
[Item35] ordinal 금지 (0) | 2022.03.15 |
---|---|
[Item34] 항상 enum만 사용할 순 없으니 (0) | 2022.03.14 |
[Item32] varargs는 신중히 (0) | 2022.03.11 |
[Item31] 한정적 와일드카드 뭐시기?? (0) | 2022.03.10 |
[Item30] 따봉 제네릭스 (0) | 2022.03.09 |