# 애노테이션의 변화

목차

# 1. 애노테이션 관련 두가지 큰 변화

  • 자바 8부터 애노테이션을 타입 선언부에도 사용할 수 있게 됨
  • 자바 8부터 애노테이션을 중복해서 사용할 수 있게 됨

# 1-1. 타입 선언 부

  • 제네릭 타입
  • 변수 타입
  • 매개변수 타입
    • @Target(ElementType.TYPE_PARAMETER)
  • 예외 타입
  • etc

# 1-1-1. @Target 설정

타입에 애노테이션을 사용하기 위해 아래와 같은 ENUM 타입을 명시해야 함.

  • TYPE_PARAMETER : 타입 변수에만 사용할 수 있다.
  • TYPE_USE : 타입 변수를 포함해서 모든 타입 선언부에 사용할 수 있다.
public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}
@Retention(RetentionPolicy.RUNTIME) // 이 애노테이션 정보를 언제까지 유지할 것인가
@Target(ElementType.TYPE_PARAMETER) // 이 애노테이션을 사용할 곳
public @interface Chicken {
}
public class App {
	public static void main(@Chicken String[] args) throws @Chicken RuntimeException {
		List<@Chicken String> names = Arrays.asList("Park");
	}
	// @Target(ElementType.TYPE_PARAMETER) parameter 만 사용
	static class FeelsLikeChicken<@Chicken T> {

	}
	// @Target(ElementType.TYPE_USE) 사용
	static class FeelsLikeChicken2<@Chicken T> {
		// 전자의 <C> 는 타입 파라미터
		// 후자의 C 는 타입
		public static <@Chicken C> void print(@Chicken C c) {
			System.out.println(c);
		}
	}
}

# 1-2. 중복 사용할 수 있는 애노테이션을 만들기

  • 중복 사용할 애노테이션 만들기
  • 중복 애노테이션 컨테이너 만들기
    • 컨테이너 애노테이션은 중복 애노테이션과 @Retention@Target이 같거나 더 넓어야 한다.

# 1-2-1. 중복사용할 애노테이션 생성

/*
  @Target(ElementType.TYPE_PARAMETER)
    - 제네릭을 사용할 때 타입 변수 앞에 애노테이션을 사용할 수 있다.
  @Target(ElementType.TYPE_USE)
   - 타입 변수를 포함해서 타입 선언부에서 애노테이션을 사용할 수 있다.
  @Repeatable(컨테이너 성격의 애노테이션 class)
   - 여러 개의 애노테이션을 가지고 있을 컨테이너 애노테이션을 설정해주면 반복해서 애노테이션 사용이 가능하다.
   - 컨테이너의 애노테이션 설정(Retention, Target)은 반드시 자기자신이 감싸는 애노테이션의 범위보다 같거나 넓어야 한다.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
@Repeatable(ChickenContainer.class)
public @interface Chicken {
		String value() default "후라이드";
}

# 1-2-2. 중복 애노테이션의 컨테이너 생성

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE_USE)
public @interface ChickenContainer {
		// 컨테이너 애노테이션은 자기 자신이 감쌀 애노테이션 배열을 가지고 있어야 한다.
    Chicken[] value();
}

# 1-2-3. 컨테이너 애노테이션으로 중복 애노테이션 참조

@Chicken
@Chicken("양념")
@Chicken("마늘간장")
public class App {

    public static void main(String[] args) {
        // 1. 클래스에서 해당 애노테이션 타입으로 바로 읽어오는 방법
        Chicken[] chickens = App.class.getDeclaredAnnotationsByType(Chicken.class);
        Arrays.stream(chickens)
            .forEach(c -> System.out.println(c.value()));

        //2. 컨테이너 애노테이션 타입으로 읽는 방법
        ChickenContainer chickenContainer = App.class.getAnnotation(ChickenContainer.class);
        Arrays.stream(chickenContainer.value())
            .forEach(c -> System.out.println(c.value()));
    }
}

@Chicken 은 default value가 없으면 에러가 발생한다.

Last Updated: 6/18/2023, 2:13:15 PM