🔥딱 8일간! 인프런x토스x허먼밀러 역대급 혜택

[인프런 워밍업 스터디 클럽 0기 Back] 어노테이션 관련 1일차 미션

1일차 과제

우리는 최초로 API를 만들어 보았습니다. GET API를 만들기 위해 사용했던 어노테이션에 익숙하지 않다면 자바 어노테이션에 대해서 몇 가지 블로그 글을 찾아보세요! 다음 질문을 생각하며 공부해보면 좋습니다! 😊

[질문]

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

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

[답]

  • 어노테이션이란?

    • 코드에게 메타데이터를 제공하는 방법이다.

    • 어노테이션은 자바 코드에 직접 포함되지만, 어노테이션 자체는 실행 가능한 코드처럼 동작하지 않는다.

    • 어노테이션은 직접적으로 프로그램에 영향을 주는 것이 아니며, 메타 데이터를 제공하는 역할을 한다.

  • 어노테이션의 목적

    • 컴파일 시점에서의 검사 및 처리

      • 어노테이션을 통해 컴파일러는 코드의 정확성을 검사하고, 필요에 따라 코드를 자동으로 생성할 수 있다.

      • 정확성 검사

        • @Ovrride 어노테이션을 사용하면, 메서드가 상위 클래스나 인터페이스의 메서드를 오버라이드 한다는 것을 명시한다.

        • 컴파일러는 이 어노테이션을 참고하여, 실제로 상위 클래스나 인터페이스에 해당 메서드가 있는지 검사한다.

        • 메서드 시그니처가 일치하지 않게 되면 컴파일 에러가 발생한다.

      • 코드 생성

        • Lombok 같은 라이브러리는 @Getter 등의 어노테이션을 통해 컴파일때 게터를 자동으로 생성한다.

        • 반복적인 보일러플레이트 코드를 대폭 줄여준다.

      • 코드 분석 도구

        • 일부 어노테이션은 코드 분석 도구에 사용될 수 있다.

        • @Deprecated 어노테이션이 붙은 사용되지 않는 메서드를 찾아 개발자에게 경고한다.

    • 런타임에서의 동작 제어

      • 런타임에서는 리플렉션 API를 사용하여 어노테이션 정보를 조회하고, 프로그램의 동작을 제어한다.

      • 조건부 로직 실행

        • @Secured 어노테이션을 사용하면 메서드 실행 전 사용자 권한을 체크하는 로직이 실행된다.

        • 보안 관련 로직을 중앙에서 관리하고, 코드의 재사용성을 높이는데 도움을 준다.

      • 동적 구성

        • @Autowired 어노테이션을 사용해 의존성을 자동으로 주입하면 런타임에 객체 간의 의존 관계가 동적으로 구성된다.

        • 설정 코드를 줄이고, 유연한 구성을 가능하게 만든다.

    • 개발 도구에서의 사용

      • IDE나 빌드 도구는 어노테이션을 사용해 코드 구조를 이해하고, 개발자에게 유용한 정보를 제공하거나, 특정 작업을 자동화한다.

      • IDE 지원

        • 어노테이션을 통해 코드의 문제점을 더 쉽게 식별할 수 있도록 돕는다.

        • @NotNull 어노티에션을 변수로 적용하면, IDE는 해당 변수에 null 값이 할당되는 경우 경고를 표시한다.

      • 빌드 자동화

        • Maven, Gradle 등 빌드 도구는 어노테이션 프로세서를 통해 컴파일 시점에 코드 생성 또는 변환 작업을 자동으로 수행한다.

        • 빌드 과정을 최적화하고, 반복적인 작업을 자동화하는데 도움이 된다.

      • 테스트 프레임워크 통합

        • JUnit 같은 테스트 프레임워크는 @Test 어노테이션을 사용해 테스트 메서드를 식별하고 실행한다.

        • 따라서 테스트 코드의 구조를 명확하게 하고, 테스트 실행을 간편하게 할 수 있다.

  • 나만의 어노테이션

    package com.example.springlibraryapp;
    
    import jakarta.validation.Constraint;
    import jakarta.validation.ConstraintValidator;
    import jakarta.validation.ConstraintValidatorContext;
    import jakarta.validation.Payload;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.FIELD, ElementType.METHOD})
    @Constraint(validatedBy = EmailValidator.class)
    public @interface ValidEmail {
        String message() default "올바른 emil 형식이 아닙니다.";
        Class<?>[] groups() default {};
        Class<? extends Payload>[] payload() default {};
    }
    
    public class EmailValidator implements ConstraintValidator<ValidEmail, String> {
        @Override
        public void initialize(ValidEmail constraintAnnotation) {}
    
        @Override
        public boolean isValid(String email, ConstraintValidatorContext context) {
            if (email == null) {
                return false;
            }
            return email.matches("^[A-Za-z0-9+_.-]+@([A-Za-z0-9.-]+\\\\\\\\.[A-Za-z]{2,})$");
        }
    }
    
    
    • @ValidEmail 어노테이션

      • @Retention(retentionPolicy.RUNTIME) : 런타임에도 유지된다는 것을 정의. 리플렉션을 통해 런타임에 어노티에션 정보를 조회할 수 있음을 의미한다.

      • @Target({ElemintType.FIELD, ElementType.METHOD}) : 필드와 메서드에만 적용될 수 있음을 나타낸다.

      • @Constraint(validatedBy = EmailValidator.class) : 유효성 검증 로직이 EmailValidator 클래스에 의해 정의된다는 것을 나타낸다.

      • @interface : 어노테이션을 정의할 때 사용되는 키워드이다.

      • String message() default : 유효성 검사를 통과하지 못할 경우 반환될 기본 메시지

      • Class<?>[] groups() default : 유효성 검사 그룹을 지정할 때 사용된다. 특정 그룹만 검사하도록 함.

      • Class<?extends Payload>[] payload() default : 클라이언트에게 유효성 검사 실패에 대한 추가적인 정보를 제공하는 매커니즘을 지정할 때 사용된다.

    • EmailValidator 클래스

      • implements ConstraintValidator<ValidEmail, String> : ConstraintValidator 인터페이스를 구현한다. ValidEmail은 지원하는 어노테이션 타입, Stirng은 검증할 데이터의 타입

      • public void initialize(ValidEmail constraintAnnotation) : 초기화시 호출되는 메서드.

      • public boolean isValid(String email, ConstraintValidatorContext context)

        • 실제 유효성 검사 로직을 구현한다.

        • 입력된 email이 null이 아니고, 주어진 정규식에 맞는지 확인하여 결과를 반환한다.

  • 회고

    스프링을 사용할 때 반드시 사용되는 것들이 어노테이션이다. 스프링에서

    사용되는 어노테이션들은 단순히 사용법으로 인식을 했기 때문에 아무런 생각 없이 사용을 하고 있었는데, 생각해보면 어노테이션 자체가 무엇인지도, 해당 어노테이션을 사용한다고 어떻게 빈으로 등록되는지도 이유를 모르고 있었다.

