H'academy
  • H'academy
  • Web
    • Back-end
      • Spring Framework
        • Spring 개발환경 구축
          • Project 생성
          • Maven 설정
          • Maven 저장소 위치 설정
          • Apache Tomcat 연동
          • Lombok 설정
        • Spring MVC Project
          • pom.xml
          • web.xml
          • root-context.xml
          • servlet-context.xml
          • DispatcherServlet
        • Controller
          • File Upload / Download
          • RestController(작성중)
        • Spring Test
          • Assert 단정문
          • Spring 환경 연동 테스트
          • MockMvc Test
        • Spring AOP
          • AOP 용어
          • Pointcut Expression
          • Filter
          • Interceptor
          • Filter vs Interceptor
          • Controller Advice(작성중)
        • Spring JDBC
          • DBCP
          • myBatis
            • ResultMap 활용
        • ETC
          • Logging
            • Tomcat Logging 설정
          • Property 관리
          • E-mail
            • Gmail 변경사항
          • Scheduler
          • Websocket
      • Spring Boot
        • STS 다운로드
        • 프로젝트 생성
        • 프로젝트 구조
        • Spring Devtools
        • Spring Controller
          • JSP 연동
            • * JSP 생성불가 문제
            • Spring Boot 3.x
          • Model
          • 요청 파라미터 처리
          • 경로 변수 처리
          • 요청 메소드
          • Redirect
          • Spring Actuator
        • Spring Boot JDBC
          • Database 정보
          • DAO Pattern
          • ORM Framework
            • myBatis
              • Mapper 생성
            • Spring Data JPA
        • Spring AOP
          • AspectJ
          • Filter
          • Interceptor
          • ControllerAdvice
        • REST API
        • Spring WebSocket
        • Send Mail
        • Logging
        • Spring Boot Test
        • Lombok
      • Java EE
        • 개발환경 구성
          • Server와 Client
          • Web Server와 WAS
        • Dynamic Web Project
      • Apache Tomcat
        • Apache Tomcat 구조
        • Tomcat User 생성
        • Tomcat Manager 설정
      • Maven
      • Jenkins
        • Installation
          • Github Webhook 설정
          • Maven 연동
        • Project setting
          • 소스 코드 관리 설정
          • 빌드 유발 설정
          • 빌드 작업 설정
      • OpenAPI(swagger)
        • swagger 2.x (legacy)
        • swagger 3.x (boot)
        • Swagger UI 꾸미기
        • SpringDoc
    • Front-end
      • HTML
        • Heading
        • <A>
        • <IMG>
        • <DIV>
        • <TABLE>
        • <FORM>
          • <INPUT>
          • <SELECT>
          • <TEXTAREA>
          • <FIELDSET>
        • List
      • CSS
        • CSS 적용 방식
          • 크기(size)
            • 픽셀(px)
          • 색상(color)
        • CSS 선택자
          • 스타일 우선순위
        • CSS 주요 속성
          • 크기 속성
            • border
            • margin
            • padding
            • box-sizing
          • 배경 속성
          • 글자 속성
            • font
            • text
          • 배치 속성
            • position
            • display
            • overflow
            • float
            • flexbox
        • CSS Reset
      • JS
        • syntax
          • let, const
          • 구조 분해 할당
          • spread operator
          • Object copy
          • this
          • module
        • jQuery
          • structure
          • function
          • ajax
            • ajax file upload
        • VueJS
          • CDN(Vue3)
            • 기본 구조
            • Vue Devtools
            • jQuery vs VueJS
            • Vue instance
              • data
                • IME issue
              • v-model
              • template
              • computed
              • watch
                • deep watch
                • vs Computed
              • methods
            • Vue directive
              • v-text
              • v-html
              • v-bind
                • v-bind style
                • v-bind class
              • v-on
                • once
                • prevent
              • v-show
              • v-if
              • v-for
          • Vue-cli 3
            • 프로젝트 구조
            • src
              • main.js
              • App.vue
              • HelloWorld.vue
            • Vue Router 4
              • History mode
              • 404 not found
              • Guard
                • beforeEach
            • Vuex
              • 이동 횟수 측정
            • axios
              • interceptor
          • Vue-electron
        • ReactJS
          • CDN(React18)
            • 템플릿 설명
            • JSX
            • render
            • Handling Events
              • onClick
              • onInput
            • Component
              • 클래스 컴포넌트
                • state
                • props
                • event
                  • Mouse
                  • Input
                • lifecycle
              • 함수형 컴포넌트
                • useState
                • useEffect
                • useReducer
                • useMemo
                • props
                • 조건부 렌더링
          • CRA
            • 자원 경로 설정
            • src 절대 경로 설정
            • react-router
            • Context API
            • Electron 설정
        • Webpack
          • NodeJS
          • Git
    • Ubuntu server
      • Jenkins
    • 테스트 도구
      • JMeter
        • Test Plan
        • Test Plan(with login)
        • Plugin 설치
    • WebRTC
  • Base Language
    • Java
      • Java 실행 과정
        • 개발 환경 구축
        • 샘플 코드 작성
        • 컴파일/실행
        • 환경 변수 설정
      • Java 초급
        • Hello world
        • 자료와 정보
        • 변수
          • 정수
            • 정수의 저장 원리
            • 정수형 변수 생성
          • 실수
            • 실수의 저장 원리
            • 실수형 변수 생성
          • 논리
            • 논리형 변수 생성
          • 문자
          • 문자열
            • 문자열 변수 생성
          • 사용자 정의 자료형
        • 연산자
          • 대입 연산
          • 부호 연산
          • 산술 연산
          • 복합 대입 연산
          • 증감 연산
          • 쉬프트 연산
          • 비트 연산
          • 비교 연산
          • 논리 연산
          • 삼항 연산
          • 변환 연산
        • 표준 입출력
          • 표준 출력
          • 표준 오류 출력
          • 표준 입력
            • Scanner 입력
        • 제어문
          • if 구문
            • 단일 조건
            • 두 가지의 조건
            • 여러 가지의 조건
          • switch~case 구문
          • while 구문
          • do~while 구문
          • for 구문
        • 랜덤(Random)
        • 배열
          • 1차원 배열
          • 2차원 배열
          • 다차원 배열
          • Sort
            • 선택 정렬
            • 버블 정렬
            • 삽입 정렬
      • Java 중급
        • 객체 지향 프로그래밍
        • 클래스
        • 인스턴스
        • 필드
        • 메소드
          • 설정(setter) 메소드
          • 반환(getter) 메소드
        • 생성자
        • 접근 제한
          • private
          • package
          • protected
          • public
        • 정적(static)
        • 불변(final)
        • 상수(constant)
        • 상속
          • this와 super의 이해
          • 멤버 변수 설정
          • 멤버 메소드 설정
          • 생성자 설정
        • 추상화
          • 추상 클래스
          • 인터페이스
        • 다형성
        • 중첩 클래스
          • 일반 중첩 클래스
          • static 중첩 클래스
          • 지역 중첩 클래스
          • 익명 중첩 클래스
      • Java API(작성중)
        • java.lang
        • java.util
        • java.text
        • java.time
        • java.io
        • java.net
        • java.sql
        • java.awt
        • javax.swing
      • Java 고급
        • 제네릭(Generic)
        • 열거형(Enum)
        • Annotation Type
          • Retention
          • Target
          • Nested Annotation
        • Java Reflection
          • Intro
          • Class
          • Field
          • Constructor
          • Method
          • Package
      • JDBC
        • 드라이버 로드
        • 연결 생성
          • JDBC Driver 유형
        • JdbcTemplate
      • Java 버전별 변경사항
        • Java 1.8
          • Lambda Expression
          • Stream API
          • java.time 패키지
        • Java 9
        • Java 12
          • switch~case
        • Java 13
          • Text Block
    • Arduino
      • 학습 준비
        • Reference
        • 아두이노 온라인 시뮬레이터
        • 전기의 이해
        • 그라운드(GND)의 이해
      • 개발 환경 구축
        • CH340 보드 설치
        • Editor 글꼴 설정
      • 아두이노 제어
        • 코드의 구성
        • 시리얼 출력
        • 디지털 출력
          • LED 출력
        • PWM 출력
        • 시리얼 입력
        • 디지털 입력
          • PIR 센서
        • 아날로그 입력
          • 온도 센서(LM35DZ)
          • 조도 센서
          • 가스 센서
        • 피에조 부저
        • 서보 모터 제어
          • 시리얼 서보 모터 제어
          • 스위치 서보 모터 제어
        • 온습도 센서(DHT-11)
        • LCD
      • 아두이노 통신
        • 블루투스(Bluetooth)
          • HC-06
            • 온도 센서 활용
          • HM-10
        • 와이파이(Wi-Fi)
          • ESP-01
            • WiFiEsp 라이브러리 추가
            • WiFiEsp 네트워크 스캔
        • 이더넷(Ethernet)
        • ArduinoJson 라이브리 사용
    • Regular Expression
  • Database
    • Oracle
      • 설치
        • SQL Plus
        • SQL Developer
        • DBeaver
        • Docker(Mac OS)
      • SQL
        • 관리자 명령
          • 사용자 관리
          • 권한 관리
          • Encoding 설정
          • 서비스 포트 설정
        • 사용자 명령
          • 테이블 관리
            • 테이블 항목 제약 조건
            • 외래키 제약조건
            • 데이터 유형
          • 시퀀스 관리
          • 데이터 관리
            • 데이터 추가
            • 데이터 조회
              • 오라클 내장 함수
              • 그룹 조회
              • Top N Query
            • 데이터 수정
            • 데이터 삭제
          • 뷰 관리
          • 인덱스 관리
          • 집합 연산
          • 테이블 조인
            • 등가 조인
            • 외부 조인
        • HR 계정
        • 기타 명령
          • 컬럼 간격 조정
      • 내보내기 및 불러오기
        • EXPDP, IMPDP
        • Docker로 실행중인 경우
      • 기타
        • 자동 세션 제거
        • Tablespace 관리
        • Unlock user
  • 면접대비
    • Q&A
      • Java
      • Database
      • Web
      • IT 일반상식
  • ETC
    • Eclipse IDE
      • 설치
      • 화면 설명
      • 환경 설정
      • 프로젝트 생성
      • 소스파일 작성 및 실행
    • Github
      • Github 계정 관리
      • Github 저장소 관리
        • Profile
        • Collaborators
        • Code
        • Issues
        • Pull requests
        • Action
          • Vue 3 Deploy Action
      • Personal Access Token
      • Git ignore 설정
        • Spring 개발용 샘플
      • Github Eclipse 연동
        • Branches
        • Project
        • Team project
          • Dynamic web project
          • Spring Boot Project
          • Branch 생성
          • Pull Request
          • Branch 보호
          • Branch 다시 생성
    • Figma
      • Team
      • Design
      • Component
    • 과정평가형
      • 실기 모의고사 1회
      • 실기 모의고사 2회
      • 실기 모의고사 3회
      • 실기 모의고사 4회
    • VScode
      • Live Server 실행 오류
      • Github 계정 변경
    • Naver ToastUI Editor
      • Editor 만들기
        • Editor options
          • File upload
      • Viewer 만들기
    • 문자 인코딩 방식
    • OBS
      • 녹화 잡음 제거 설정
    • Semantic Version
