1. 程式人生 > >Eclipse中安裝lombok安裝及使用和原理

Eclipse中安裝lombok安裝及使用和原理

lombok:通過註解方式減少POJO類的getter和setter等方法來消除冗餘程式碼量

安裝
1.下載 lombok.jar
2.官網說是可以雙擊安裝,,,我用這種方法不可行
2.手動安裝
(1)將lombok.jar移到eclipse的安裝目錄
這裡寫圖片描述

(2)在eclipse.in檔案最後加入下面兩行

-Xbootclasspath/a:lombok.jar
-javaagent:lombok.jar
  • =============

-javaagent:xxx.jar 的jar名稱 需要與根目錄下的jar名一致,
不一致,可能會出現eclipse無法啟動的情況。

(3)重啟eclipse,進行程式碼測試

原始java程式碼:

public class NoteTest {

    private int noteId;
    private String title;
    private String content;
    private int typeId;

}

class檔案反編譯後:

public class NoteTest
{

    private int noteId;
    private String title;
    private String content;
    private int typeId;

    public NoteTest()
    {

、、、、、、、、、、、、、、、、、、、、、、、、、、、、、、
加入lombok註解後的java程式碼:

@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString(exclude="typeId")
public class NoteTest {

    private int noteId;
    private String title;
    private String content;
    private int typeId;

}

加註解,經反編譯:

public class NoteTest
{

    private int noteId;
    private String title;
    private String content;
    private int typeId;

    public int getNoteId()
    {
        return noteId;
    }

    public String getTitle()
    {
        return title;
    }

    public String getContent()
    {
        return content;
    }

    public int getTypeId()
    {
        return typeId;
    }

    public void setNoteId(int noteId)
    {
        this.noteId = noteId;
    }

    public void setTitle(String title)
    {
        this.title = title;
    }

    public void setContent(String content)
    {
        this.content = content;
    }

    public void setTypeId(int typeId)
    {
        this.typeId = typeId;
    }

    public boolean equals(Object o)
    {
        if (o == this)
            return true;
        if (!(o instanceof NoteTest))
            return false;
        NoteTest other = (NoteTest)o;
        if (!other.canEqual(this))
            return false;
        if (getNoteId() != other.getNoteId())
            return false;
        Object this$title = getTitle();
        Object other$title = other.getTitle();
        if (this$title != null ? !this$title.equals(other$title) : other$title != null)
            return false;
        Object this$content = getContent();
        Object other$content = other.getContent();
        if (this$content != null ? !this$content.equals(other$content) : other$content != null)
            return false;
        return getTypeId() == other.getTypeId();
    }

    protected boolean canEqual(Object other)
    {
        return other instanceof NoteTest;
    }

    public int hashCode()
    {
        int PRIME = 59;
        int result = 1;
        result = result * 59 + getNoteId();
        Object $title = getTitle();
        result = result * 59 + ($title != null ? $title.hashCode() : 43);
        Object $content = getContent();
        result = result * 59 + ($content != null ? $content.hashCode() : 43);
        result = result * 59 + getTypeId();
        return result;
    }

    public NoteTest()
    {
    }

    public NoteTest(int noteId, String title, String content, int typeId)
    {
        this.noteId = noteId;
        this.title = title;
        this.content = content;
        this.typeId = typeId;
    }

    public String toString()
    {
        return (new StringBuilder("NoteTest(noteId=")).append(getNoteId()).append(", title=").append(getTitle()).append(", content=").append(getContent()).append(")").toString();
    }
}

常用的 lombok 註解

@EqualsAndHashCode:實現equals()方法和hashCode()方法 @ToString:實現toString()方法
@Data :註解在類上;提供類所有屬性的 getting 和 setting 方法,此外還提供了equals、canEqual、hashCode、toString 方法
@Setter:註解在屬性上;為屬性提供 setting 方法
@Getter:註解在屬性上;為屬性提供 getting 方法
@Log4j :註解在類上;為類提供一個 屬性名為log 的 log4j 日誌物件
@NoArgsConstructor:註解在類上;為類提供一個無參的構造方法
@AllArgsConstructor:註解在類上;為類提供一個全參的構造方法
@Cleanup:關閉流 @Synchronized:物件同步 @SneakyThrows:丟擲異常

@Data

不使用 lombok 的方案

public class Person {

 private String id;
 private String name;
 private String identity;
 private Logger log = Logger.getLogger(Person.class);
 public Person() {
   }
 public Person(String id, String name, String identity) {
      this.id   = id;
      this.name = name;
      this.identity = identity;
  }    
 public String getId() {
       return id;
   } 
 public String getName() {
           return name;
   }

 public String getIdentity() {
     return identity;
  }    
 public void setId(String id) {
      this.id = id;
  }

  public void setName(String name) {
    this.name = name;
  }

  public void setIdentity(String identity) {
      this.identity = identity;
  }
}

使用 lombok 的方案

 @Data
 @Log4j
 @NoArgsConstructor
 @AllArgsConstructor
 public class Person {
 private String id;
 private String name;
 private String identity;
}

上面的兩個 java 類,從作用上來看,它們的效果是一樣的,相比較之下,很明顯,使用 lombok 要簡潔許多

 <dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
 </dependency>

@Builder

不使用 lombok 的方案

public class Example<T> {
        private T foo;
        private final String bar;

        private Example(T foo, String bar) {
                this.foo = foo;
                this.bar = bar;
        }

        public static <T> ExampleBuilder<T> builder() {
                return new ExampleBuilder<T>();
        }

        public static class ExampleBuilder<T> {
                private T foo;
                private String bar;

                private ExampleBuilder() {}

                public ExampleBuilder foo(T foo) {
                        this.foo = foo;
                        return this;
                }

                public ExampleBuilder bar(String bar) {
                        this.bar = bar;
                        return this;
                }

                @java.lang.Override 
                public String toString() {
                        return "ExampleBuilder(foo = " + foo + ", bar = " + bar + ")";
                }

                public Example build() {
                        return new Example(foo, bar);
                }
        }
 }

使用 lombok 的方案 guava 16.0.1

@Builder
 public class Example {
        private int foo;
        private final String bar;
 }

構造一個例項,屬性不需要單獨set
Example.builder().foo(1).bar(“test”).build()

lombok的使用和原理

一、專案背景
在寫Java程式的時候經常會遇到如下情形:
新建了一個Class類,然後在其中設定了幾個欄位,最後還需要花費很多時間來建立getter和setter方法
lombok專案的產生就是為了省去我們手動建立getter和setter方法的麻煩,它能夠在我們編譯原始碼的時候自動幫我們生成getter和setter方法。即它最終能夠達到的效果是:在原始碼中沒有getter和setter方法,但是在編譯生成的位元組碼檔案中有getter和setter方法
比如原始碼檔案:

  1. import java.io.Serializable;

  2. import lombok.Data;

  3. @Data

  4. public class BasicClusterInfo implements Serializable {

  5. private static final long serialVersionUID = 3478135817352393604L;

  6. private String hbaseKey;

  7. private int receiverCount;

  8. }

以下是編譯上述原始碼檔案得到的位元組碼檔案,對其反編譯得到的結果

  1. public class BasicClusterInfo extends java.lang.Object implements java.io.Serializable{

  2. public BasicClusterInfo();

  3. public java.lang.String getHbaseKey();

  4. public int getReceiverCount();

  5. public void setHbaseKey(java.lang.String);

  6. public void setReceiverCount(int);

  7. public boolean equals(java.lang.Object);

  8. public boolean canEqual(java.lang.Object);

  9. public int hashCode();

  10. public java.lang.String toString();

  11. }



二、使用方法
使用lombok專案的方法很簡單,分為四個步驟:
1)在需要自動生成getter和setter方法的類上,加上@Data註解
2)在編譯類路徑中加入lombok.jar包
3)使用支援lombok的編譯工具編譯原始碼(關於支援lombok的編譯工具,見“四、支援lombok的編譯工具”)
4)編譯得到的位元組碼檔案中自動生成了getter和setter方法


