어노테이션 들여다보기 - 2

YJS·2023년 9월 8일
0

Spring Boot 탐구

목록 보기
3/11

😖문제 상황

엔티티에서 @NoArgsConstructor 어노테이션을 사용해서 생성자를 만들었는데 코드를 실행해보니 mapper 인터페이스에서 기본 생성자에 접근을 못해서 에러가 나는 이슈가 있었다.

문제 코드 )

// entity
@Getter
@Entity
@Table(name="promotion_object")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@EntityListeners(AuditingEntityListener.class)
@DynamicInsert
public class Object{
	...
}


//mapper
@Mapper(componentModel = "spring")
public interface ObjectMapper extends GenericMapper<ObjectInfo, Object>{}

//service
@Service
@RequiredArgsConstructor
public class ObjectService{
	private final ObjectMapper objectMapper;
    ...
}

🤓문제 해결 과정

step1. mapper에서 어떤 경우에 생성자를 호출하는지 확인했다.

생성자에 접근할 때 주로 사용되는 패턴 중 하나는 생성자 주입. 이는 스프링과 같은 의존성 주입(Dependency Injection) 프레임워크에서 많이 사용됨. 이 패턴에서는 생성자를 통해 의존성을 주입받는다.
위 코드에서 ObjectMapper 인터페이스의 구현체가 Spring에 의해 주입되고, 이것을 사용하여 데이터베이스와 상호 작용.

매퍼 인터페이스와 생성자 간의 관계는 주로 프레임워크나 라이브러리, 그리고 사용 중인 의존성 주입 패턴에 따라 달라집니다. 일반적으로 매퍼 인터페이스 내에서 생성자 호출보다는 매퍼 메서드를 통해 객체를 생성하고 매핑하는 것이 일반적입니다. 생성자 주입은 주로 의존성 관리를 위해 사용되며, 생성자가 private이 아니라면 Spring과 같은 프레임워크에서 사용됩니다.

step2. 기본 생성자에 접근하지 못하는 원인을 찾아봤다.

(Object엔티티에서 어노테이션이 제대로 세팅되었는지 체크했고 NoArgsConstructor를 사용한 것을 확인했다.)

step3. 생성자의 접근 권한을 확인했다.

🧐문제의 원인 파악

문제의 원인은 object entity 클래스의 어노테이션에 있었다. 해당 엔티티에서 생성자를 NoArgsConstructor(access = AccessLevel.PROTECTED)로 만들고 있었는데 accesslevel을 protected로 했기 때문에 생성자가 아무것도 없어서 에러가 났던 것이다. 따라서 protected가 아닌 public으로 접근 제한자를 변경했더니 오류가 해결됐다

// entity
@Getter
@Entity
@Table(name="promotion_object")
@NoArgsConstructor
@EntityListeners(AuditingEntityListener.class)
@DynamicInsert
public class Object{
	...
}

그렇다면 자바의 접근 제한자란 무엇인가?

접근 제한자란
접근 제한자(Visibility Modifier)는 클래스, 메서드, 필드 등의 멤버에 대한 접근 권한을 지정하는 키워드입니다

-public 접근 제한: public 접근 제한은 모든 패키지에서 아무런 제한 없이 생성자를 호출할 수 있도록 합니다.

-protected 접근 제한: protected 접근 제한은 default 접근 제한과 마찬가지로 같은 패키지에 속하는 클래스에서 생성자를 호출할 수 있도록 합니다. 차이점으로 다른 패키지에 속한 클래스가 해당 클래스의 자식(child) 클래스라면 생성자를 호출할 수 있습니다.

-default 접근 제한: default 접근 제한은 같은 패키지에서는 아무런 제한 없이 생성자를 호출할 수 있으나, 다른 패키지에서는 생성자를 호출할 수 없도록 합니다.

-private 접근 제한: private 접근 제한은 동일한 패키지이건 다른 패키지이건 상관없이 생성자를 호출하지 못하도록 제한합니다. 오로지 클래스 내부에서만 생성자를 호출할 수 있고 객체를 만들 수 있습니다.