Powered by GitBook
On this page
  • Retention
  • @interface Retention
  • enum RetentionPolicy
  • RetentionPolicy.SOURCE
  • RetentionPolicy.CLASS
  • RetentionPolicy.RUNTIME
  1. Base Language
  2. Java
  3. Java 고급
  4. Annotation Type

Retention

Retention

이 문서에서는 Retention 설정 옵션에 따른 차이를 다룬다.

@interface Retention

Library에서 Retention 코드를 찾아보면 다음과 같다. 편의상 주석은 제거하였다.

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    RetentionPolicy value();
}
  • @Documented - 작성된 Annotation이 Javadoc에 문서화 됨을 표시

  • @Target - 이 Annotation이 다른 Annotation type에 작성될 수 있음을 표시

Annotation 내부에는 RetentionPolicy라는 Enum 값을 저장할 수 있는 value 속성이 존재한다.

enum RetentionPolicy

RetentionPolicy의 코드는 다음과 같다.

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

설정 가능한 RetentionPolicy 값은 다음과 같다.

  • SOURCE - 컴파일러에 의해 삭제되는 Annotation

  • CLASS - 컴파일러에 의해 클래스파일에 기록되지만 런타임 시 VM에서는 관리하지 않음

  • RUNTIME - 컴파일러에 의해 클래스파일에 기록되고 VM에서 관리하여 실행 중 읽을 수 있음