해당 과제를 통해 어노테이션 학습을 통해 메타 데이터를 스프링에 전달을 함으로써, 해당 클래스가 빈으로 등록되고 컨트롤러라는 것을 정의한다는 것은 알았지만, 어떻게해서 그렇게 되는 것인지는 방대한 스프링을 공부하면서 천천히 알아갈 예정이다.

또한, 어노테이션은 이미 작성된 것 이외에, @interface를 통해 커스텀 어노테이션을 만들 수 있다는 사실을 알게되었다. 그 전에는 스프링에서 제공하거나, Lombok에서 제공하는 어노테이션을 기계적으로 사용했는데, 커스텀 어노테이션을 통해 내가 필요로 하는 어노테이션을 직접 작성하여 코드를 간결하게 만들 수 있다는 것이 의미있게 다가왔다. 물론 그것을 어떻게 활용할지는 미래의 나에게 달려있는 문제이지만....

  • 미션 해결과정

    ChatGPT를 많이 활용했다... 개발자의 자리를 위협할 가능성이 있는 도구지만, 개인적으로는 최고의 선생님이자 최고의 도구라고 생각한다.

여튼, 나만의 어노테이션을 만들어야 한다는 미션이 주어졌고, 단순히 어노테이션을 정의하는 부분에서 끝낼 수 있긴 했지만, 개인적으로는 어짜피 시간을 투자하는거 나에게 의미가 있는 어노테이션을 만들자는 생각이 들었다. 어떠한 어노테이션을 만들까 고민을 했지만, 유효성 검증 이외에는 유의미한 응용 방법이 떠오르질 않았다. 유효성 검증에 대해 생각을 하니, 이메일 관련 유효성 검증 어노테이션을 만들면 좋을 것 같다는 생각으로 이어졌다.

검색을 통해 어노테이션을 정의하는 방법에 대해 알게되었고, 어노테이션을 이용해 커스텀 어노테이션의 설정을 하는 방법을 알게 되었고, 비즈니스 로직은 클래스를 통해 위임된다는 것도 알게되었다. 따라서 검증을 하는 클래스를 만들고, 정규식은 인터넷을 참고하여 이용을 해서 해당 과제를 수행할 수 있었다.

댓글을 작성해보세요.

채널톡 아이콘