doortts / blog

0 stars 0 forks source link

[dw Review] 자바 DTO 개선시키기, Lombok #148

Open doortts opened 14 years ago

doortts commented 14 years ago

@doortts (doortts) 님이 작성한 게시글입니다. ---

doortts | 2010-10-26 화요일 오전 12:17 | Better SW Development | 원본

아쉽게도 많은 언어들이 자신만의 장점을 소개할 때 많이 사용하는 방법 중 하나는 자바빈(Java Bean)을 얼마나 적은 코드로 구현할 수 있는지를 보여주며 자랑으로 삼곤 한다.

별거 아닌데 살짝 분하다는 생각이 든다. 그게 뭐 큰 자랑이라고!... 라고는 하지만 때때로 자랑은 자랑이다. 너무 축약되서 의미가 훼손되는 수준이 아니라면, 코드 줄 수는 적을 수록 좋은게 맞다.

자바의 대표적인 노다가성 코드가 엔티티 클래스나 자바 빈계열의 DTO클래스를 만들때 발생한다. getter와 setter로 클래스의 대부분을 채우기 십상이다. 그리고 hashcode나 equals구현, toString 정도 집어넣으면 별 로직도 없는 코드가 잔뜩 길어진다. 이럴때 유용한 자바 라이브러리가 바로 Lombok(http://projectlombok.org) 이다.

lombok.png

[IBM DW] Java 코드에서 불필요한 코드를 제거할 수 있는 편리한 방법 http://www.ibm.com/developerworks/kr/library/os-lombok/index.html

아래 코드는 Lombok을 사용하기 전

001 **import **java.util.Arrays; 002  003 **public class **DataExample { 004 **private final **String name; 005 **private ****int **age; 006 **private ****double **score; 007 **private **String[] tags; 008  009 **public **DataExample(String name) { 010 **this**.name = name; 011 } 012  013 **public **String getName() { 014 **return this**.name; 015 } 016  017 **void **setAge(**int **age) { 018 **this**.age = age; 019 } 020  021 **public ****int **getAge() { 022 **return this**.age; 023 } 024  025 **public ****void **setScore(**double **score) { 026 **this**.score = score; 027 } 028  029 **public ****double **getScore() { 030 **return this**.score; 031 } 032  033 **public **String[] getTags() { 034 **return this**.tags; 035 } 036  037 **public ****void **setTags(String[] tags) { 038 **this**.tags = tags; 039 } 040  041 @Override **public **String toString() { 042 **return **"DataExample(" + **this**.getName() + ", " + **this**.getAge() + ", " + **this**.getScore() + ", " + Arrays.deepToString(**this**.getTags()) + ")"; 043 } 044  045 @Override **public ****boolean **equals(Object o) { 046 **if **(o == **this**) **return true**; 047 **if **(o == **null**) **return false**; 048 **if **(o.getClass() != **this**.getClass()) **return false**; 049 DataExample other = (DataExample) o; 050 **if **(**this**.getName() == **null **? other.getName() != **null **: !**this**.getName().equals(other.getName())) **return false**; 051 **if **(**this**.getAge() != other.getAge()) **return false**; 052 **if **(Double.compare(**this**.getScore(), other.getScore()) != 0) **return false**; 053 **if **(!Arrays.deepEquals(**this**.getTags(), other.getTags())) **return false**; 054 **return true**; 055 } 056  057 @Override **public ****int **hashCode() { 058 **final ****int **PRIME = 31; 059 **int **result = 1; 060 **final ****long **temp1 = Double.doubleToLongBits(**this**.getScore()); 061 result = (result*PRIME) + (**this**.getName() == **null **? 0 : **this**.getName().hashCode()); 062 result = (result*PRIME) + **this**.getAge(); 063 result = (result*PRIME) + (**int**)(temp1 ^ (temp1 >>> 32)); 064 result = (result*PRIME) + Arrays.deepHashCode(**this**.getTags()); 065 **return **result; 066 } 067  068 **public static class **Exercise { 069 **private final **String name; 070 **private final **T value; 071  072 **private **Exercise(String name, T value) { 073 **this**.name = name; 074 **this**.value = value; 075 } 076  077 **public static ** Exercise of(String name, T value) { 078 **return new **Exercise(name, value); 079 } 080  081 **public **String getName() { 082 **return this**.name; 083 } 084  085 **public **T getValue() { 086 **return this**.value; 087 } 088  089 @Override **public **String toString() { 090 **return **"Exercise(name=" + **this**.getName() + ", value=" + **this**.getValue() + ")"; 091 } 092  093 @Override **public ****boolean **equals(Object o) { 094 **if **(o == **this**) **return true**; 095 **if **(o == **null**) **return false**; 096 **if **(o.getClass() != **this**.getClass()) **return false**; 097 Exercise other = (Exercise) o; 098 **if **(**this**.getName() == **null **? other.getValue() != **null **: !**this**.getName().equals(other.getName())) **return false**; 099 **if **(**this**.getValue() == **null **? other.getValue() != **null **: !**this**.getValue().equals(other.getValue())) **return false**; 100 **return true**; 101 } 102  103 @Override **public ****int **hashCode() { 104 **final ****int **PRIME = 31; 105 **int **result = 1; 106 result = (result*PRIME) + (**this**.getName() == **null **? 0 : **this**.getName().hashCode()); 107 result = (result*PRIME) + (**this**.getValue() == **null **? 0 : **this**.getValue().hashCode()); 108 **return **result; 109 } 110 } 111 }

Lombok을 사용하면 동일한 내용이 아래와 같이 구현가능

01 **import **lombok.AccessLevel; 02 **import **lombok.Setter; 03 **import **lombok.Data; 04 **import **lombok.ToString; 05  06 @Data **public class **DataExample { 07 **private final **String name; 08 @Setter(AccessLevel.PACKAGE) **private ****int **age; 09 **private ****double **score; 10 **private **String[] tags; 11  12 @ToString(includeFieldNames=**true**) 13 @Data(staticConstructor="of") 14 **public static class **Exercise { 15 **private final **String name; 16 **private final **T value; 17 } 18 }

Lombok에는 이외에도 리소스 정리 작업( close 메소드 호출 계열)을 지원해 주는 @Cleanup 기능. 원하는 수준으로 적절히 Lock을 제공하는 @Synchronized 등등의 기능을 제공한다.

다음 JDK에서는 일부 기능을 언어차원에서 지원해 줘도 괜찮을 것 같다는 생각이 든다. :)

--- attachments --- lombok.png