RetentionPolicy.SOURCE

RetentionPolicy.SOURCE로 설정된 Annotation은 컴파일과 동시에 사라진다. 따라서 다음 용도로 사용이 가능하다.

  1. 코드상에 단순한 표식(Marking) 생성

  2. 컴파일 시 특정 코드로 치환되도록 자동화 구현

코드상에 단순한 표식 설정

예를 들어 테스트가 진행중인 메소드에 다음과 같이 표시를 남겨 정보를 줄 수 있다.

먼저 Annotation을 다음과 같이 생성한다.

@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.METHOD)
public @interface TestInProgress {
	String tester();
	String last() default "today";
}

그리고 특정 메소드에 Annotation을 작성하고 옵션으로 정보를 설정한다.

public class TestFunction {
	@TestInProgress(tester = "Hacademy")
	public static void print() {
		System.out.println("Hello world!");
	}
}

생성된 class 파일을 찾아서 디컴파일하면 다음과 같이 표시된다.

// 
// Decompiled by Procyon v0.5.36
// 

package com.hacademy.annotation;

public class TestFunction
{
    public static void print() {
        System.out.println("Hello world!");
    }
}

@TestInProgress Annotation이 사라진 것을 확인할 수 있다.

컴파일 시 특정 코드로 치환되도록 자동화 구현

