Annotation

DeadWhale·2023년 3월 5일
0

JAVA

목록 보기
8/10

JDK 1.5 이전 버전에서는 컴파일러가 어노테이션을 처리할 수 있는 방법이 없었다.
예를 들어 JUnit에서는 @Test가 아닌 TestCase를 상속받아 테스트 케이스를 작성했다.
혹은 XML파일을 이용해 EJB(Enterprise JavaBeans)의 정보를 지정했다.
자바 기반 기업용 서버 컴포넌트 모델

자바의 어노테이션은 2종류가 있다

  • 기본적으로 선언되어 있는 3종
  • 내가 정의해 만드는 어노테이션

기본적으로 선언되어 있는 3종

  • @Override
    - 이 어노테이션은 메서드를 재정의할 때 사용된다
    이 어노테이션을 사용하여 부모 클래스나 인터페이스의 메서드를 재정의하는 것이 맞는지
    컴파일러가 확인하도록 할 수 있다.
  • @Deprecated
    - 이 어노테이션은 더 이상 사용되지 않는 메서드나 클래스, 필드 등을 표시할 때 사용된다.
    - 주로 하위호환성 때문에 지우지 못한 코드를
  • @SupressWarnings
    - 이 어노테이션은 컴파일러에서 경고 메시지를 무시하도록 지시하는 데 사용된다.

Meta Annotation

사용자 정의 어노테이션 구현 시 사용되는 어노테이션이다.
이 어노테이션이 어떻게 동작 해야하는지 컴파일러에게 알려주는 것.

@Target
이 어노테이션이 사용될 범위를 지정한다
  • ElementType.ANNOTATION_TYPE: 어노테이션 타입 선언
  • ElementType.CONSTRUCTOR: 생성자 선언
  • ElementType.FIELD: 필드 선언 (멤버 변수)
  • ElementType.LOCAL_VARIABLE: 지역 변수 선언
  • ElementType.METHOD: 메소드 선언
  • ElementType.PACKAGE: 패키지 선언
  • ElementType.PARAMETER: 매개변수 선언
  • ElementType.TYPE: 클래스, 인터페이스, enum, annotation 타입 선언
@Retention
어노테이션의 생명주기를 지정한다.
  1. RetentionPolicy.SOURCE: 컴파일 이후 버려지는 어노테이션. 즉, 런타임에는 유효하지 않다.
  2. RetentionPolicy.CLASS: 런타임에는 유효하지 않지만, 컴파일러가 클래스 파일에 어노테이션 정보를 저장한다.. 이 방법으로 컴파일된 클래스를 로드하면 어노테이션 정보를 가져올 수 있다..
  3. RetentionPolicy.RUNTIME: 런타임에도 유효한 어노테이션. 즉, 어노테이션 정보가 런타임에도 유지됩니다.
@Documented
javadoc 문서에 포함되어야 할지 여부를 나타낸다.

해당 어노테이션 추가 시 이 어노테이션의 사용하는 클래스나 메소드가 javadoc을 만들 때.
해당 어노테이션도 그 javadoc에 포함되어야 한다.

@Inherited
어노테이션의 상속이 가능한지 여부를 나타낸다.
  • 어노테이션은 기본적으로 상속이 허용되지 않는다.
  • 부모클래스에서 어노테이션을 사용해도 상속받은 자식클래스에서는 어노테이션을 사용할 수 없다는 의미.
import java.lang.annotation.*;

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

@MyAnnotation("This is the parent class.")
public class Parent {
    // ...
}

public class Child extends Parent {
    // ...
}

선언방식

import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyClassAnnotation {
    String name();
    int version() default 1;
    boolean isDeprecated() default false;
}

어노테이션을 사용자가 만들때 반드시 들어가야하는 정보는 두가지 이다.

  • @Retention
    - 유효기간을 지정
  • @Target
    - 적용 범위를 지정
@interface 는 무엇일까?

@interface 그냥 interface는 무엇이 다를까.
@interface 5버전 부터 추가된 어노테이션 선언 시 사용되는 키워드이다.
그냥 interface와는 사용방법과 목적성 모두 차이가 있다.

