꾸준한 스터디
article thumbnail

명명 패턴이란 변수나 함수의 이름을 일관된 방식으로 작성하는 패턴을 말하며 이러한 명명 패턴은 전통적으로 도구나 프레임워크가 특별히 다뤄야 할 프로그램 요소를 구분하기 위해 적용해왔다.

 

예를 들어 테스트 프레임 워크인 JUnit은 버전 3까지 테스트 메서드 이름을 test로 시작해야했다.

효과적인 방법이지만 단점도 큰데

 

  1. 메서드 이름에 오타가 나면 안된다.
    • 실수로 이름을 'tsetSafetyOverride'로 지으면 JUnit 3은 이 메서드를 무시하고 지나치기 때문에 개발자는 이 테스트가 실패하지 않았으니 통과했다고 오해할 수 있다.
  2. 올바른 프로그램 요소에서만 사용되리라 보증 할 방법이 없다는 것이다.
    • 메서드가 아닌 클래스 이름을 TestSafetyMechanisms로 지어 JUnit에 던져주고 개발자는 이 클래스에 정의된 테스트 메서드들을 수행해주길 기대했지만 JUnit은 클래스 이름에는 관심이 없다. JUnit은 경고 메세지조차 출력하지 않지만 개발자가 의도한 테스트는 전혀 수행되지 않는다.
  3. 프로그램 요소를 매개변수로 전달할 마땅한 방법이 없다.
    • 특정 예외를 던져야만 성공하는 테스트가 있을 때, 기대하는 예외 타입을 테스트에 매개변수로 전달해야 하는 상황이다. 예외의 이름을 테스트 메서드 이름에 덧붙이는 방법도 있지만, 가독성이 떨어지고 컴파일러는 메서드 이름에 붙인 문자열이 예외를 가리키는 이름인지 알 수 없다. 테스트를 실행하기 전에는 그런 이름의 클래스가 존재하는지 혹은 예외가 맞는지조차 알 수 없다.

 

애너테이션은 이 모든 문제를 해결해주는 멋진 개념으로 JUnit 버전 4 부터 도입되었다.

Annotaion : 사전적인 의미로 주석. 자바에서 사용될 때는 코드 사이에 주석처럼 쓰여서 특별한 의미, 기능을 수행하도록 하는 기술. 즉, 프로그램에게 추가적인 정보를 제공해주는 메타데이터라고 볼 수 있다.
JDK 1.5부터도입된 기능으로 정보를 알려주는 기능과 컴파일러에게 문법 에러 체크를 제공하기도 한다. 
DispatcherServlet에게 등록할 Bean을 알려주는 역할도 한다.

 

자동으로 수행되는 간단한 테스트용 애너테이션을 정의했다. 예외가 발생하면 해당 테스트를 실패로 처리한다.

이와 같은 애너테이션을 "아무 매개변수 없이 단순히 대상에 마킹한다"는 뜻에서 마커 애너테이션이라고 한다.

@Test 애너테이션 타입 선언에 @Retention과 @Target 을 메타애너에이션이라고 한다.

Meta-data : 데이터에 관한 구조화된 데이터로, 다른 데이터를 설명해주는 데이터.
메타 데이터는 데이터에 대한 데이터이다. 대량 정보 가운데 찾고있는 정보를 효율적으로 찾아내서 이용하기 위해 일적한 규칙에 따라 컨텐츠에 부여되는 데이터.
Meta-Annotaion : 다른 Annotaion 에서 사용되는 Annotaion을 말한다. @Controller와 @Service 어노테이션은 빈으로 등록되기 위해 @Component를 포함하고 있는데 이 어노테이션 안에서 사용되고 있는 어노테이션인 @Component를 메타 어노테이션이라고 부른다. 보통 커스텀 어노테이션을 만들 때 많이 사용된다.
그 외 @Target, @Retention, @Document 등등이 있다.
애노테이션을 다른 애노테이션의 메타 애노테이션으로 사용하기 위해 @Target 메타 애노테이션에 ElementType.ANNOTATION_TYPE 이 선언되어야 한다.
  • @Retention - 애너테이션이 실제로 적용되고 유지되는 범위
    • RetentionPolicy.RUNTIME - 컴파일 이후에도 JVM에 의해 계속 참조가 가능. 주로 리플렉션이나 로깅에 사용
    • RetentionPolicy.CLASS -  컴파일러가 클래스를 참조할 때 까지 유효
    • RetentionPolicy.SOURCE - 컴파일 전까지 유효. 컴파일 이후에는 사라진다.
  • @Target - 애너테이션이 어디에 적용될지 결정
    • ElementType.PACKAGE - 패키지 선언
    • ElementType.TYPE - 타입 선언
    • ElementType.ANNOTATION_TYPE - 애너테이션 선언
    • ElementType.CONSTRUCTOR - 생성자 선언
    • ElementType.FIELD - 필드 선언
    • ElementType.LOCAL_VARIABLE - 지역 변수 선언
    • ElementType.METHOD - 메서드 선언
    • ElementType.PARAMETER - 매개변수 선언
    • ElementType.TYPE_PARAMETER - 매개변수 타입 선언
    • ElementType.TYPE_USE -  타입이 사용되는 곳에 선언

 