三、原理分析
接下來進行lombok能夠工作的原理分析,以Oracle的javac編譯工具為例。
自從Java 6起,javac就支援“JSR 269 Pluggable Annotation Processing API”規範,只要程式實現了該API,就能在javac執行的時候得到呼叫。
舉例來說,現在有一個實現了"JSR 269 API"的程式A,那麼使用javac編譯原始碼的時候具體流程如下:
1)javac對原始碼進行分析,生成一棵抽象語法樹(AST)
2)執行過程中呼叫實現了"JSR 269 API"的A程式
3)此時A程式就可以完成它自己的邏輯,包括修改第一步驟得到的抽象語法樹(AST)
4)javac使用修改後的抽象語法樹(AST)生成位元組碼檔案
詳細的流程圖如下:



lombok本質上就是這樣的一個實現了"JSR 269 API"的程式。在使用javac的過程中,它產生作用的具體流程如下:
1)javac對原始碼進行分析,生成一棵抽象語法樹(AST)
2)執行過程中呼叫實現了"JSR 269 API"的lombok程式
3)此時lombok就對第一步驟得到的AST進行處理,找到@Data註解所在類對應的語法樹(AST),然後修改該語法樹(AST),增加getter和setter方法定義的相應樹節點
4)javac使用修改後的抽象語法樹(AST)生成位元組碼檔案


