인프런 워밍업 과제 BE - 1일차 과제

어노테이션을 사용하는 이유(효과)는 무엇일까?

어노테이션이란?

  • 어노테이션은 프로그램 내에서 주석과 유사하게, 프로그래밍 언어에는 영향을 미치지 않으면서 프로그램에 유의미한 정보를 제공하는 역할을 한다. 이 속성을 어떤 용도로 사용할지, 이 클래스에 어떤 역할을 부여할지 결정하게 된다.

  • 혹은, 인터페이스 기반으로 한 문법으로 주석처럼 코드에 달아 클래스에 특별한 의미를 부여하거나 기능을 주입할 수 있다.

 

어노테이션을 사용하는 효과

  • 로직 흐름에 대한 컨텍스트가 응축되어 있어 불필요한 반복코드가 줄고 개발자가 비지니스 로직에 더 집중할 수 있도록 해준다.

  • 설정 정보를 코드에 포함시켜 유지할 수 있으며 설정 파일을 공유하는 불편함이 없다.

  • 소스코드의 로직을 방해하지 않고, 특정 프로그램을 위해 정보를 제공할 수 있다.

 


 

나만의 어노테이션은 어떻게 만들 수 있을까?

커스텀 어노테이션은 왜 사용할까?

  • 역시 어노테이션이 가진 가장 큰 장점은 간결함이다.

  •  

커스텀 어노테이션을 사용하는 방법

  • 어느 한 블로그에서는 커스텀 어노테이션 사용과 실행절차를 사과가 포장되는 과정에 비유하여 설명하였다.

판매가능한 사과에는 판매가능(@CanSale) 라벨지를 달아서 포장과정시 이를 판별하여 제품을 포장한다고 가정한다면, 타겟에 적합한 라벨지를 만들어야 한다. 라벨에는 이 라벨을 붙일 대상을 명시하고, 언제까지 타겟에 부착할 것인지를 적는다. 그리고 라벨에 이름을 적으면 라벨이 만들어진다. 사과의 상태에 따라 판매가능 라벨을 부착하여 싱싱한 사과라는 타겟에 판매가능이라는 어노테이션을 부착하게 되고, 제품 포장 과정에서는 이 라벨을 보고 판별하여 제품을 포장하는 것이다.

위의 비유와 같이, 어노테이션을 정의한 후 원하는 타겟에 적용하면 된다. 그 후, 어노테이션이 붙은 타겟을 어떻게 사용할지 기능을 구현하면 해당 기능이 실행될 때 타겟에 붙은 어노테이션에 따라서 타겟의 경로가 결정된다.


위의 시나리오로 CanSale 어노테이션을 정의해보자.

CanSale 어노테이션 정의하기

@Target(ElementType.TYPE) // 클래스 레벨에 어노테이션 적용
@Retention(RetentionPolicy.RUNTIME) // 런타임까지 어노테이션 정보 유지
public @interface CanSale {
    String target();
    String validUntil();
    String labelName();
}
  • @Target: 선언된 어노테이션이 적용될 수 있는 Java 요소의 종류를 지정한다. 클래스, 메소드, 필드, 파라미터 등이 해당한다. 이를 통해 어노테이션의 적용 범위를 제한하여 개발자가 의도하지 않은 곳에 어노테이션이 사용되는 것을 방지한다.

  • @Retention: 어노테이션의 정보가 언제까지 유지될 것인지를 지정한다.

    • RetentionPolicyu.SOURCE : 소스파일에만 유지되며, 컴파일러에 의해 제거된다.

    • RetentionPolicy.CLASS : 바이트코드 파일에는 존재하지만, 런타임에는 사용할 수 없다.

    • RetentionPolicy.RUNTIME : 런타임에도 유지되어 리플렉션을 통해 어노테이션 정보를 조회할 수 있다.

  • @Interface : 커스텀 어노테이션을 정의할 때 사용하는 키워드이다. 이 어노테이션 내부에는 여러 요소(element)를 정의할 수 있고, 각 요소는 어노테이션을 적용할 때 설정할 수 있는 속성을 의미한다.

CanSale 어노테이션을 사용하는 클래스 정의하기

@CanSale(target = "FreshApple", validUntil = "2024-02-19", labelName = "FreshAppleSale")
public class Apple {
    private boolean isFresh;

    public Apple(boolean isFresh) {
        this.isFresh = isFresh;
    }

    public boolean isFresh() {
        return isFresh;
    }
}
  • @CanSale : 커스텀으로 정의한 어노테이션이다. 판매가능한 사과에 대한 정보를 담기위해 생성하였으며, target, validUntil, labelName과 같은 요소들을 포함하여 판매대상, 유효기간, 라벨이름을 지정하는데 사용되었다.

어노테이션 정보 처리하기

public class PackagingProcess {
    public static void packageProduct(Object product) throws Exception {
        if (product.getClass().isAnnotationPresent(CanSale.class)) {
            CanSale saleInfo = product.getClass().getAnnotation(CanSale.class);
            System.out.println("Packaging " + saleInfo.target() + ". Valid until: " + saleInfo.validUntil() + ". Label: " + saleInfo.labelName());
            // 유효기간, 라벨이름 등을 판단하여 포장 처리
        } else {
            System.out.println("판매할 수 없는 물건입니다.");
        }
    }

    public static void main(String[] args) throws Exception {
        Apple apple = new Apple(true); // 싱싱한 사과 인스턴스 생성
        packageProduct(apple); // 제품 포장 시도
    }
}
  • 제품포장 과정에서 CanSale 어노테이션이 있ㄴ는지 확인하고 그 정보를 바탕으로 판매 가능한 사과를 포장하는 로직을 구현한다.

 

커스텀 어노테이션을 선언할 때 메타 어노테이션을 함께 사용하기

메타 어노테이션(meta-annotation) 이란?

  • 어노테이션을 정의할 때 사용되는 어노테이션이다. 즉, 다른 어노테이션을 위한 어노테이션으로, 어노테이션의 동작 방식을 지정하는데 사용된다.

 

주요 메타 어노테이션

@Target

  • 어노테이션이 적용될 수 있는 요소를 지정한다. 어노테이션의 사용 범위를 명확히하여 어노테이션의 적용 오류를 방지한다.

@Retention

  • 정보가 유지되는 시점을 지정한다. 세가지 RetentionPolicy가 존재한다.

@Documented

  • 어노테이션 정보가 JavaDoc 문서에 포함될지 여부를 지정한다. 이를 사용하면 어노테이션이 적용된 요소의 문서에도 어노테이션 정보가 나타난다.

@Inherited

  • 어노테이션이 하위 클래스로 상속될지 여부를 지정한다. 클래스에만 적용되며, 어노테이션이 적용ㄷ된 클래스를 상속받는 하위 클래스에서도 해당 어노테이션 정보를 유지하게 된다.

@Repeatable

  • 같은 어노테이션을 하나의 요소에 여러번 적용할 수 있게 한다. 어노테이션을 담을 컨테이너 어노테이션을 함께 정의해야 한다.

 


참고

https://seongeun-it.tistory.com/142

https://www.nextree.co.kr/p5864/

https://ittrue.tistory.com/158

댓글을 작성해보세요.