[자바, 코틀린] 어노테이션

어노테이션

어노테이션(annotation)(또는 주석)이란 소스 코드에 대한 메타데이터의 한 형태이다. 어노테이션이 제공하는 메타데이터는 애플리케이션에 일부로 포함되며 기존 코드의 실행에 직접적인 영향을 미치지는 않는다.

어노테이션 정의 시 @ 문자를 사용하여 컴파일러에게 해당 코드가 어노테이션임을 알려준다. 어노테이션은 이름이 있거나 없는 요소(element)를 포함할 수 있으며 이 경우 해당 요소에 대한 값을 지정한다. 요소를 포함하지 않을 수도 있다.

어노테이션은 클래스, 메서드, 변수, 파라미터 정의에 설정할 수 있으며, 컴파일 및 런타임 시에 해당 어노테이션이 사용 및 처리될 수 있다. 어노테이션을 사용하여 클래스, 메서드, 변수에 대한 메타데이터를 설정하고 이를 통해 프로그램 구현을 위한 부가적인 처리들을 할 수 있다.

어노테이션의 사용 유형은 다음과 같다.

  • 컴파일러에 대한 정보 제공: 컴파일러는 어노테이션을 사용하여 컴파일 시 발생 가능한 에러 및 경고를 감지하거나 무시할 수 있다.
  • 컴파일 타임, 개발 시 처리: 소프트웨어 도구(예: IDE)는 어노테이션을 사용하여 코드를 생성할 수 있다.
  • 런타임 처리: 어노테이션은 런타임에 사용될 수 있다.

컴파일 처리 어노테이션을 적용한다면 적용 대상에 대해 부가적인 소스 코드를 작성한 후 컴파일한다. 컴파일된 소스는 어노테이션 프로세서에 의해 실행된다.

런타임 처리 어노테이션을 적용한다면 런타임 시 적용 대상에 대한 어노테이션 메타데이터를 조회하고 해당 어노테이션이 적용된 클래스 및 메서드에 대한 부가적인 처리를 수행할 수 있다. 자바의 경우 리플렉션을 사용하여 클래스명을 통해 런타임 처리 어노테이션을 적용할 수 있으며 스프링에서는 spring-context 또는 spring-core 라이브러리를 통해 런타임 처리 어노테이션을 적용할 수 있다.

어노테이션의 사용 예는 다음과 같다.

  • 코드 검사 기능:
    • 변수 값 유효성 검사:
    • 애플리케이션 내부 동작 확인:
  • 코드 자동 생성 기능:


타입 어노테이션

자바 8 부터 어노테이션은 타입 사용(type use)에 적용될 수 있으며 이러한 어노테이션을 타입(type) 어노테이션이라고 한다. 코드 상에서 타입을 사용하는 모든 곳에서 타입 어노테이션을 사용할 수 있다.

  • 클래스의 인스턴스 생성 표현식
  • 타입 캐스팅
  • 인터페이스 구현문 (implements)
  • 예외 발생 선언문 (throws)

타입 어노테이션은 타입 확인 기능 개선을 위해 사용될 수 있다. 자바 8는 타입 검사 프레임워크를 제공하지 않지만, 컴파일러와 함께 사용되는 하나 이상의 플러그인 모듈로 구현된 타입 검사 프레임워크를 작성하거나 다운로드하여 사용할 수 있다.

어노테이션은 변수, 매개변수 및 반환값에 추가하여 메서드 반환 값, 전달된 매개변수, 로컬 변수 및 필드를 검사하는 메타데이터 태그로 추가된다. 주석을 코드 검사 도구와 함께 사용하면 null 포인터 예외 및 리소스 유형 충돌과 같은 문제를 감지하는 데 도움이 될 수 있다.

타입 어노테이션은 NullPointerException 런타임 예외 발생을 피하고 값이 null일 수 있는지에 대한 여부를 강제 적용하는 데 유용하다. 컴퍼일러는 변수에 null이 할당될 수 없게 하거나 할당될 수 있게 하거나 null일 가능성이 있는 경우 null인지 먼저 검사하도록 한다. 주어진 변수, 매개변수 또는 반환 값의 null 가능성 여부를 확인하려면 @Nullable@NonNull 어노테이션을 추가한다. 이러한 어노테이션을 nullness 어노테이션이라고 한다. @Nullable 어노테이션은 null이 될 수 있는 변수, 파라미터 또는 반환값을 나타내며, @NonNullnull이 될 수 없는 변수, 파라미터 또는 반환값을 나타낸다.

