Spring

[Lombok] Lombok에서 생성자 Annotation에 대해 알아보자

hanrabong 2022. 10. 29. 08:26

 

 

 

 Spring 을 이용해서 프로젝트를 하면 Annotation을 이용해서 쉽게 코드를 작성할 수 있는 lombok 라이브러리를 사용하곤 했습니다. 수 많은 Annotation이 있다보니 정확히 내부적으로 어떻게 동작하는지도 모르고 종종 사용하였습니다. spring의 생성자 주입과 관련된 생성자 annotation에 대해서 헷갈려 정리하려고 합니다.

 

 

 

생성자 관련 Annotation 종류


 Lombok에서 생성자 관련 Annotaion은 3가지가 있습니다.

@AllArgsConstructor

@RequiredArgsConstructor

@NoArgsConstructor

 하나씩 어떤 조건의 생성자를 만들어주는지 확인해 보겠습니다.

 

 

 

@AllArgsConstructor


 영어 뜻 그대로 모든 argument를 가지고 생성자를 만들어 준다는 것을 의미합니다. 여기서 argument는 클래스가 가지고 있는 field라고 생각하면 됩니다. 코드로 예를 들어보겠습니다.

 

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

 

위의 코드를 Lombok Annotation을 쓰지 않고서 밑의 코드와 같이 표현할 수 있습니다.

 

public class Person {
	private String name;
	private int age;
    
	Person(String name, int age) {
		this.name = name;
		this.age = age;
	}
}

 

실제로 생성자 만드는 코드가 생성이 되는지 확인해 보겠습니다. build 폴더에서 해당 코드를 찾아서 디컴파일 해주면 코드를 확인할 수 있습니다. 저의 경우 코드를 확인하면 다음과 같이 나옵니다.

 

public class Person {
	private String name;
	private int age;

	public Person(final String name, final int age) {
		this.name = name;
		this.age = age;
	}
}

@AllArgsConstructor로 인하여 모든 필드를 초기화해주는 생성자가 만들어집니다.

 

@AllArgsConstructor의 경우 모든 필드를 이용하여 생성자를 만들고 싶을 때 사용하는 Annotation입니다.

 

 

 

@RequiredArgsConstructor


 영어 뜻처럼 필요한 field를 가지고 생성자를 만들어 준다는 것을 의미합니다. 그럼 여기서 필요한 field란 무엇을 의미하는 것일까요?

 

Lombok document를 보면 이렇게 나와있습니다.

@RequiredArgsConstructor generates a constructor with 1 parameter for each field that requires special handling. All non-initialized final fields get a parameter, as well as any fields that are marked as @NonNull that aren't initialized where they are declared. For those fields marked with @NonNull, an explicit null check is also generated. The constructor will throw a NullPointerException if any of the parameters intended for the fields marked with @NonNull contain null. The order of the parameters match the order in which the fields appear in your class.

 

 위의 글을 보면 final field와 @NonNull annotation이 마크된 field를 포함해서 생성자가 만들어진다는 것을 알 수 있습니다. final field의 경우에는 생성자를 이용하여 초기화해줘야 하기에@RequiredArgsConstrcutor로 인해 만들어진 생성자에 포함이 되어야 합니다. 그렇다면 @NonNull은 왜 포함을 시켜줘야 할까요? 

 

@NonNull도 lombok 라이브러리에 있는 annotation 중 하나입니다. 말 그대로 값이 null이 들어가면 안된다는 뜻입니다. 만약에 생성자에 해당 field가 없는데 접근을 하면 값이 null로 나오기에 생성자에서 초기화를 해줘야 합니다.

코드로 자세히 알아보겠습니다.

 

@RequiredArgsConstructor
public class Person {
	private final String name;
	public final int age;
	protected final String address;
	private String phone;
}

 위의 코드를 보면 @RequiredArgsConstructor 가 있으니 final이 붙은 field를 이용하여 생성자가 만들어질 것입니다. build 폴더에서 해당 class를 decompile하여 확인해보겠습니다.

 

public class Person {
	private final String name;
	public final int age;
	protected final String address;
	private String phone;

	public Person(final String name, final int age, final String address) {
		this.name = name;
		this.age = age;
		this.address = address;
	}
}

 final 제어자가 붙은 field로만 이루어진 생성자가 만들어진 것을 볼 수 있습니다.

 

그럼 이번에 @NonNull를 이용하여 코드를 짜서 확인해 보겠습니다.

@RequiredArgsConstructor
public class Person {
	private String name;
	public final int age;
	protected String address;
	@NonNull
	private String phone;
}

 위의 코드를 보면 age필드에 final 제어자와 phone에 @NonNull이 마크되어 있습니다. 그럼 해당 2개의 필드로 이루어진 생성자가 생성되는 것을 예상할 수 있습니다. 마찬가지로 build폴더에서 해당 파일을 decompile해서 확인해 보겠습니다.

 

public class Person {
	private String name;
	public final int age;
	protected String address;
	private @NonNull String phone;

	public Person(final int age, final @NonNull String phone) {
		if (phone == null) {
			throw new NullPointerException("phone is marked non-null but is null");
		} else {
			this.age = age;
			this.phone = phone;
		}
	}
}

 위의 코드와 같이 age와 phone field만을 이용하여 생성자가 생성된 것을 볼 수 있습니다.

 

@RequiredArgsConstructor의 경우 final, @NonNull 필드가 있을 때 사용하면 자동으로 생성자를 생성해줍니다. 따라서 직접 생성자 코드를 작성하지 않아도되고 생성자 코드를 작성해야하는데 까먹었을 때도 위의 annotation을 사용하면 오류가 발생하지 않습니다. 하지만 그렇다고 final, @NonNull 없이 RequiredArgsConstructor annotation을 사용하면 생성자도 만들어 주지도 않는데 불필요한 코드가 존재하기에 무분별하게 사용해서는 안됩니다.

 

 

 

@NoArgsConstructor


 영어 뜻 그대로 아무런 field없이 생성자를 만들어 준다는 것을 의미합니다. 위와 마찬가지로 코드로 예를 들어보겠습니다.

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

 

 위의 코드를 Lombok Annotation을 쓰지 않고서는 밑의 코드와 같이 표현할 수 있습니다. 생성자가 없는데 어떻게 똑같은지 궁금할 수 있습니다. Class에 어떠한 생성자도 존재하지 않을 시에 compiler가 default constructor를 생성해 줍니다.

 

public class Person {
	private String name;
	private int age;
}

실제로 위의 두 코드가 똑같은지 빌드 파일을 확인해 보겠습니다. 

 

public class Person {
	private String name;
	private int age;

	public Person() {
	}
}

빌드 파일을 확인하면 위의 두 코드 전부 이렇게 decompile이 됩니다. 

 

 

그럼 여기서 기본 생성자를 만들어 주는데 왜 @NoArgsConstructor를 사용한지 궁금증이 들 수도 있습니다.

 

 아무런 생성자가 없을 때는 기본적으로 만들어 주지만, 생성자가 이미 존재하거나 @AllArgsConstructor@RequiredArgsConstructor와 같이 사용할 때도 당연히 생성자가 존재하기에 @NoArgsConstructor를 이용하여 쉽게 아무 field도 갖고 있지 않은 생성자를 만들어 줄 수 있습니다.

 

 

 

 

 

※ 궁금한 사항이나 잘못된 점 댓글 부탁드립니다.

 

 

참고자료

https://projectlombok.org/features/constructor

 

@NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor

 

projectlombok.org