그냥 이름만 비슷할 뿐 아예 다른 것으로 인식하는 것이 올바를것 같다.
왜 @ + interface 라는 이름이 만들어졌을까를 찾아보니.
어노테이션과 인터페이스 사이의 유사성 존재하기 때문이라 판단되었다.

어노테이션 : 일종의 메타데이터의 집합( 컴파일러에게 부가적인 데이터를 제공해주기 위한 코드)
인터페이스 : 메소드 시그니처의 집합

둘 모두 정보의 집합이고 , 정보를 정의하는 것에 중점이 있기 때문에. 같은 인터페이스라는 이름을 채용했다 생각한다.


활용예

스프링이나 여러 라이브러리, 컴포넌트를 이용해 이미 많은 환경에서 어노테이션을 사용한다

String Bean의

  • @Component
  • @Controller
  • @Service
  • @Repository
  • @Bean

Lombok의

  • @Getter
  • @Setter
  • @NoArgsConstructor
  • @RequiredArgsConstructor
    등등 여러 대표적인 어노테이션이 있다.
다른 예시 ( Test Case Annotation )
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
    Class<? extends Throwable>[] expected() default {};

    long timeout() default 0L;

    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    public static class None extends Throwable {
        private static final long serialVersionUID = 1L;

        private None() {
        }
    }
}

public class MyTest {
    @Test
    public void testMethod() {
        // 테스트 코드
    }
}
  • JUnit 에서 사용되는 @Test 어노테이션의 내부이다
  • 테스트 메서드에서 발생할 수 있는 예외 처리와 타임아웃 설정을 위한 기능들을 제공해준다.
다른 예시 ( @Getter )
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.SOURCE)
public @interface Getter {
    AccessLevel value() default AccessLevel.PUBLIC;
    
    boolean onMethod() default true;
    boolean onParam() default false;
    String onParam_() default "";
    String prefix() default "";
}
  • value : Getter 메서드의 접근제어자를 지정하는데 사용
  • onMethod : 메소드가 생성될 때 null 체크 코드를 생성할 지 여부
  • onParam : 특정 메서드에서 특정 파라미터에 대한 Getter를 생성할때 사용
  • onParam_ : 특정 메서드에서 특정 파라미터에 대한 Getter를 생성할때 사용
  • prefix : 멤버 변수는 Getter 메서드의 이름을 지정하는데 사용
  1. 컴파일러가 소스 코드를 읽어들일 때, @Getter 어노테이션이 적용된 필드를 찾는다.
  2. @Getter 어노테이션이 적용된 필드의 Getter 메서드를 자동으로 생성한다.
  3. 생성된 Getter 메서드는 컴파일된 클래스 파일에 추가된다.
  4. 생성된 Getter 메서드는 실행 시점에 동작하며, 필드의 값을 반환하는 역할을 한다..

롬복이나 스프링에서 제공하는 보증된 어노테이션 말고
회사 혹은 개인이 필요해 맞게 활용한 커스텀 어노테이션의 뭐가 있을까 하고
찾다가 발견한 우아한 형제들 기술 블로그의 글이 있다.시의적절한 커스텀 어노테이션

비회원도 몇몇 서비스를 이용 할 수 있도록 해야 하는데 회원정보 또한 미리보기가 가능하도록 해야 한다.
이를 위한 API를 하나더 만드는 것이 아닌 이용해 인증을 회피하는 어노테이션을 구현해

새로운 API를 만들고 분기처리를 하는것이 아닌 좀더 좋은 방향으로 개발한 예시 인것 같다.


커스텀 어노테이션의 장점은 간결함인것 같다.
하지만 단점도 간결함인것같다.

어노테이션의 이름이 직관적이면서 다른 개발자가 어노테이션 코드를 어노테이션까지 확인해 가면서
개발해야 한다면 매우 불편한 일이 될것 같다.
@NoArgsConstructor 처럼 어노테이션의 이름만 가지고 아 이 어노테이션은 어느 역할을 하는지를 명시하는게 가장 중요하다 생각한다.

0개의 댓글