Sample 클래스에는 정적 메서드가 7개고 그 중 4개에 @Test를 달았다.

m3, m7 메서드는 예외를 던지고 m1,m5는 예외를 던지지 않지만 m5는 인스턴스 메서드이므로 @Test를 잘못사용한 경우다.

 

Test 애너테이션은 단순히 Test 이름에 오타를 내거나 메서드 선언 외에 프로그램 요소에 달면 컴파일 오류를 내는 역활이고 주석에 매개변수 없는 static 메서드 전용이다 라는 제약을 적용하려면 적절한 애너테이션 처리기를 구현해야 한다.

이 테스트 러너는 정규화된 클래스 이름을 받아 그 클래스에서 @Test 애너테이션이 달린 메서드를 차례로 호출한다.

isAnnotationPresent가 실행할 메서드를 찾아주는 메서드다. 테스트 메서드가 예외를 던지면 리플렉션 메커니즘이 InvocationTargetException으로 감싸서 다시 던진다. 예외에 담긴 실패 정보를 추출해(getCause) 출력한다.

InvocationTargetException 외의 예외가 발생한다면 @Test 애너테이션을 잘못 사용했다는 뜻으로 인스턴스 메서드, 매개변수가 있는 메서드, 호출할 수 없는 메서드 등에 달았을 경우이다. 이를 처리하기 위해 새로운 애너테이션 타입이 필요하다.

 

이 애너테이션의 매개변수 타입은 Class<? extends Throwable>로 와일드카드 타입의 의미는 "Throwable을 확장한 클래스의 Class 객체"라는 뜻이며, 모든 예외 타입을 수용한다.

 

이 코드는 애너테이션 매개변수의 값을 추출하여 테스트 메서드가 올바른 예외를 던지는지 확인하는데 사용한다.

형 변환 코드가 없으니 ClassCastException 걱정은 없고 테스트 프로그램이 문제없이 컴파일 되면 애너테이션 매개변수가 올바른 예외 타입이라는 뜻이다.

 

 

 

@ExceptionTest 애너테이션의 매개변수 타입을 Class 객체의 배열로 수정하여 예외를 여러개 명시할 수 있게 하고 그중 하나가 발생하면 성공으로 만들 수 있다.

 

원소가 여럿인 배열을 지정할 때는 원소들을 중괄호로 감싸고 쉼표로 구분한다.

 

반복문을 추가하여 Throwable 배열을 검증하는 로직이 추가 됐다.

 

 

자바 8부터 여러 개의 값을 받는 애너테이션을 배열 매개변수를 사용하는 대신 애너테이션에 @Repeatable 메타 애너테이션을 다는 방식을 제공한다. 

@Repeatable 단 애너테이션은 하나의 프로그램 요소에 여러번 달 수 있다.

 

단, 주의할 점으로

  1. @Repeatable을 단 애너테이션을 반환하는 '컨테이너 애너테이션'을 하나 더 정의하고 @Repeatable에 이 컨테이너 애너테이션의 class 객체를 매개변수로 전달해야 한다.
  2. 컨테이너 애너테이션은 내부 애너테이션 타입의 배열을 반환하는 value 메서드를 정의해야 한다.
  3. 컨테이너 애너테이션 타입에는 적절한 보존 정책(@Retention)과 적용 대상(@Target)을 명시해야 한다. 그렇지 않으면 컴파일되지 않는다.

 

반복 가능 애너테이션을 여러개 달면 하나만 달았을 때와 구분하기 위해 해당 '컨테이너' 애너테이션 타입이 적용된다.

getAnnotationsByTypes 메서드는 이 둘을 구분하지 않아서 반복 가능 애너테이션과 그 컨테이너 애너테이션을 모두 가져오지만, isAnnotationPresent 메서드는 둘을 명확히 구분한다. 매개변수가 달려있는 수와 상관없이 모두 검사하려면 둘을 따로따로 확인해야 한다.

 

반복 가능 애너테이션을 사용해 하나의 프로그램 요소에 같은 애너테이션을 여러 번 달 때 코드 가독성을 높여보았으나 코드양이 늘어나며 처리 코드가 복잡해져 오류가 날 가능성이 커짐을 명심해야 한다.

 

 

 

애너테이션으로 할 수 있는 일을 명명 패턴으로 처리할 이유는 없다.

도구 제작자를 제외하고는 일반 프로그래머가 애너테이션 타입을 직접 정의할 일은 없다. 하지만 자바 프로그래머라면 예외 없이 자바가 제공하는 애너테이션 타입들은 사용해야 한다.

 

 

https://jjingho.tistory.com/86

profile

꾸준한 스터디

@StudyRecord

포스팅이 유익하셨다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!