[Java] 애노테이션
Web/Java

[Java] 애노테이션

 

 

애노테이션

 

자바를 개발한 사람들은 소스코드에 대한 문서를 따로 만들기보다 소스코드와 문서를 하나의 파일로 관리하는 것이 낫다고 생각했습니다.

그래서 소스코드의 주석 '/** ~ */'에 소스코드에 대한 정보를 저장하고, 소스코드의 주석으로부터 HTML문서를 생성해내는 프로그램인 javadoc.exe 를 만들어 사용했습니다.

 

아래는 모든 애노테이션의 조상은 Annotation 인터페이스의 실제 소스코드의 일부입니다.

 

'/**'로 시작하는 주석 안에 소스코드에 대한 설명들이 있고, 그 안에 '@'이 붙은 태그들이 보입니다.

 

미리 정의된 태그들을 이용해서 주석 안에 정보를 저장하고, javadoc.exe가 이 정보를 읽어서 문서를 작성하는데 이용합니다.

 

애노테이션은 프로그램의 소스코드 안에 다른 프로그램을 위한 정보를 미리 약속된 형식으로 포함시킨 것입니다.

주석처럼 프로그래밍 언어에 영향을 미치지 않으면서도 다른 프로그램에게 유용한 정보를 제공할 수 있습니다.

 

 

 

애노테이션은 2가지로 구분합니다.

  1. 표준 애노테이션
  2. 메타 애노테이션

 

 

표준 애노테이션

JDK에서 제공하는 표준 애노테이션으로 주로 컴파일러를 위한 것입니다.

 

애노테이션 설명
@Override 컴파일러에게 오버라이딩하는 메서드라는 것을 알린다.
@Deprecated 앞으로 사용하지 않을 것은 권장하는 대상에 붙인다.
@SuppressWarnings 컴파일러의 특정 경고메세지가 나타나지 않게 해준다.
@SafeVarargs 지네릭스 타입의 가변인자에 사용한다.(JDK1.7)
@FunctionalInterface 함수형 인터페이스라는 것을 알린다.(JDK 1.8)
@Native native메서드에서 참조되는 상수 앞에 붙인다.(JDK 1.8)

 

 

 

 

메타 애노테이션

메타 애노테이션은 애너테이션을 위한 애노테이션 입니다.

즉 애노테이션에 붙이는 애노테이션으로 애노테이션을 정의할 때 애노테이션의 적용대상(target)이나 유지기간(retention)등을 지정하는데 사용됩니다.

 

 

애노테이션 설명
@Target 애노테이션이 적용가능한 대상을 지정하는데 사용한다.
@Documented 애노테이션 정보가 javadoc으로 작성된 문서에 포함되게 한다.
@Inherited 애노테이션이 자손 클래스에 상속되도록 한다.
@Retention 애노테이션이 유지되는 범위를 지정하는데 사용한다.
@Repeatable 애노테이션을 반복해서 적용할 수 있게 한다.(JDK 1.8)

 

 

 

 

@Target

 

애노테이션이 적용가능한 대상을 지정하는데 사용합니다.

 

여러 개의 값을 지정할 때는 배열에서처럼 괄호{ } 를 사용해야 합니다.

 

표준애노테이션 SuppressWarnings의 일부

 

 

 

@Target으로 지정할 수 있는 애노테이션 적용대상의 종류

 

대상타입 의미
ANNOTATION_TYPE 애노테이션
CONSTRUCTOR 생성자
FIELD 필드(멤버변수, enum상수)
LOCAL_VARIABLE 지역변수
METHOD 메서드
PACKAGE 패키지
PARAMETER 매개변수
TYPE 타입(클래스, 인터페이스, enum)
TYPE_PARAMETER 타입 매개변수(JDK 1.8)
TYPE_USE 타입이 사용되는 모든 곳(JDK 1.8)

 

 

 

@Retention

애노테이션이 유지(retention)되는 기간을 저장하는데 사용됩니다.

 

유지 정책 의미
SOURCE 소스 파일에만 존재. 클래스파일에는 존재하지 않음.
CLASS 클래스 파일에 존재. 실행시에 사용불가. 기본 값
RUNTIME 클래스 파일에 존재. 실행시에 사용가능.

 

 

 

SOURCE

@Override나 @SuppressWarning처럼 컴파일러가 사용하는 애노테이션은 유지 정책이 SOURCE 입니다.

 

내가 컴파일러를 직접 작성할 것이 아니라면, 소스단에서만 사용하는 일반 주석이라고 보면 됩니다.

 

 

 

 

CLASS

컴파일러가 애노테이션의 정보를 클래스 파일에 저장할 수 있게는 하지만, 클래스 파일이 JVM에 로딩될 때는 애노테이션의 정보가 무시되어 실행 시에 애노테이션에 대한 정보를 얻을 수 없습니다.

 

 

