본문 바로가기

Dev.BackEnd/JAVA

[JAVA Adv] Annotaion 에 대해서,


Annotaion (어노테이션인가, 애너테이션인가, 애노테이션인가)
도입 배경
프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시키기 위해서이다. 어노테이션 이전에는 주석을 사용하여 소스코드에 대한 설명을 적었고, 이 주석을 javadoc.exe라는 프로그램을 사용하여 문서를 작성하였다.

문법으로서 역할
어노테이션은 기본적으로 인터페이스이다. JEE 5부터 추가된 문법이며, 사전적 정의로는 주석이라는 의미를 갖고 있다. 주석과는 역할이 다르지만 주석처럼 달아 클래스에 특수한 의미를 부여하거나, 기능을 주입할 수 있고, 이 의미는 컴파일 타임 또는 런타임에 해석될 수 있다.

기존의 자바 웹 애플리케이션들은 구성과 설정값들을 외부의 XML 설정 파일에 명시하는 방법으로 프로그래밍 되었다. 변경될 수 있는 데이터들을 코드가 아닌 외부 설정 파일에 분리하기 때문에, 재컴파일 없이도 쉽게 변경사항을 적용할 수 있었지만, 프로그램 작성을 위해 매번 많은 설정을 작성해야 한다는 불편함이 존재했다. 이러한 단점이 웹 애플리케이션의 규모가 커지면서 극대화되었고 이러한 문제점을 해결하기 위해 고안된 문법이 어노테이션인 것이다.

어노테이션을 사용하면 데이터에 대한 유효성 검사조건을 어노테이션을 사용하여 직접 명시함으로써 유효조건을 쉽게 파악할 수 있게 되며 코드가 깔끔해진다. 단순히 부가적인 표현 뿐만 아니라 reflection을 이용하면 어노테이션 지정만으로 원하는 클래스를 주입할 수도 있다. 그 용도에 대해서 조금 더 자세히 알아보자.

어노테이션은 크게 문서화, 컴파일러 체크, 코드 분석을 위한 용도로 사용된다. 문서화 부분은 JavaDoc이 있기 때문에 많이 사용되지 않는다. 어노테이션의 본질적인 목적은 소스 코드에 메타데이터를 표현하는 것이다.


Built-in Annotaion
이미 Java에 내장되어 있는 어노테이션을 Built-in Annotaion이라고 한다.
주로 컴파일러를 위한 것으로 컴파일러에게 유용한 정보를 제공한다.
대표적인 예로는 다음 세 가지 + 추가적인 한 가지이다.

@Override
메서드 앞에만 붙일 수 있으며, 현재 메서드가 수퍼클래스의 메소드를 오버라이드한 메소드임을 컴파일러에게 명시한다.
오버라이딩 할 때 메서드 명에서 오타가 발생할 수 있는데 컴파일러 입장에서는 새로운 메서드를 생성하는 것인지 오버라이딩 하는 것인지 모른다. 이런 경우 어노테이션을 통해서 오타가 발생할 수 있는 부분을 잡아줄 수 있다.

@Deprecated
차후 버전에 지원되지 않을 수 있기 때문에 더 이상 사용되지 말아야 할 메소드를 나타낸다.

@SupressWarning
프로그래머의 의도를 컴파일러에게 전달하여 경고를 제거한다.

@FunctionalInterface
컴파일러에게 다음의 인터페이스는 함수형 인터페이스라는 것을 알린다. 오버라이딩 어노테이션과 같은 이유로 실수를 미연에 방지하기 위해 사용한다.


Meta-Annotaion
어노테이션에 사용되는 어노테이션으로 해당 어노테이션의 동작대상을 결정한다.
주로 새로운 어노테이션을 정의할 때 사용한다.
@Target
어노테이션이 적용가능한 대상을 지정하는데 사용한다. 여러 개의 값을 지정할 때는 배열에서 처럼 괄호 { }를 사용해야 한다.

