/ JAVAJUNGSUK

Ch12-34~37. 애너테이션

자바의 정석 기초편

0. 목차



Chapter12. 지네릭스, 열거형, 애너테이션

Ch12 - 34. 애너테이션 타입 정의하기

Ch12 - 35. 애너테이션의 요소

Ch11 - 36. 모든 애너테이션의 조상

Ch11 - 37. 마커 애너테이션

Ch11 - 38. 애너테이션 요소의 규칙

Ch11 - 39. 애너테이션의 활용 예제



Ch12 - 34. 애너테이션 타입 정의하기


▶ 애너테이션을 직접 만들어 사용 가능

▷ 애너테이션 생성 방법
@interface 애너테이션 이름 {
    타입 요소 이름(); // 애너테이션 요소 선언
    ...
}
  • @DateTime의 예
      @interface DateTime {
          String yymmdd();
          String hhmmss();
      }    
    
▷ 애너테이션의 메서드는 추상 메서드이며, 애너테이션 적용 시 지정 해 줌(순서X)
  • @TestInfo 생성
    @interface TestInfo {
      int count();
      String testedBy();
      String[] testTools();
      TestType testType(); // enum TestType { FIRST, FINAL }
      DateTime testDate(); // 자신이 아닌 다른 애너테이션(@DateTime) 포함 가능
    }
    
  • @TestInfo 사용
    @TestInfo (
      count = 3;,
      testedBy = "Baek",
      testTools = {"JUnit", "AutoTester"},
      testType = TestType.FIRST,
      testDate = @DateTime(yymmdd = "160101", hhmmss = "235959")
    ) // 요소마다 값을 지정
    public class NesClass { ... }
    
    • 추상 메서드를 구현할 필요X
    • 사용할 때 요소마다 값을 넣어주면 됨




Ch12 - 35. 애너테이션의 요소


▶ 애너테이션 요소 지정

▷ 적용 시 값을 지정하지 않으면, 사용될 수 있는 기본값 지정가능
@interface TestInfo {
  int count() default 1; // 기본값을 1로 지정
}

@TestInfo // @TestInfo(count = 1)과 동일
public class NewClass { ... }
  • @TestInfo 사용 시, 요소 지정 해야하지만 default가 있기 때문에 요소 지정 생략
▷ 요소가 하나이고 이름이 value일 때, 요소 이름 생략 가능
@interface TestInfo {
  String value();
}

@TestInfo("passed") // @TestInfo(value = "passed")와 동일
public class NewClass { ... }
▷ 요소 타입이 배열인 경우, 괄호{}를 사용해야 함
▷ 단 배열의 값이 하나일 경우 괄호{} 사용하지 않아도 됨
@interface TestInfo {
  String[] testTools();
}

