java 개발자에 있어 lombok은 아주 좋은 라이브러리이다. 어노테이션 하나로 자동으로 바이트코드를 만들어주니 더 할 것이 없는 라이브러리이다. 다른 언어들은 언어 자체에서 지원해주긴 하지만..
필자도 아주아주 잘 쓰지는 못하지만 필자가 아는 것만큼 포스팅을 해보자!
@Data
lombok을 사용한다면 제일 많이 사용하는 어노테이션이다. 이 어노테이션은 다재다능한 기능이다. 사용하는 사람은 알겠지만 getter, setter, toString, hasCode, equals, constructor 등 많은 부분을 자동으로 생성해준다.
각각 부분적으로는 밑에서 설명하도록 하겠다.
@Data
어노테이션에는 속성이 한개 있는데
staticConstructor
라는 속성이다. 말그대로 static한 생성자? 를 만들어 주는 것이다.
@Data(staticConstructor = "of")
public class DataObject {
private final Long id;
private String name;
}
위와 같이 선언한다면 다음과 같이 사용가능하다.
DataObject dataObject = DataObject.of(1L);
id
경우에는 final이라 필수 생성자에 포함되어 있다. 만일 위와 같이 사용한다면
new
로 생성할 수 없다.
DataObject dataObject2 = new DataObject(); // compile error
위와 같이 new 를 이용해 생성할 시에는 컴파일 에러가 발생한다.
위의 여러 메서드를 제외하고 한개의 메서드가 더 생성이 되는데 그 메서드는
canEqual
이라는 메서드이다. 해당 메서드의 역할은
instanceof
로 타입정도만 체크 한다. 하지만 메서드의 접근제한자는
protected
이다. 필자도 사용할 일이 없었다.
XXXXArgsConstructor
위의 어노테이션은 생성자를 생성해주는 어노테이션이다. 생성자를 생성해주는 어노테이션은 3가지가 있다. 첫 번째는 디폴트 생성자를 생성해주는
@NoArgsConstructor
두 번째는 모든 필드의 생성자를 생성해주는
@AllArgsConstructor
마지막으로 필수 생성자를 생성해주는
@RequiredArgsConstructor
가 있다.
속성에는 여러가지 있는데 자주 사용할 법한 속성들만 설명하겠다. (필자가 아는 것 만..)
1.
staticName
: 위에서
@Data
어노테이션의
staticConstructor
와 동일하다. static한 생성자를 만들어 준다.
2.
access
: 접근제한을 할 수 있다.
PUBLIC
,
MODULE
,
PROTECTED
,
PACKAGE
,
PRIVATE
등으로 설정가능 하다.
3.
onConstructor
: 생성자에 어노테이션을 작성할 수 있다.
공통적인 속성으로는 위와 같이 3가지가 존재한다.
@RequiredArgsConstructor(staticName = "of", onConstructor = @__(@Inject))
public class ConstructorObject {
private final Long id;
private final String name;
}
만약 위와 같은 어노테이션을 작성할 경우에는 다음과 같은 코드가 나올 것이라고 예상해본다.
class ConstructorObjectNot {
private final Long id;
private final String name;
@Inject
private ConstructorObjectNot(Long id, String name) {
this.id = id;
this.name = name;
}
public static ConstructorObjectNot of(Long id, String name) {
return new ConstructorObjectNot(id, name);
}
}
staticName
가 존재해
access
는 별루 의미가 없어 사용하지 않았다.
@Getter와 @Setter
어노테이션 이름 그대로 getter와 setter를 생성해준다. 클래스 레벨에도 사용가능하며 필드 레벨에도 사용가능하다.
공통 속성으로는
value
,
onMethod
속성이 존재한다.
value
의 경우에는 접근 제한을 할 수 있으며
onMethod
메서드의 어노테이션을 작성할 수 있다.
public class GetSetObject {
@Getter(value = AccessLevel.PACKAGE, onMethod = @__({@NonNull, @Id}))
private Long id;
}
만약 위와 같은 코드를 작성하였을 경우에는 다음과 같은 코드가 작성 될 것이다.
class GetSetObjectOnMethod {
private Long id;
@Id
@NonNull
Long getId() {
return id;
}
}
물론 @Setter 어노테이션에도 onMethod를 사용할 수 있다.
@Setter(onMethod = @__({@NotNull}))
그리고 @Getter, @Setter 각각이 다른 속성들을 한개씩 가지고 있는데. @Getter인 경우에는
lazy
속성이고 @Setter의 경우에는
onParam
이라는 속성이다.
@Getter 의 lazy 속성은 속성명 그대로 필드의 값은 지연시킨다는 것이다.
@Getter(value = AccessLevel.PUBLIC, lazy = true)
private final String name = expensive();
private String expensive() {
return "wonwoo";
}
lazy가 true일때는 무조건 final 필드어야만 한다. lazy 속성이 false 일 경우에는 객체를 생성할 때
expensive()
메서드를 호출하지만 속성이 true일 경우에는 getName() 메서드를 호출할 때
expensive()
메서드를 호출 한다.
다음은 @Setter의 onParam 속성이다. 이 속성은 파라미터의 어노테이션을 작성할 수 있는 속성이다.
@Setter(onParam = @__(@NotNull))
private Long id;
만약 다음과 같은 코드가 있을 경우에는 아래와 같은 코드가 작성될 것이라고 판단된다.
class GetSetObjectOnParam {
private Long id;
public void setId(@NotNull Long id) {
this.id = id;
}
}
아주 간단한 코드이다. (물론 만든 사람은 아니겠지만..)
IDEA에서는 onParam
과 onMethod
에 @Column 어노테이션의 속성을 넣으면 잘 동작하지 않는다. onParam 은 파라미터에 적용되니 @Column 자체가 들어 갈 수 없으니 그렇다 쳐도 onMethod는 왜안되는지.. 플러그인 문제인듯 싶다.
@EqualsAndHashCode 와 @ToString
@EqualsAndHashCode
어노테이션은 이름 그대로 hashcode와 equals를 생성해주는 어노테이션이고,
@ToString
도 마찬가지로
toString()
메서드를 생성해주는 어노테이션이다.
공통 속성으로는 4가지 있는데
exclude
,
of
,
callSuper
,
doNotUseGetters
가 존재 한다. exclude는 제외시킬 변수명을 작성하면 되고 of는 포함시킬 변수명을 작성하면 된다. callSuper 속성은 상위 클래스의 호출 여부를 묻는 속성이다. 마지막으로 doNotUseGetters의 속성은 getter 사용여부 인듯 하나 제대로 동작하지는 모르겠다.
@EqualsAndHashCode(of = "id")
@ToString(exclude = "name")
public class HashCodeAndEqualsObject {
private Long id;
private String name;
}
만일 위와 같이 작성하였다면 hasCode, equals, toString 모두 id만 존재하게 된다.
각각의 속성으로는 @EqualsAndHashCode 는
onParam
, @ToString 는
includeFieldNames
속성이 존재한다. onParam 은 equals에 작성되며 위의 onParam 속성과 동일하므로 생략한다. includeFieldNames는 toString의 필드 명을 출력할지 하지 않을지의 여부이다. 만일 위의 코드로
includeFieldNames
을 false로 한다면 다음과 같이 출력 된다.
HashCodeAndEqualsObject(null)
참고로
canEqual
메서드도
@EqualsAndHashCode
메서드에 포함되어 있다.
@val 와 @var
스칼라, 코틀린 이외에 다른 언어들의 키워드와 동일하게 타입추론을 한다.
public class ValAndVarTests {
@Test
public void valVarTest() {
val arrVal = Arrays.asList(1, 2, 3, 4, 5);
arrVal = new ArrayList<>(); // compile error
var arrVar = Arrays.asList(1, 2, 3, 4, 5);
arrVar = new ArrayList<>();
}
}
val
경우에는
final
키워드가 생성된다. 그래서 다시 어사인을 할 경우에 컴파일 에러가 발생한다. 마찬가지로
var
는 final이 존재 하지 않으므로 다시 어사인이 가능하다. 위의 코드를 다시 만들어 보면 다음과 같을 것으로 예상된다.
final List<Integer> arrVal1 = Arrays.asList(1, 2, 3, 4, 5);
arrVal1 = new ArrayList<>();
List<Integer> arrVar1 = Arrays.asList(1, 2, 3, 4, 5);
arrVar1 = new ArrayList<>();
위와 동일한 바이트코드가 나올 것으로 예상해본다.
@UtilityClass
유틸리티 클래스에 적용하면 되는 어노테이션이다. 만약 이 어노테이션을 작성하면 기본생성자가
private
생성되며 만약 리플렉션 혹은 내부에서 생성자를 호출할 경우에는
UnsupportedOperationException
이 발생한다.
@UtilityClass
public class UtilityClassObject {
public static String name() {
return "wonwoo;";
}
}
만약 위의 코드를 다시 작성해보면 다음과 같다.
class UtilityClassObjectNot {
private UtilityClassObjectNot() {
throw new UnsupportedOperationException("This is a utility class and cannot be instantiated");
}
public static String name() {
return "wonwoo;";
}
}
이번시간에는 이정도로 마무리를 짓도록 하자. 오늘은 자주 사용하는 lombok에 대해서 알아봤다. 다음에는 자주 사용은 하지 않지만 특이하거나 재미있는 코드를 살펴보도록 하자. (물론 자주 사용하는 것도 있다.)
오늘은 여기까지!