Lombok을 사용하면 Getter나 Setter처럼 정말 많이 쓰는 작업을 자동화할 수 있어서 편하다.
테스트를 위해서 User 클래스 하나를 만들었다.
아래처럼 생겼다.
package com.test;
public class User {
private Long id;
private String name;
private String password;
public void update(String name,
String password) {
this.name = name;
this.password = password;
}
}
빌드해보자. 빌드를 하면 build 디렉터리 아래 class 파일이 생성된다.
원래는 알아볼 수 없게 생겼다.
IntelliJ IDEA 상에서 빌드된 파일을 클릭하면 디컴파일러를 통해서 원래 코드 모습을 확인할 수 있다.
public User() { } 생성자가 추가된 것을 볼 수 있다.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.test;
public class User {
private Long id;
private String name;
private String password;
public User() {
}
public void update(String name, String password) {
this.name = name;
this.password = password;
}
}
@Getter
같은 코드에 @Getter 추가했다.
package com.test;
import lombok.Getter;
@Getter
public class UserWithGetter {
private Long id;
private String name;
private String password;
public void update(String name,
String password) {
this.name = name;
this.password = password;
}
}
빌드된 클래스를 보자. get 메소드들이 추가된 걸 볼 수 있다. lombok이 자동으로 추가해주고 있다는 것을 확인할 수 있다.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.test;
public class UserWithGetter {
private Long id;
private String name;
private String password;
public UserWithGetter() {
}
public void update(String name, String password) {
this.name = name;
this.password = password;
}
public Long getId() {
return this.id;
}
public String getName() {
return this.name;
}
public String getPassword() {
return this.password;
}
}
@NoArgsConstructor
같은 코드에 @NoArgsConstructor 추가했다.
package com.test;
import lombok.NoArgsConstructor;
@NoArgsConstructor
public class UserWithNoArgsConstructor {
private Long id;
private String name;
private String password;
public void update(String name,
String password) {
this.name = name;
this.password = password;
}
}
빌드된 파일을 열어보자.
그냥 User 클래스와 아무런 차이가 없다.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.test;
public class UserWithNoArgsConstructor {
private Long id;
private String name;
private String password;
public void update(String name, String password) {
this.name = name;
this.password = password;
}
public UserWithNoArgsConstructor() {
}
}
@Builder
@Builder를 클래스에 추가해봤다.
package com.test;
import lombok.Builder;
@Builder
public class UserWithBuilder {
private Long id;
private String name;
private String password;
public void update(String name,
String password) {
this.name = name;
this.password = password;
}
}
모든 필드가 할당된 생성자가 생긴 것을 확인할 수 있다.
아무 필드도 없는 생성자는 없는 것을 알 수 있다.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.test;
public class UserWithBuilder {
private Long id;
private String name;
private String password;
public void update(String name, String password) {
this.name = name;
this.password = password;
}
UserWithBuilder(Long id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
public static UserWithBuilder.UserWithBuilderBuilder builder() {
return new UserWithBuilder.UserWithBuilderBuilder();
}
public static class UserWithBuilderBuilder {
private Long id;
private String name;
private String password;
UserWithBuilderBuilder() {
}
public UserWithBuilder.UserWithBuilderBuilder id(Long id) {
this.id = id;
return this;
}
public UserWithBuilder.UserWithBuilderBuilder name(String name) {
this.name = name;
return this;
}
public UserWithBuilder.UserWithBuilderBuilder password(String password) {
this.password = password;
return this;
}
public UserWithBuilder build() {
return new UserWithBuilder(this.id, this.name, this.password);
}
public String toString() {
return "UserWithBuilder.UserWithBuilderBuilder(id=" + this.id + ", name=" + this.name + ", password=" + this.password + ")";
}
}
}
이 경우 builder를 쓰기 위해서는 반드시 세 필드를 할당해야만 한다. 아주 번거로워진다.
builder 자체를 쓰는 의미가 없어진다.
@Builder 메소드에 쓰기
필요한 메소드에만 추가해봤다. getter가 없기 때문에 name과 password를 public으로 했다.
package com.test;
import lombok.Builder;
public class UserWithMethodBuilder {
private Long id;
public String name;
public String password;
@Builder
public void update(String name,
String password) {
this.name = name;
this.password = password;
}
}
빈 생성자가 추가된 것을 볼 수 있다.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.test;
public class UserWithMethodBuilder {
private Long id;
public String name;
public String password;
public UserWithMethodBuilder() {
}
public void update(String name, String password) {
this.name = name;
this.password = password;
}
public UserWithMethodBuilder.VoidBuilder builder() {
return new UserWithMethodBuilder.VoidBuilder();
}
public class VoidBuilder {
private String name;
private String password;
VoidBuilder() {
}
public UserWithMethodBuilder.VoidBuilder name(String name) {
this.name = name;
return this;
}
public UserWithMethodBuilder.VoidBuilder password(String password) {
this.password = password;
return this;
}
public void build() {
UserWithMethodBuilder.this.update(this.name, this.password);
}
public String toString() {
return "UserWithMethodBuilder.VoidBuilder(name=" + this.name + ", password=" + this.password + ")";
}
}
}
쓸모없다. 아래처럼 테스트 해보면 john이 나온다.
UserWithMethodBuilder userWithMethodBuilder = new UserWithMethodBuilder();
userWithMethodBuilder.builder().name("john").build();
System.out.println(userWithMethodBuilder.name);
@Getter와 메소드에 @Builder 같이 쓰기
Builder를 쓰려면 Getter를 같이 쓰는 게 맞다. 필드 public으로 하기보다는.
package com.test;
import lombok.Builder;
import lombok.Getter;
@Getter
public class UserWithGetterAndMethodBuilder {
private Long id;
private String name;
private String password;
@Builder
public void update(String name,
String password) {
this.name = name;
this.password = password;
}
}
아래처럼 클래스가 생성된다.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.test;
public class UserWithGetterAndMethodBuilder {
private Long id;
private String name;
private String password;
public UserWithGetterAndMethodBuilder() {
}
public void update(String name, String password) {
this.name = name;
this.password = password;
}
public UserWithGetterAndMethodBuilder.VoidBuilder builder() {
return new UserWithGetterAndMethodBuilder.VoidBuilder();
}
public Long getId() {
return this.id;
}
public String getName() {
return this.name;
}
public String getPassword() {
return this.password;
}
public class VoidBuilder {
private String name;
private String password;
VoidBuilder() {
}
public UserWithGetterAndMethodBuilder.VoidBuilder name(String name) {
this.name = name;
return this;
}
public UserWithGetterAndMethodBuilder.VoidBuilder password(String password) {
this.password = password;
return this;
}
public void build() {
UserWithGetterAndMethodBuilder.this.update(this.name, this.password);
}
public String toString() {
return "UserWithGetterAndMethodBuilder.VoidBuilder(name=" + this.name + ", password=" + this.password + ")";
}
}
}
아래처럼 테스트를 해보면 john을 얻을 수 있다.
UserWithGetterAndMethodBuilder userWithGetterAndMethodBuilder = new UserWithGetterAndMethodBuilder();
userWithGetterAndMethodBuilder.builder().name("john").build();
System.out.println(userWithGetterAndMethodBuilder.getName());
@AllArgsConstructor
@AllArgsConstructor을 클래스에 추가하자.
package com.test;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
public class UserWithAllArgsConstructor {
private Long id;
private String name;
private String password;
public void update(String name,
String password) {
this.name = name;
this.password = password;
}
}
단어 뜻 그대로 모든 arguments 필드가 포함된 생성자가 추가된다.
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//
package com.test;
public class UserWithAllArgsConstructor {
private Long id;
private String name;
private String password;
public void update(String name, String password) {
this.name = name;
this.password = password;
}
public UserWithAllArgsConstructor(Long id, String name, String password) {
this.id = id;
this.name = name;
this.password = password;
}
}
이렇게 할 경우 문제는 public이라 해당 클래스에 어떤 필드가 있는지 모두 노출된다는 점이다.
또 데이터베이스 Entity라면 보통 id는 auto increment 설정으로 자동 증가하게 되는데 id까지 설정할 수 있게 된다.
그래서 @AllArgsConstructor 편하지만 되도록 쓰지 않는게 좋다.
결론
@Getter와 특정 메소드에 @Builder를 쓰는 방식이 적절하다.
@Getter의 경우에 특정 필드만 쓸 수도 있다. 그렇게 해서 @Builder를 통해서 할당할 수는 있지만 값에 접근은 안 되게 할 수도 있다.