Java에서 Annotation의 개념과 활용 방법

Annotation이란?

Annotation은 자바 5부터 도입된 메타데이터 기반의 기능으로, 클래스, 메서드, 필드 등 프로그램 요소에 설명 정보를 부여하는 데 사용됩니다. 이는 코드의 실행 로직과 무관하며, 컴파일 타임 또는 런타임 시 특정 프레임워크나 도구가 이를 해석하여 동작을 조정하거나 처리하도록 설계되어 있습니다.

Annotation은 마치 수정자처럼 패키지, 클래스, 생성자, 메서드, 필드, 파라미터, 지역 변수 선언에 적용될 수 있으며, 코드의 가독성과 유지보수성을 높이는 데 기여합니다.

내부 구조 및 작동 원리

Annotation은 실질적으로 java.lang.annotation.Annotation 인터페이스를 상속한 특수한 인터페이스입니다. 이는 @interface 키워드로 정의되며, 일반 인터페이스와는 달리 제약 사항이 존재합니다.

  • 메서드는 매개변수 없이, 예외를 던지지 않아야 합니다.
  • 반환 타입은 기본형, Class, 열거형, 다른 어노테이션, 또는 이러한 타입의 1차원 배열만 가능합니다.
  • 기본값은 default 키워드로 지정되며, null은 허용되지 않습니다.
  • 제네릭을 사용할 수 없으며, Class 타입의 메서드만 제네릭을 포함할 수 있습니다.

이러한 제약은 어노테이션이 단순하고 예측 가능한 메타데이터를 제공하기 위함이며, 컴파일러나 리플렉션을 통해 쉽게 분석할 수 있도록 합니다.

주요 사용 사례

어노테이션은 주로 프레임워크 내부에서 사용되며, 다음과 같은 목적을 달성합니다:

  • 컴파일 타임 검사 (예: @Override)
  • 코드의 비추천 사용 알림 (예: @Deprecated)
  • 경고 메시지 억제 (예: @SuppressWarnings)
  • 런타임 동작 결정 (예: 스프링의 @Component, @Autowired)

표준 어노테이션 종류

@Override

상위 클래스의 메서드를 재정의했는지 확인하는 마커 어노테이션입니다. 잘못된 이름으로 오버라이딩을 시도하면 컴파일 에러를 발생시킵니다.

@Deprecated

사용이 권장되지 않는 클래스나 멤버를 표시합니다. 컴파일러는 해당 요소를 사용할 경우 경고를 출력하며, 문서화 도구(javadoc)에서도 이 정보를 반영합니다.

@SuppressWarnings

특정 경고를 무시하도록 지시합니다. 예를 들어, 타입 캐스팅 경고("unchecked")나 불필요한 코드 흐름 경고("fallthrough") 등을 제거할 수 있습니다.

@SuppressWarnings({"unchecked", "fallthrough"})
public void process() {
    // ...
}

단일 값인 경우 중괄호 생략 가능:

@SuppressWarnings("unchecked")

사용자 정의 어노테이션 예제

다음은 커스텀 어노테이션을 정의하고 리플렉션을 통해 값을 추출하는 예제입니다.

1. Author.java

package com.magc.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Author {
    String name();
    String group();
}

2. Description.java

package com.magc.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface Description {
    String value();
}

3. Utility.java

package com.magc.annotation;

@Description(value = "이 클래스는 유틸리티 기능을 제공합니다.")
public class Utility {

    @Author(name = "haoran_202", group = "com.magc")
    public String execute() {
        return "작업 완료";
    }
}

4. AnalysisAnnotation.java

package com.magc.annotation;

import java.lang.reflect.Method;

public class AnalysisAnnotation {
    public static void main(String[] args) {
        try {
            Class<?> clazz = Class.forName("com.magc.annotation.Utility");
            Method[] methods = clazz.getMethods();

            if (clazz.isAnnotationPresent(Description.class)) {
                Description desc = clazz.getAnnotation(Description.class);
                System.out.println("설명: " + desc.value());
            }

            for (Method method : methods) {
                if (method.isAnnotationPresent(Author.class)) {
                    Author author = method.getAnnotation(Author.class);
                    System.out.println("저자: " + author.name() + " (" + author.group() + ")");
                }
            }

        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

실행 결과:

설명: 이 클래스는 유틸리티 기능을 제공합니다.
저자: haoran_202 (com.magc)

태그: java Annotation reflection Custom Annotation Runtime Retention

6월 3일 01:28에 게시됨