대표적인 라이브러리로 Lombok이 있다. Lombok에서 사용하는 @Getter @Setter @ToString @EqualsAndHashCode 등이 해당된다.

Lombok을 이용하여 다음과 같이 클래스를 하나 만든다.

Book.java
package com.hacademy.annotation;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data @NoArgsConstructor @AllArgsConstructor @Builder
public class Book {
	private String name;
	private int price;
}

이 클래스에는 Lombok에서 제공하는 Annotation 4종류를 사용하였다.

  • @Data - Getter/Setter, ToString, EqualsAndHashCode 생성

  • @NoArgsConstructor - 기본 생성자 생성

  • @AllArgsConstructor - 모든 필드 초기화 생성자 생성

  • @Builder - 빌더 패턴을 위한 빌더 클래스 생성

디컴파일러를 이용하여 생성된 클래스를 살펴보면 다음과 같다.

Book.class
// 
// Decompiled by Procyon v0.5.36
// 

package com.hacademy.annotation;

public class Book
{
    private String name;
    private int price;
    
    public static Book.BookBuilder builder() {
        return new Book.BookBuilder();
    }
    
    public String getName() {
        return this.name;
    }
    
    public int getPrice() {
        return this.price;
    }
    
    public void setName(final String name) {
        this.name = name;
    }
    
    public void setPrice(final int price) {
        this.price = price;
    }
    
    @Override
    public boolean equals(final Object o) {
        if (o == this) {
            return true;
        }
        if (!(o instanceof Book)) {
            return false;
        }
        final Book other = (Book)o;
        if (!other.canEqual(this)) {
            return false;
        }
        if (this.getPrice() != other.getPrice()) {
            return false;
        }
        final Object this$name = this.getName();
        final Object other$name = other.getName();
        if (this$name == null) {
            if (other$name == null) {
                return true;
            }
        }
        else if (this$name.equals(other$name)) {
            return true;
        }
        return false;
    }
    
    protected boolean canEqual(final Object other) {
        return other instanceof Book;
    }
    
    @Override
    public int hashCode() {
        final int PRIME = 59;
        int result = 1;
        result = result * 59 + this.getPrice();
        final Object $name = this.getName();
        result = result * 59 + (($name == null) ? 43 : $name.hashCode());
        return result;
    }
    
    @Override
    public String toString() {
        return "Book(name=" + this.getName() + ", price=" + this.getPrice() + ")";
    }
    
    public Book() {
    }
    
    public Book(final String name, final int price) {
        this.name = name;
        this.price = price;
    }
}

생성된 내부에 Java에서 작성한 적이 없는 코드들이 추가되어 있는 것을 확인할 수 있다. 또한 @Builder 로 인하여 빌더 클래스가 하나 더 생긴것을 확인할 수 있다.

Book$BookBuilder.class
// 
// Decompiled by Procyon v0.5.36
// 

package com.hacademy.annotation;

public static class BookBuilder
{
    private String name;
    private int price;
    
    BookBuilder() {
    }
    
    public BookBuilder name(final String name) {
        this.name = name;
        return this;
    }
    
    public BookBuilder price(final int price) {
        this.price = price;
        return this;
    }
    
    public Book build() {
        return new Book(this.name, this.price);
    }
    
    @Override
    public String toString() {
        return "Book.BookBuilder(name=" + this.name + ", price=" + this.price + ")";
    }
}

