ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [live-study] 12주차 :: 애노테이션
    JAVA/라이브 스터디 | whiteship 2021. 2. 15. 00:12

    https://youtu.be/HLnMuEZpDwU

    참고도서 : Java의 정석(3rd Edition)

     

     

     


    0. 애노테이션

    애노테이션이란
    • 애노테이션(Annotation)주석이라는 뜻이다.
    • 자바를 개발한 사람들은 소스코드에 대한 문서를 따로 만들기 보다는, 소스코드와 문서를 하나의 파일로 관리하는 것이 낫다고 생각했다. 그래서 주석 /** ~ **/ 에 소스코드에 대한 정보를 저장하고, 그 소스코드의 주석으로부터 HTML문서를 생성해내는 프로그램 (javadoc.exe)을 만들어서 사용했다.
    • 주석과 마찬가지로 프로그래밍 언어에 영향을 끼치지 않으면서, 유용한 정보를 제공한다.
    • 그리고 모든 애노테이션의 조상은 Annotation (java.lang.annotation.Annotation) 이다. 하지만, 애노테이션은 상속이 허용되지 않으므로 아래와 같이 extends 할 수는 없다.

    • 아래와 같이 모든 애노테이션의 조상인 Annotation은 애노테이션이 아니라 인터페이스로 정의가 되어 있다. 따라서, 모든 애노테이션 객체에 대해 equals(), toString()과 같은 객체 호출이 가능하다.

    표준 애노테이션과 메타 애노테이션
    • 자바에서 기본적으로 제공하는 표준 애노테이션과 애노테이션을 정의하는데 사용되는 '애노테이션의 애노테이션'인 메타 애노테이션이 있다.
    • JDK에서 제공하는 표준 애노테이션은 주로 컴파일러를 위한 것으로 컴파일러에게 유용한 정보를 제공한다.
    • 메타 에노테이션 중에 @retention, @target, @documented는 아래에서 조금 더 살펴본다.

    * 메타 애노테이션

    1. 애너테이션 정의하는 방법

    애노테이션 정의
    • 직접 애노테이션을 만드는 방법은 interface 정의하는 방법 + @를 붙이는 것이라고 보면 된다.

    애노테이션 요소 (element) 
    • 애노테이션 내에 선언된 메소드를 애노테이션의 요소라고 한다.
    • 애노테이션 요소를 선언할 때에는 다음과 같은 규칙을 따른다.
      • 요소의 타입은 기본형, String, enum, 애노테이션, class만 허용된다.
      • ()안에 매개변수를 선언할 수 없다.
      • 예외를 선언할 수 없다.
      • 요소를 타입 매개변수로 정의할 수 없다.
    • 그리고 아래와 같이 요소들을 정의할 수 있으며, 애노테이션의 요소는 반환값이 있고 매개변수는 없는 추상 메소드의 형태를 가지며, 상속을 통해 구현하지 않아도 된다. 

     

    • 다만, 애노테이션을 적용할 때 아래와 같이 요소들을 빠짐없이 지정해주어야한다. 순서는 상관없다.
    • 기본값이 있는 요소라면, 에노테이션을 적용할 때 값을 지정하지 않으면 기본값이 사용된다.

    +) 표준 애노테이션

    @Override
    • 메소드 앞에만 붙일 수 있는 애노테이션이다.
    • 조상의 메소드를 오버라이딩하는 것을 컴파일러에게 알려주는 역할을 한다.
    • 예를 들어, 아래와 같이 오버라이딩을 할 때 메소드의 이름을 잘못 적는 경우가 있다고 가정해보자. 컴파일러는 잘못 적은 메소드를 오버라이딩 하는 메소드로 인식하는 것이 아니라, 새로운 메소드가 추가 되었다고 인식한다.

    • 하지만, @Override라는 애노테이션을 붙이면 컴파일러가 조상 메소드와 같은 이름이 있는지 체크하고 아래와 같이 에러메시지를 출력한다.

    @Deprecated
    • 새로운 버젼은 JDK가 소개될 때, 이 과정에서 기존의 기능을 대체할 것들이 추가되어도 이미 여러곳에서 사용되고 있을지도 몰라서 기존의 것들을 함부로 삭제할 수 없다.
    • 그래서 더 이상 사용되지 않는 필드나 메소드에 '@Deprecated'를 붙이는 것이다.
    • 예를 들어 java.util.Date 클래스의 대부분의 메소드에는 @Deprecated가 붙어있다. 그 중에서 getDate()를 보면 아래와 같이 Calendar클래스의 get()을 사용하라고 적혀 있고, Date클래스의 getDate()메소드에는 @Deprecated가 붙어 있는 것을 볼 수 있다.

    • 사용 할 수는 있겠지만, 권장하지는 않는다.

    @FunctionalInterface
    • 함수형 인터페이스(functional interface)를 선언할 때, 컴파일러가 함수형 인터페이스를 올바르게 선언했는지 확인하고 아니라면 에러를 발생시키는 애노테이션이다.
    @SuppressWarnings
    • 컴파일러가 보여주는 경고메시지를 나타나지 않게 해준다. 묵인해야하는 경고가 발생하는 대상에는 반드시 @SuppressWarnings를 붙여서 경고 메시지가 발생하지 않도록 해주어야한다. 
    • 주로 억제하는 경고 메시지의 종류에는 derpecation, unchecked, rawtypes, varargs가 있다.
      • deprecation은 '@Deprecated'가 붙은 대상을 사용해서 발생하는 경고 억제
      • unchecked는 generics로 타입을 지정하지 않았을 때 발생하는 경고 억제
      • rawtypes는 generics를 사용하지 않아서 발생하는 경고 억제
      • varargs는 가변인자의 타입이 generic type일 떄 발생하는 경고 억제
    @SafeVarargs
    • 메소드에 선언된 가변인자의 타입이 non-reifiable타입(컴파일 후에 제거되는 타입)일 경우, unchecked경고가 발생한다. 해당 코드에 문제가 없다면, @SafeVarargs를 사용하여 경고를 억제해야한다.

    2. @Retention

    @Retention
    • 애노테이션인 유지(retention)되는 기간을 지정하는데 사용된다.
    • 애노테이션의 유지 정책(retention policy). 종류는 다음과 같다.

    • 컴파일러가 사용하는 애노테이션(@Override, @SuppressWarnings)은 유지 정책이 SOURCE이다. 컴파일러를 직접 작성할 것이 아니라면 이 유지정책은 필요없다.

    • @FunctionalInterface는 @Override처럼 컴파일러가 체크해주는 애노테이션이지만, 실행 시에도 사용되므르 유지 정책인 RUNTIME으로 되어 있다.

    • CLASS 유지정책은 기본값임에도 불구하고, 잘 사용되지 않는다. 컴파일러가 애노테이션의 정보를 클래스 파일에 저장할 수 있게 해주지만, 클래스 파일이 JVM에 로딩될 떄는 애노테이션의 정보가 무시되어 실행 시에 애노테이션에 대한 정보를 얻을 수 없기 때문이다.

    3. @Target

    @Target
    • 애노테이션이 적용가능한 대상을 지정하는데 사용된다.

    애노테이션 적용대상 종류

    • 아래와 같이 @SuppressWarnings 정의를 보면, 이 애노테이션에 적용할 수 있는 대상을 @Target으로 지정한 것을 볼 수 있다.여러개의 값을 지정할 때는 괄호 { }를 사용한다.

     

    4. @Documented

    @Documented
    • 애노테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 한다. 자바에서 제공하는 기본 애노테이션 중에 @Override, @SuppressWarnings를 제외하고는 모두 @Documented 메타 애노테이션이 붙어 있다.

    5. 애노테이션 프로세서

    애노테이션 프로세서
    • 애노테이션 프로세서란 컴파일 시에 해당하는 어노테이션에 대한 소스 코드를 수정, 생성하는 역할을 한다. 대표적인 예로 Lombok(롬복)이 있다.
    • 애노테이션 프로세서는 라운드(회차) 개념으로 작동한다. 각 라운드마다 프로세스가 가지고 있는 element를 찾으면서 처리를 시킨다.
    • 아래 예제는 더 자바, 코드를 조작하는 다양한 방법 예제를 일부 가져왔다.
    • 우리가 구현하고자 하는 것은 @Magic이라는 커스텀 애노테이션을 만들고, @Magic 애노테이션이 붙어있는 Moja라는 인터페이스에서 MagicMoja.class 파일을 생성해주는 코드이다.
    • @Magic 이라는 커스텀 애노테이션이다.

    • MagicMojaProcessor 클래스를 만든다. (중간에 javapoet등을 이용한 부분은 생략했다..)

    • 이렇게 만든 패키지를 직접 사용할 Moja 인터페이스가 있는 프로젝트로 가서 의존성 주입을 해주면 에러 없이 @Magic 애노테이션을 사용할 수 있다. 그리고 컴파일 하고 나면 MagicMoja.class 파일이 생성되는 것을 볼 수 있다. 마지막으로 MagicMoja 파일을 소스 파일로 인식할 수 있게 모듈에서 바꿔주고 나면 MagicMoja를 사용할 수 있는 것을 볼 수 있다.

    참고자료 

    댓글

Programming Diary