자바와 코틀린의 메서드 시그니처 차이 해결하기

dojinyou·2023년 2월 12일
0

상황

토비의 스프링부트 강의 중 섹션 4. 독립 실행형 스프링 어플리케이션에서 자바 코드 구성 정보 사용 강의에서 AnnotationConfigWebApplicationContext를 익명 클래스로 상속받아 onRefresh()메서드를 재정의하여 사용합니다.

이때, 코틀린의 경우에는 setClassLoader(classLoader: ClassLoader)메서드를 재정의해야 한다고 IDE가 알려줍니다. 강의에서는 뜨지 않았던 이 함수를 왜 재정의 해야되는 지 알아보았습니다.

원인 파악

해당 함수의 선언이 어디에 되어 있는 지 우선 찾기 위해 AnnotationConfigWebApplicationContext의 상속구조를 확인해보았습니다.

AnnotationConfigWebApplicationContext의 상속 관계 다이어그램

위 상속 구조에서 보면 DefaultResourceLoadersetClassLoader메서드가 구현되어 있습니다. 그리고 ConfigurableWebApplicationContextsetClassLoader 메서드가 선언되어 있습니다.

여기서 차이점은 @Nullable이라는 어노테이션입니다. 이 어노테이션의 자바와 코틀린에서의 차이를 만들어내고 있습니다. 자바에서는 어노테이션과 무관하게 선언과 구현이 같은 메서드 시그니처를 가지게 됩니다. 하지만 코틀린에서는 @Nullable어노테이션을 타입에 추가하여 변환하기 때문에 메서드 시그니처의 구성요소 중 하나인 파라미터의 타입이 달라지게 됩니다. 결국 인터페이스의 선언이 구현되지 않게 되는 것이죠.

메서드 시그니처란? 메서드를 식별하기 위한 구성요소로 메서드의 이름과 파라미터의 타입(과 순서)으로 구성됩니다.

해결방안

nullable한 타입을 별도로 두는 것은 코틀린의 특성으로 코틀린 내부적으로는 해결할 수 없습니다. 자바에서 해결을 해야했습니다. java class로 AnnotationConfigWebApplicationContext를 상속받은 MyAnnotationConfigWebApplicationContext를 직접 구현하고 이를 이용하였습니다.

덧붙여

그렇다면 실제로 Kotlin에서 위 함수를 구현하는 건 문제를 해결할 수 없을까요?

네. 그렇습니다. 실제로 setClassLoader를 구현하더라도 JVM signature가 동일하게 되어 충돌이 발생합니다.

실제로 이렇게 두개의 분리된 함수가 필요하다면 @JvmName을 이용하여 signature를 다르게 만들어줄 수도 있지만 해당 경우에는 스프링의 코드를 이용하므로 이렇게 적용할 수 없었습니다.

  • 잘못 작성된 내용이 있다면 언제든지 댓글로 알려주시면 감사하겠습니다.
profile
더 좋은 세상을 만드는 데 기술로 기여하고 싶습니다

1개의 댓글

comment-user-thumbnail
2023년 9월 11일

감사합니다~ 덕분에 삽질하고 있던 부분 해결했어요!

답글 달기