@Retention
어노테이션이 유지되는 기간을 지정하는데 사용한다.
세 가지 유지 정책(retention policy)를 사용할 수 있다.
SOURCE :: 소스 파일에만 존재하며, 클래스 파일에는 존재하지 않는다.
@Override 나 @SupressWarnings 같은 컴파일러에 의해 사용되는 어노테이션 유지 정책이 SOURCE이다. 컴파일러를 직접 작성할 것이 아니라면, 이 유지 정책은 사용할 일이 없다.
CLASS :: 클래스 파일에는 존재하지만 런타임 시에 사용이 불가능하다. Retention 어노테이션의 default 값이지만, 런타임 시에 사용이 불가능하여 잘 사용되지 않는다.
RUNTIME :: 클래스 파일에 존재하며 런타임 시에도 사용 가능하다. 런타임 시에 리플렉션(Reflection)을 통해 클래스 파일에 저장된 어노테이션 정보를 읽어서 처리할 수 있게 된다. @FunctionalInterface는 컴파일러가 체크하는 어노테이션이지만, 런타임 시에도 사용되므로 RUNTIME의 유지정책을 갖는다.

@Documented
어노테이션에 대한 정보가 jvavadoc으로 작성한 문서에 포함되도록 할 때 사용하는 어노테이션이다. built-in-annotation 중 @Override와 @SuppressWarnings를 제외하고는 모두 이 메타 어노테이션이 붙어있다.

code>>
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface() {}

@Inherited
어노테이션이 자손 클래스에도 상속되도록 하는 어노테이션이다. 이 어노테이션을 조상 클래스에 붙이면 자손 클래스도 이 어노테이션이 붙은 것과 같이 인식된다.


@Native
네이티브 메서드에 의해 참조되는 상수필드에 붙이는 어노테이션이다. 네이티브 메서드란 JVM이 설치된 OS의 메서드를 말한다. 네이티브 메서드는 보통 C언어로 작성되어 있고 자바에서는 메서드의 선언부만 정의하고 구현은 하지 않는다. Object 클래스의 메서드들은 대부분 네이티브 메서드이다. 우리는 자바라는 언어를 통해 OS의 메서드를 호출하고 있었던 것이다. 네이티브 메서드와 자바에 정의된 메서드를 연결하는 것을 JNI(Java Native Interface)라고 한다.



Custom Annotaion 만들기
public @interface MyAnnotaion {}
어노테이션 타입 선언은 특별한 종류의 인터페이스이다.
어노테이션 타입 선언을 일반적인 인터페이스 선언과 구분하기 위해 예약어 interface 앞에 @를 붙여준다.
어노테이션 타입은 암묵적으로 java.lang.annotaion.Annotaion을 확장하기 때문에 extends절을 가질 수 없다.
다음과 같은 형식을 갖는다.
@interface 어노테이션 이름 {
     타입 요소이름 ();
     ...
}

어노테이션은 메타데이터 저장을 위해 클래스처럼 멤버를 가질 수 있다. 어노테이션 내에 선언된 메서드를 애너테이션의 요소(element)라고 한다. 이 요소의 개수에 따라 Maker 어노테이션, Single-value 어노테이션, Full 어노테이션으로 분류할 수 있다.
Maker 어노테이션
요소가 한 개도 없으며 단순히 표식으로서 사용되는 어노테이션이다. 이 어노테이션은 컴파일러에게 어떤 의미를 전달하는데 사용된다.

Single-vaule 어노테이션
요소로 단일 변수만을 갖는 어노테이션이다. 단일변수 밖에 없기 때문에 값만을 명시하여 데이터를 전달할 수 있다.
@interface TestInfo {
String value();
}
@TestInfo(“passed”) // @TestInfo(value=“passed”) 와 동일
class NewClass{ … }

Full 어노테이션
요소로 둘 이상의 변수를 갖는 어노테이션으로, 데이터를 배열 안에 key-value의 형태로 전달한다.

이 요소에는 일정한 규칙이 존재한다.
1. 요소의 타입은 기본형, String, enum, 애너테이션, Class만 허용된다.
2. 요소의 ()안에 매개변수를 선언할 수 없다.
3. 예외를 선언할 수 없다.
4. 요소를 타입 매개변수로 정의할 수 없다.
+ 어노테이션의 각 요소는 기본값을 가질 수 있다.
@interface TestInfo {
int count() default 1;
}
@TestInfo(“passed”) // @TestInfo(count=1) 와 동일
class NewClass{ … }



Spring Framework API를 살펴보면서 중요하다고 생각되는 Java 문법들을 다루고 있습니다 :)



end