Lombok 활용하기
Gradle 설정
build.gradle에 다음 롬복설정을 추가해준다.
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
compileOnly 'org.projectlombok:lombok:1.18.20'
annotationProcessor 'org.projectlombok:lombok:1.18.20'
testCompileOnly 'org.projectlombok:lombok:1.18.20'
testAnnotationProcessor 'org.projectlombok:lombok:1.18.20'
}
추가후에 반드시 아래 설정을 해줘야한다.
Preferences -> Compiler -> Annotation Processors
Enable annotation processing을 반드시 설정해줘야한다.
@Getter / @Setter
접근자(getXxx()
)와 설정자(setXxx()
)를 자동으로 생성해준다.
package dh0023.springcore.member.domain;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class Member {
private Long id;
private String name;
private Grade grade;
}
다음과 같이 자동으로 getter와 setter가 생성된 것을 확인할 수 있다.
생성자 자동 생성
@NoArgsConstructor
파라미터가 없는 생성자를 자동으로 생성해준다.
@AllArgsConstructor
모든 필드 값을 파라미터로 받는 생성자를 생성해준다.
@NoArgsConstructor
@AllArgsConstructor
public class Member {
private Long id;
private String name;
private Grade grade;
}
@RequiredArgsConstructor
@RequiredArgsConstructor
어노테이션은 final
이나 @NonNull
인 필드 값만 파라미터로 받는 생성자를 만들어준다.
이렇게 생성하면, 코드가 훨씬 깔끔해지고 간편한 것을 확인할 수 있다.
@Component
public class OrderServiceImpl implements OrderService{
// final은 반드시 값이 있어야한다.
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
public OrderServiceImpl(MemberRepository memberRepository, DiscountPolicy discountPolicy) {
this.memberRepository = memberRepository;
this.discountPolicy = discountPolicy;
}
}
위와 같이 생성자를 직접 만들어줄 필요 없이 해당 어노테이션만 별도로 설정해주면 된다.
@Component
@RequiredArgsConstructor
public class OrderServiceImpl implements OrderService{
// final은 반드시 값이 있어야한다.
private final MemberRepository memberRepository;
private final DiscountPolicy discountPolicy;
}
intelliJ에서 command + F12
로 해당 클래스의 메서드와 변수를 확인할 수 있는데, 아래와 같이 생성자가 생성된 것을 확인할 수 있다.
@ToString
toString()
메소드도 lombok의 @ToString
어노테이션으로 간단하게 생성할 수 있다. 또한, exclude
옵션으로 특정 필드를 제외할 수 있다.
@Getter
@Setter
@ToString(exclude = "grade")
@AllArgsConstructor
public class Member {
private Long id;
private String name;
private Grade grade;
}
public class LombokTest {
@Test
@DisplayName("toString() 테스트")
void getToString() {
Member member = new Member(1L, "test123", Grade.VIP);
System.out.println(member);
}
}
Member(id=1, name=test123)
Process finished with exit code 0
exclude
에 포함된 필드를 제외하고 전체 출력되는 것을 확인할 수 있다.
@Builder
@Builder
로 단순하게 빌더를 생성할 수 있다.
public class Item {
private final String itemCd; // 필수
private final String itemNm; // 필수
private final String ctgId; // 필수
private final BigDecimal price; // 선택
private final String sellTypeCd; // 선택
public static class Builder {
private final String itemCd; // 필수
private final String itemNm; // 필수
private final String ctgId; // 필수
// 선택적 매개변수는 default 값으로 초기화
private BigDecimal price = BigDecimal.ZERO;
private String sellTypeCd = "00";
public Builder(String itemCd, String itemNm, String ctgId){
this.itemCd = itemCd;
this.itemNm = itemNm;
this.ctgId = ctgId;
}
public Builder price(BigDecimal price){
this.price = price;
return this;
}
public Builder sellTypeCd(String sellTypeCd){
this.sellTypeCd = sellTypeCd;
return this;
}
public Item build(){
return new Item(this);
}
}
private Item(Builder builder){
itemCd = builder.itemCd;
itemNm = builder.itemNm;
ctgId = builder.ctgId;
price = builder.price;
sellTypeCd = builder.sellTypeCd;
}
}
다음과 같이 Item.Builder를 단순히 @Builder
어노테이션 만으로 구현할 수 있다.
@Builder
public class Item {
private final String itemCd; // 필수
private final String itemNm; // 필수
private final String ctgId; // 필수
private final BigDecimal price; // 선택
private final String sellTypeCd; // 선택
}
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package ch2.dahye.item2;
import java.math.BigDecimal;
public class Item {
private final String itemCd;
private final String itemNm;
private final String ctgId;
private final BigDecimal price;
private final String sellTypeCd;
Item(String itemCd, String itemNm, String ctgId, BigDecimal price, String sellTypeCd) {
this.itemCd = itemCd;
this.itemNm = itemNm;
this.ctgId = ctgId;
this.price = price;
this.sellTypeCd = sellTypeCd;
}
public static Item.ItemBuilder builder() {
return new Item.ItemBuilder();
}
public static class ItemBuilder {
private String itemCd;
private String itemNm;
private String ctgId;
private BigDecimal price;
private String sellTypeCd;
ItemBuilder() {
}
public Item.ItemBuilder itemCd(String itemCd) {
this.itemCd = itemCd;
return this;
}
public Item.ItemBuilder itemNm(String itemNm) {
this.itemNm = itemNm;
return this;
}
public Item.ItemBuilder ctgId(String ctgId) {
this.ctgId = ctgId;
return this;
}
public Item.ItemBuilder price(BigDecimal price) {
this.price = price;
return this;
}
public Item.ItemBuilder sellTypeCd(String sellTypeCd) {
this.sellTypeCd = sellTypeCd;
return this;
}
public Item build() {
return new Item(this.itemCd, this.itemNm, this.ctgId, this.price, this.sellTypeCd);
}
public String toString() {
return "Item.ItemBuilder(itemCd=" + this.itemCd + ", itemNm=" + this.itemNm + ", ctgId=" + this.ctgId + ", price=" + this.price + ", sellTypeCd=" + this.sellTypeCd + ")";
}
}
}
상속 받은 클래스 Builder 구현
@Getter
@AllArgsConstructor
public class Parent {
private final String parentName;
private final int parentAge;
}
@Getter
public class Child extends Parent {
private final String childName;
private final int childAge;
@Builder
public Child(String parentName, int parentAge, String childName, int childAge) {
super(parentName, parentAge);
this.childName = childName;
this.childAge = childAge;
}
}
상속받은 클래스에서는 다음과 같이 생성자에 Builder 어노테이션을 추가해 Builder를 구현할 수 있다.
public class Child extends Parent {
private final String childName;
private final int childAge;
public Child(String parentName, int parentAge, String childName, int childAge) {
super(parentName, parentAge);
this.childName = childName;
this.childAge = childAge;
}
public static Child.ChildBuilder builder() {
return new Child.ChildBuilder();
}
public String getChildName() {
return this.childName;
}
public int getChildAge() {
return this.childAge;
}
public static class ChildBuilder {
private String parentName;
private int parentAge;
private String childName;
private int childAge;
ChildBuilder() {
}
public Child.ChildBuilder parentName(String parentName) {
this.parentName = parentName;
return this;
}
public Child.ChildBuilder parentAge(int parentAge) {
this.parentAge = parentAge;
return this;
}
public Child.ChildBuilder childName(String childName) {
this.childName = childName;
return this;
}
public Child.ChildBuilder childAge(int childAge) {
this.childAge = childAge;
return this;
}
public Child build() {
return new Child(this.parentName, this.parentAge, this.childName, this.childAge);
}
public String toString() {
return "Child.ChildBuilder(parentName=" + this.parentName + ", parentAge=" + this.parentAge + ", childName=" + this.childName + ", childAge=" + this.childAge + ")";
}
}
}
다음과 같이 부모 클래스의 필드까지 모두 Builder 내부에 구현된 것을 확인할 수 있다.
Child child = Child.builder()
.parentName("Andrea")
.parentAge(38)
.childName("Emma")
.childAge(6)
.build();
@SuperBuilder
Lombok 1.18.2 이후부터는 @SuperBuilder
어노테이션으로 상속되는 클래스의 Builder를 생성할 수 있다.
@SuperBuilder
public class Parent {
private final String parentName;
private final int parentAge;
}
@SuperBuilder
public class Child extends Parent {
private final String childName;
private final int childAge;
}
public class Parent {
private final String parentName;
private final int parentAge;
protected Parent(Parent.ParentBuilder<?, ?> b) {
this.parentName = b.parentName;
this.parentAge = b.parentAge;
}
public static Parent.ParentBuilder<?, ?> builder() {
return new Parent.ParentBuilderImpl();
}
private static final class ParentBuilderImpl extends Parent.ParentBuilder<Parent, Parent.ParentBuilderImpl> {
private ParentBuilderImpl() {
}
protected Parent.ParentBuilderImpl self() {
return this;
}
public Parent build() {
return new Parent(this);
}
}
public abstract static class ParentBuilder<C extends Parent, B extends Parent.ParentBuilder<C, B>> {
private String parentName;
private int parentAge;
public ParentBuilder() {
}
protected abstract B self();
public abstract C build();
public B parentName(String parentName) {
this.parentName = parentName;
return this.self();
}
public B parentAge(int parentAge) {
this.parentAge = parentAge;
return this.self();
}
public String toString() {
return "Parent.ParentBuilder(parentName=" + this.parentName + ", parentAge=" + this.parentAge + ")";
}
}
}
public class Child extends Parent {
private final String childName;
private final int childAge;
protected Child(Child.ChildBuilder<?, ?> b) {
super(b);
this.childName = b.childName;
this.childAge = b.childAge;
}
public static Child.ChildBuilder<?, ?> builder() {
return new Child.ChildBuilderImpl();
}
private static final class ChildBuilderImpl extends Child.ChildBuilder<Child, Child.ChildBuilderImpl> {
private ChildBuilderImpl() {
}
protected Child.ChildBuilderImpl self() {
return this;
}
public Child build() {
return new Child(this);
}
}
public abstract static class ChildBuilder<C extends Child, B extends Child.ChildBuilder<C, B>> extends ParentBuilder<C, B> {
private String childName;
private int childAge;
public ChildBuilder() {
}
protected abstract B self();
public abstract C build();
public B childName(String childName) {
this.childName = childName;
return this.self();
}
public B childAge(int childAge) {
this.childAge = childAge;
return this.self();
}
public String toString() {
String var10000 = super.toString();
return "Child.ChildBuilder(super=" + var10000 + ", childName=" + this.childName + ", childAge=" + this.childAge + ")";
}
}
}
ChildBuilder는 ParentBuilder를 상속받고 있는것을 볼 수 있다.
참고
Last updated