RUNTIME

 

유지 정책을 RUNTIME으로 하면, 실행 시에 *리플랙션(reflection) 을 통해 클래스 파일에 저장된 애노테이션의 정보를 읽어서 처리할 수 있습니다.

 

@FunctionalInterface는 @Override처럼 컴파일러가 체크해주는 애노테이션이지만, 실행 시에도 사용되므로 유지 정책이 RUNTIME으로 되어있습니다.

 

 

*리플랙션 (reflectoin)

객체를 통해 클래스의 정보를 분석해 내는 프로그램 기법.

 

 

 

 

@Documented

애노테이션에 대한 정보가 javadoc으로 작성한 문서에 포함되도록 합니다. 자바에서 제공하는 기본 애노테이션 중에 '@Override'와 '@SuppressWarnings'를 제외하고는 모두 이 메타 애노테이션이 붙어있습니다.

 

 

 

 

 

 

 

직접 애노테이션 정의

 

기본적인 구조

@interface 애노테이션이름 {
    타입 요소이름();
    ...
}

 

예시)

package javastudy.ch12;

@interface TestInfo {
    int count();
    String testedBy();
    String[] testTools();
    TestType testType(); // enum TestType {FIRST, FINAL}
    DateTime testDate(); // 자신이 아닌 다른 애노테이션(@DateTime)을 포함할 수 있다.
}

@interface DateTime {
    String yymmdd();
    String hhmmss();
}

 

 

사용

 

애노테이션을 적용할 때는 요소들의 값을 빠짐없이 지정해주어야 합니다. (순서는 상관없음)

package javastudy.ch12;

@TestInfo(
        count = 3, testedBy = "Kim",
        testTools = {"JUnit", "AutoTester"},
        testType = TestType.FIRST,
        testDate = @DateTime(yymmdd = "160101", hhmmss = "235959")
)
public class NewClass {
    ...
}

 

 

 

기본 값

애노테이션의 각 요소는 기본 값을 가질 수 있습니다.

 

>> default 이용 <<

@interface TestInfo {
    int count() default 1; // 기본 값을 1로 지정
    String testTools(); default {"JUnit", "AutoTester"}; // 기본 값을 {"JUnit", "AutoTester"}로 지정
    ...
}

 

 

 

애노테이션 적용시 요소의 이름 생략 조건

  1. 애노테이션 요소가 하나뿐이다.
  2. 요소의 이름이 value이다.
@interface TestInfo() {
    String value();
}

@TestInfo("passed")
class NewClass {...}

 

 

@SuppressWarning의 경우 요소가 String[] value 하나뿐이므로 애노테이션을 적용할 때 요소의 이름을 생략할 수 있습니다.

@SuppressWarning({"deprecation", "unchecked"})
class NewClass {...}

 

 

 

 

 

 

 

 

애노테이션 프로세서

 

소스코드 레벨에서 소스 코드에 붙어있는 애노테이션 정보를 읽어서 컴파일러가 새로운 소스코드를 생성하거나 기존의 코드 변경을 가능하게 합니다.

 

대표적인 애노테이션 프로세서는 롬복(Lombok)이 있습니다.

 

롬복(Lombok)

어노테이션 기반으로 코드를 자동추가해주는 라이브러리 입니다.

lombok을 이용하면 Getter, Setter, Equals, ToString 등과 같은 자주 쓰이는 코드를 개발자가 직접 작성하지 않아도 컴파일 시점에 추가해줍니다.

 

 

간단한 사용예제 (@Getter, @Setter @NoArgsConstructor)

package dongho.classflix.domain;

import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import javax.validation.constraints.NotEmpty;

import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Member extends BaseTimeEntity{
    @Id
    @GeneratedValue
    @Column(name = "member_id")
    private Long id;

    private String userName;

    private int age;

    @Enumerated(EnumType.STRING)
    private Gender gender;

    private String career;

    @OneToMany(mappedBy = "member")
    private List<Review> reviews = new ArrayList<>();

    public Member(String userName, int age, Gender gender) {
        this.userName = userName;
        this.age = age;
        this.gender = gender;
    }

    public Member(String userName, int age, Gender gender, String career) {
        this.userName = userName;
        this.age = age;
        this.gender = gender;
        this.career = career;
    }
}

 

Getter

 

 

Setter

 

'Web > Java' 카테고리의 다른 글

[Java] I/O  (2) 2021.08.24
[Java] Enum  (2) 2021.08.11
[Java] 멀티쓰레드 프로그래밍  (1) 2021.08.06
[Java] 예외  (2) 2021.08.02
[Java] 인터페이스  (2) 2021.07.26