// 배열의 값 2개인 경우 : { } 사용
@TestInfo(testTools = ({"Junit", "AutoTester"})

// 배열의 값 1개인 경우 : { } 생략 
@TestInfo(testTools = "Junit")

// 배열의 값 0개인 경우 : { } 사용
@TestInfo(testTools = { })



Ch12 - 36. 모든 애너테이션의 조상


▶ java.lang.annotation.Annotation

▷ 모든 애너테이션의 조상
▷ Annotation은 모든 애너테이션의 조상이지만 상속은 불가
@interface TestInfo extends Annotation { // 에러, Annotation 상속 불가
  int count();
  String testedBy();
}
▷ 사실 Annotation은 인터페이스
package java.lang.annotation;

public interface Annotation { // Annotation 자신은 인터페이스
  boolean equals(Object obj);
  int hashCode();
  String toString();
  
  class<? extends Annotation> annotationType(); // 애너테이션의 타입을 반환
}
  • Annotation = 인터페이스 → Annotation의 메서드 = 추상 메서드
  • 다른 애너테이션과 달리 추상 메서드를 구현하지 않아도 Annotation 사용 가능



Ch12 - 37. 마커 애너테이션


▶ 마커 애너테이션(Marker Annotation)이란?

▷ 요소가 하나도 정의되지 않은 애너테이션
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override { } // 마커 애너테이션, 정의된 요소가 없음

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Test { } // 마커 애너테이션

@Test // 괄호()에 요소 값 없음, 이 메서드가 테스트 대상임을 테스트 프로그램에게 알림
public void method() { }



Ch12 - 38. 애너테이션 요소의 규칙


▶ 애너테이션의 요소 선언 시, 규칙을 반드시 지켜야 함

▷ 요소의 타입 : 기본형, String, enum, 애너테이션, Class만 허용
▷ 괄호() 안에 매개 변수 선언 불가
▷ 예외 선언 불가
▷ 요소를 타입 매개 변수로 정의 불가



Ch12 - 39. 애너테이션의 활용 예제


▶ Play class를 Deprecated 하기

▷ @Deprecated
@Deprecated
public class Play {

	public static void main(String[] args) {
		
	}
}


▶ Play class에 “hello”라는 경고를 억제 시키기

▷ @SuppressWarnings
@Deprecated
@SuppressWarnings("hello") // 경고, 경고 hello는 없으므로 무시
public class Play {

	public static void main(String[] args) {
		
	}
}


▶ @TestInfo 생성

▷ @Retention : RUNTIME
@Retention(RetentionPolicy.RUNTIME) 
@interface TestInfo {

}
▷ 요소 채우기
@Retention(RetentionPolicy.RUNTIME) 
@interface TestInfo {
	int       count()	  	default 1;
	String    testedBy();
	String[]  testTools() 	default "JUnit";
	TestType  testType()    default TestType.FIRST; // TestType은 enum
	DateTime  testDate();
}

enum TestType { FIRST, FINAL }

@Retention(RetentionPolicy.RUNTIME)
@interface DateTime {
	String yymmdd();
	String hhmmss();
}


▶ @TestInfo 사용

▷ 요소에 값 넣어주기
@Deprecated
@SuppressWarnings("hello")
@TestInfo(testedBy="baek", testDate=@DateTime(yymmdd="210806",hhmmss="232323"))
public class Play {

	public static void main(String[] args) {
		
	}
}


▶ class의 애너테이션 읽어오는 코드 작성

▷ Play 클래스의 객체 얻어오기
@Deprecated
@SuppressWarnings("hello")
@TestInfo(testedBy="baek", testDate=@DateTime(yymmdd="210806",hhmmss="232323"))
public class Play {

	public static void main(String[] args) {
		Class<Play> cls = Play.class;
	}
}
▷ Play 클래스의 TestInfo 출력
▷ getAnnotation()을 통해 TestInfo 객체 생성
@Deprecated
@SuppressWarnings("hello")
@TestInfo(testedBy="baek", testDate=@DateTime(yymmdd="210806",hhmmss="232323"))
public class Play {

	public static void main(String[] args) {
		Class<Play> cls = Play.class;
		
		TestInfo anno = cls.getAnnotation(TestInfo.class);
	}
}
▷ TestInfo
  • int count() default 1;
  • String testedBy();
  • String[] testTools() default "JUnit";
  • TestType testType() default TestType.FIRST;
  • DateTime testDate();
@Deprecated
@SuppressWarnings("hello")
@TestInfo(testedBy="baek", testDate=@DateTime(yymmdd="210806",hhmmss="232323"))
public class Play {

  public static void main(String[] args) {
    Class<Play> cls = Play.class;
  
    TestInfo anno = cls.getAnnotation(TestInfo.class);
    
    // testedBy()
    System.out.println("testedBy : " + anno.testedBy());
    
    // testDate().yymmdd()
    System.out.println("testDate().yymmdd() : " + anno.testDate().yymmdd());
    
    // testDate().hhmmss()
    System.out.println("testDate().hhmmss() : " + anno.testDate().hhmmss());
    
    // testTools()
    for(String str : anno.testTools())
     System.out.println("testTools : "+str);
  }
}

// console
testedBy : baek
testDate().yymmdd() : 210806
testDate().hhmmss() : 232323
testTools : JUnit
// @TestInfo, TestType, DateTime 설정

@Retention(RetentionPolicy.RUNTIME) 
@interface TestInfo {
	int       count()	  	default 1;
	String    testedBy();
	String[]  testTools() 	default "JUnit";
	TestType  testType()    default TestType.FIRST;
	DateTime  testDate();
}

enum TestType { FIRST, FINAL }

@Retention(RetentionPolicy.RUNTIME)
@interface DateTime {
	String yymmdd();
	String hhmmss();
}
▷ 모든 애너테이션 배열에 담아 출력
@Deprecated
@SuppressWarnings("hello")
@TestInfo(testedBy="baek", testDate=@DateTime(yymmdd="210806",hhmmss="232323"))
public class Play {

	public static void main(String[] args) {
		Class<Play> cls = Play.class;
		
		Annotation[] annoArr = cls.getAnnotations();

		for(Annotation a : annoArr)
			System.out.println(a);
	}
}

// console
@java.lang.Deprecated(forRemoval=false, since="")
@baek.TestInfo(count=1, testType=FIRST, testTools={"JUnit"}, testedBy="baek",
    testDate=@baek.DateTime(yymmdd="210806", hhmmss="232323"))
// @TestInfo, TestType, DateTime 설정

@Retention(RetentionPolicy.RUNTIME) 
@interface TestInfo {
	int       count()	  	default 1;
	String    testedBy();
	String[]  testTools() 	default "JUnit";
	TestType  testType()    default TestType.FIRST;
	DateTime  testDate();
}

enum TestType { FIRST, FINAL }

@Retention(RetentionPolicy.RUNTIME)
@interface DateTime {
	String yymmdd();
	String hhmmss();
}