사용한 Lombok의 Annotation은 제거된 것을 확인할 수 있다. 각각의 Annotation을 보면 Retention 설정이 RetentionPolicy.SOURCE로 되어 있는 것을 확인할 수 있다.

Data.class
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Data {
    //(내용 생략)
}
NoArgsConstructor.class
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface NoArgsConstructor {
    //(내용 생략) 
}
AllArgsConstructor.class
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface AllArgsConstructor {
   //(내용 생략) 
}
Builder.class
@Target({TYPE, METHOD, CONSTRUCTOR})
@Retention(SOURCE)
public @interface Builder {
   //(내용 생략) 
}

해당 내용들을 직접 적용하려면 annotation processor 등의 처리가 필요하다.

RetentionPolicy.CLASS

RetentionPolicy.CLASS로 설정된 Annotation은 컴파일 이후의 바이트 코드까지 유지되지만 런타임 시점까지 반드시 유지할 필요는 없다. 따라서 RetentionPolicy.SOURCE와 RetentionPolicy.RUNTIME의 중간 정도로 이해할 수 있다. 보기에 따라서 상당히 애매해 보일 수 있지만 자바 애플리케이션을 만들 때 다수의 jar 파일을 사용하고, 이 jar 파일에는 class 파일만 들어있다는 것을 생각해보면 배포된 파일에는 포함되어야 하지만 실행 시에는 포함될 필요가 없는 경우 사용하는 형태라고 볼 수 있다.

RetentionPolicy.RUNTIME

다음 Book 클래스를 통해 좀 더 자세히 살펴본다.

Book.java
package com.hacademy.annotation;

@TestEntity(author = "hacdemy", date = "2022-03-03", comment = "테스트를 위한 Annotation")
public class Item {
	private String name;
	private int price;
	
	public void setName(String name) {
		this.name = name;
	}
	public void setPrice(int price) {
		this.price = price;
	}
	public String getName() {
		return name;
	}
	public int getPrice() {
		return price;
	}
	
	@Override
	public String toString() {
		return "Item [name=" + name + ", price=" + price + "]";
	}
}

Book 클래스에는 @TestEntity 라는 Annotation이 설정되어 있다. @TestEntity의 코드는 다음과 같다.

package com.hacademy.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestEntity {
	String author() default "";
	String date() default "N/A";
	String comment() default "";
}

Retention 설정이 RetentionPolicy.RUNTIME으로 되어 있기 때문에 실행 중에도 Annotation이 유지되며 Java Reflection을 이용하여 이를 알아낼 수 있다.

AnnotationCheckApplication.java
package com.hacademy.annotation;

import java.lang.annotation.Annotation;

public class AnnotationCheckApplication {
	public static void main(String[] args) throws ClassNotFoundException {
		Class<?> c = Class.forName("com.hacademy.annotation.Item");
		Annotation annotation = c.getDeclaredAnnotation(TestEntity.class);
		if(annotation == null) {
			System.out.println("일반 클래스");
		}
		else {
			System.out.println("테스트 진행중인 클래스");
			TestEntity test = (TestEntity)annotation;
			System.out.println(test.author());
			System.out.println(test.date());
			System.out.println(test.comment());
		}
	}
}

메소드는 Method, 생성자는 Constructor, 필드는 Field 클래스에 존재하는 annotation 반환 명령을 이용하여 특정 Annotation이 존재하는지 확인할 수 있고, 필요하다면 모든 Annotation 목록을 반환하도록 만들 수 있다.

  • getAnnotation(Class) - 상속된 Annotation을 포함하여 특정 Annotation의 유무 조회

  • getDeclaredAnnotation(Class) - 상속된 Annotation을 제외하고 특정 Annotation의 유무 조회

  • getAnnotations() - 상속된 Annotation을 포함하여 목록 조회

  • getDeclaredAnnotations() - 상속된 Annotation을 제외하고 목록 조회

PreviousAnnotation TypeNextTarget

Last updated 3 years ago

RetentionPolicy.RUNTIME으로 설정된 Annotation은 VM에서 런타임 시점까지 유지한다. 런타임 시점까지 유지된다는 것은 코드를 통해 Annotation의 유무와 내부에 설정된 옵션을 읽을 수 있다는 의미이다. 과 같은 기술을 사용하여 Annotation을 해석하고, 이에 따라 다른 작업을 수행할 수 있다.

Java Reflection
Project Lombok
Logo
lombok 공식 홈페이지에 있는 소개 비디오 영상
Java decompiler online