예를 들어, null 값을 포함하는 로컬 변수가 특정 메서드에 파라미터로서 전달되고 메서드의 @NonNull 어노테이션이 메서드의 파라미터에 연결되어 있는 경우 코드를 빌드하면 경고가 생성된다. 또한 결과가 null인지를 먼저 확인하지 않고 @Nullable로 표시된 메서드의 결과를 참조하려고 하면 경고가 생성된다. 메서드를 사용할 때마다 명시적으로 null 여부를 확인해야 할 경우에는 메서드의 반환값에 @Nullable만 사용한다.

null 검사를 위한 타입 어노테이션은 코틀린에서는 비교적 덜 유용하다. 코틀린에서는 널 참조를 허용할 수도, 금지할 수도 있다. 여러 연산자들을 사용하여 NullPointerException 런타임 예외 발생을 막을 수 있을 뿐만 아니라 코틀린 컴파일러는 널 값을 가질 수 없는 변수에 널 값이 할당될 수 있는 코드에 대해 컴파일 시간에 잠재적 에러를 발생시킨다.


어노테이션 정의

어노테이션 타입은 다음과 같이 정의한다.

@interface CustomAnnotation {
   타입 요소명();
   터입 요소명() default 기본값; 
}

어노테이션 타입 정의 시 interface 키워드 앞에 기호 @ (at)을 추가한다. 어노테이션 타입은 인터페이스의 한 형태이다.

어노테이션 정의 본문에는 어노테이션 타입 요소 선언이 포함되어 있으며 이는 메서드 선언과 비슷하다. 요소 선언 시 선택적으로 기본값을 정의할 수 있다.


어노테이션 프로세서

어노테이션 프로세서(annotation processor)란 컴파일 시간에 어노테이션이 지정된 대상에 대해 소스를 추가하여 새로운 파일로 컴파일하는 프로그램 또는 API이다. 예로 IDE는 어노테이션 프로세서를 사용하여 어노테이션이 지정된 소스 코드(클래스 또는 매서드)에 대해 추가적인 소스 코드를 추가하여 컴파일을 수행한다.


빌드 시 어노테이션 프로세서 컴파일 설정

모듈에 어노테이션 프로세서 의존성 항목이 있는 경우 해당 의존성 항목을 추가하려면 자바의 경우 annotationProcessor 의존성 항목 구성이 필요하며, 코틀린의 경우 kapt 또는 ksp 의존성 항목 구성이 필요하다.


어노테이션 프로세서 예

롬복(lombock) 라이브러리는 어노테이션 프로세서를 사용하는 대표적인 어노테이션의 예이다. 롬복이 제공하는 다양한 어노테이션을 클래스에 적용하여 클래스가 가지고 있는 프로퍼티에 대한 추가적인 메서드를 자동 생성할 수 있다.

원본 클래스 파일에 코드를 추가적으로 생성한 후 빌드를 통해 소스를 컴파일하고, 컴파일된 소스를 적절한 클래스패스에 추가하면 코드 상에서 부가적인 기능이 적용된 클래스를 참조하여 사용할 수 있다.


코틀린의 어노테이션 프로세서

코틀린에서 어노테이션 프로세서는 kapt(kotlin annotation processing tool)라는 컴파일러 플러그인을 통해 지원된다. kapt는 어노테이션 프로세서 실행을 위해 자바 컴파일러를 사용한다.

2023년 4월 기준으로 kapt 플러그인은 메인터넌스 모드에 있으며 새로운 기능 구현 예정이 없어 어노테이션 처리를 위해서는 kapt를 KSP(Kotlin Symbol Processing)로 대체하는 것이 권장된다. KSP는 기존 kapt의 빌드 성능을 2배 개선하였다.


참고

Comments