四、支援lombok的編譯工具
1)由“三、原理分析”可知,Oracle javac直接支援lombok
2)常用的專案管理工具Maven所使用的java編譯工具來源於配置的第三方工具,如果我們配置這個第三方工具為Oracle javac的話,那麼Maven也就直接支援lombok了
3)Intellij Idea配置的編譯工具為Oracle javac的話,也就直接支援lombok了。
4)Eclipse中使用的不是Oracle javac這個編譯工具,而是自己實現的Eclipse Compiler for Java (ECJ).要想使ECJ支援lombok,得進行設定,具體是在Eclipse程式目錄中的eclipse.ini檔案中新增如下兩行設定:
-javaagent:[lombok.jar所在路徑]
-Xbootclasspath/a:[lombok.jar所在路徑]


五、其他問題
現在使用Intellij Idea作為Java專案的IDE,配置Oracle javac作為編譯工具。
現在有一個A類,其中有一些欄位,沒有建立它們的setter和getter方法,使用了lombok的@Data註解,另外有一個B類,它呼叫了A類例項的相應欄位的setter和getter方法
編譯A類和B類所在的專案,並不會報錯,因為最終生成的A類位元組碼檔案中存在相應欄位的setter和getter方法
但是,IDE發現B類原始碼中所使用的A類例項的setter和getter方法在A類原始碼中找不到定義,IDE會認為這是錯誤
要解決以上這個不是真正錯誤的錯誤,可以下載安裝Intellij Idea中的"Lombok plugin"。


六、lombok的罪惡
使用lombok雖然能夠省去手動建立setter和getter方法的麻煩,但是卻大大降低了原始碼檔案的可讀性和完整性,降低了閱讀原始碼的舒適度。  這個根據自己的情況,來決定是否使用lombok




參考文獻:
[1]http://stackoverflow.com/questions/6107197/how-does-lombok-work
[2]https://projectlombok.org/download.html
[3]http://stackoverflow.com/questions/3061654/what-is-the-difference-between-javac-and-the-eclipse-compiler
[4]http://www.ibm.com/developerworks/library/j-lombok/
[5]http://notatube.blogspot.com/2010/12/project-lombok-creating-custom.html