티스토리 뷰

Java/Effective Java

[Item33] Super Type Tokens

ryumodern 2022. 3. 13. 15:52

Item33에서는 type safe heterogeneous container pattern에 대해 알아보는데

Parameterized Type Key를 넣는 게 과연 무슨 의미인가 궁금해졌다

너무 복잡한데 비해 실제로 만들어 본 상황이 거의 없으니 이걸 왜 쓰지? 라는 생각이 들었다

읽다보니 동적 형 변환에도 타입 안전성을 보장하기 위함이고 jackson과 같은 라이브러리에서 요긴하게 쓰고 있는 것 같다

기본적인 것들은 모두 이해했다고 가정하고 책의 예시에서 등장한 Favorites 클래스의 두 번째 제약에 대해 더 알아보려 한다

 

List<String>과 같은 제네릭 타입은 실체화 불가 타입이다

즉 List<String>.class 와 같이 쓸 수 없고 타입 안전 이종 컨테이너를 만들더라도 제네릭 타입은 사용 불가하다는 얘기다

이 제약을 해결하려는 것이 바로 슈퍼 타입 토큰이다

 

http://gafter.blogspot.com/2006/12/super-type-tokens.html

 

닐 개프터의 블로그에 올라온 예시다, 이해가 되는가? 난 안 된다

이해가 될 때까지 찾아가보자

같은 형태로 작성된 코드를 스프링이 제공해준다

처음 들러야 할 곳은 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());

ClassRepository.make
ClassRepository.constructor
AbstractRepository.constructor
ClassRepository.parse

 

return SignatureParser.make().parseClassSig(s);

SignatureParser.parseClassSig

 

 

여기까지 시그니처 분석 후 아래부터는 실체화시켜 가져오는 과정이다

return info.getSuperclass();

ClassRepository.getSuperClass
Reifier.visitClassTypeSignature
ParmeterizedTypeImpl.make

'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
댓글
링크
글 보관함
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
Total
Today
Yesterday