🤓 생성자를 만들어주는 어노테이션 뿌시기 🤓

1) @NoArgsConstructor 어노테이션
@NoArgsConstructor 어노테이션은 기본 생성자를 자동으로 생성합니다. 이 생성자는 인자를 받지 않고 객체를 초기화합니다.

@NoArgsConstructor
public class MyClass {
    private int id;
    private String name;
}

2) @RequiredArgsConstructor 어노테이션
@RequiredArgsConstructor 어노테이션은 클래스 내부의 final 필드 또는 @NonNull 어노테이션이 지정된 필드를 대상으로 생성자를 자동으로 생성합니다. 이 생성자는 해당 필드를 인자로 받아 초기화합니다.

@RequiredArgsConstructor
public class MyClass {
    private final int id;
    private final String name;
}

3) @AllArgsConstructor 어노테이션
@AllArgsConstructor 어노테이션은 클래스 내부의 모든 필드를 대상으로 생성자를 자동으로 생성합니다. 이 생성자는 모든 필드를 인자로 받아 초기화합니다.

@AllArgsConstructor
public class MyClass {
    private int id;
    private String name;
}

4) @Data 어노테이션
@Data 어노테이션은 클래스에 추가되며, 클래스 내의 필드를 대상으로 Getter, Setter, equals(), hashCode(), toString() 메서드를 자동으로 생성합니다. 이것은 주로 데이터 클래스로 사용되며, 간단한 데이터 저장과 관련된 클래스에서 편의성을 제공합니다.

@Data
public class MyClass {
    private int id;
    private String name;
}

5) @Builder 어노테이션
객체를 생성할 때 빌더(Builder) 패턴을 자동으로 생성해주는 역할을 합니다. 빌더 패턴은 객체 생성 과정을 가독성 있게 만들고 여러 옵션을 설정하기 쉽게 해주는 디자인 패턴입니다.

@Builder 어노테이션을 사용하는 경우, 해당 클래스는 다음과 같은 특성을 가집니다:

빌더 클래스 생성: @Builder 어노테이션을 사용한 클래스는 빌더 클래스를 자동으로 생성합니다. 이 빌더 클래스를 사용하면 객체를 생성하고 필드를 설정하는 과정이 간단하고 가독성 있게 됩니다.

선택적 필드 설정: 빌더 패턴을 사용하면 필드 중 일부만 설정하고 나머지는 기본값으로 남겨둘 수 있습니다. 이는 객체 생성 시 선택적인 옵션을 제공할 때 특히 유용합니다.

불변성 유지: @Builder를 사용하면 생성된 객체는 불변(Immutable)할 수 있으며, 한 번 생성된 후에는 변경할 수 없습니다. 이는 객체의 안정성과 스레드 안전성을 증가시킵니다.

import lombok.Builder;
import lombok.Getter;

@Builder
@Getter
public class Person {
    private String name;
    private int age;
}

Person person = Person.builder()
    .name("John")
    .age(30)
    .build();

⭐️tip!
**@NoArgsConstructor로 기본 생성자 만들고 필요 시에 Builder패턴으로 필요한 필드들만 추가해서 객체 생성해서 사용하기도 함!

**@RequiredArgsConstructor의 서비스 클래스에서의 사용:
서비스 클래스는 주로 비즈니스 로직을 처리하고 데이터 처리 작업을 수행합니다. @RequiredArgsConstructor 어노테이션을 서비스 클래스에서 사용하면 해당 클래스에서 필요한 의존성을 주입받는 생성자를 자동으로 생성합니다. 이를 통해 의존성 주입을 쉽게 처리할 수 있습니다.

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;

    // ...
}

@RequiredArgsConstructor 어노테이션은 코드를 간결하게 만들고 의존성 주입을 편리하게 처리할 수 있도록 도와줍니다. 따라서 서비스 클래스에서도 사용되며, 스프링과 같은 의존성 주입 프레임워크와 함께 사용할 때 특히 유용합니다.

profile
우당탕탕 개발 일기

0개의 댓글