➜ Old React website
Chung Cheuk Hang MichaelJava Web Developer
Java 8 之後既新功能寫第一個 Chrome Extension

在 Java 項目中使用 Lombok

Continued from previous post:
Java 開發筆記(五)

Table of contents

1 關於 Lombok

一般黎講,我地多數會喺啲只有 properties 既 VO(value object)、DTO(data transfer object)、entity classes 上使用 Lombok。
呢啲 classes 有以下既特徵:
  • 有好多 properties,如 privateprotected 既非 static properties,但絕對唔會係 public(除非冇跟到 best practice)
  • 至少有一個 constructor
  • 容許我地建立多個 objects(換言之呢個 class 唔可以係 singleton)
  • 每個 property 都有對應既 getter(get 開頭,冇 parameter,有 return type,如 String getName()),而如果係 mutable class 就會有埋 setter(set 開頭,有 parameter,void return type,如 void setName(String name)),呢啲 getters/setters 都係 public,應該佔呢個 class 既 methods 既大部分,而 getters/setters 其實用 Eclipse 都可以 gen 到出黎,所以被稱為 boilerplate code

1.1 唔用 Lombok 既例子

1public class Person { 2 private String firstName; 3 private String lastName; 4 5 public String getFirstName() { 6 return firstName; 7 } 8 9 public String getLastName() { 10 return lastName; 11 } 12 13 public void setFirstName(String firstName) { 14 this.firstName = firstName; 15 } 16 17 public void setLastName(String lastName) { 18 this.lastName = lastName; 19 } 20}

1.2 用左 Lombok 既例子

以下例子用左 @Getter@Setter 黎為所有 properties 去 gen getters 同 setters,以及 @FieldDefaults(level = PRIVATE) 去為所有 properties 加上 private 既 access modifier。
1@Getter 2@Setter 3@FieldDefaults(level = PRIVATE) 4public class Person { 5 String firstName; 6 String lastName; 7}

2 喺 Eclipse 安裝 Lombok

Double click 個 JAR 檔,選擇 Eclipse 既安裝路徑,然後完成安裝。
最後,重新開啟 Eclipse。

3 正式使用 Lombok

3.1 添加 Maven dependencies

pom.xml 裡面需要以下 dependency:
1<dependency> 2 <groupId>org.projectlombok</groupId> 3 <artifactId>lombok</artifactId> 4 <version>1.18.24</version> 5 <scope>provided</scope> 6</dependency> 7

3.2 寫 Java code

1@Getter 2@Setter 3@FieldDefaults(level = PRIVATE) 4public class Person { 5 String firstName; 6 String lastName; 7}

3.3 喺 Eclipse 查看 Outline

Eclipse 會話畀我地知我地既 properties 實際上係 private 同埋呢個 class 有咩 methods,我地應該會見到對應既 getters 同 setters 都已經 gen 左出黎。
雖然個 class 既 source code 睇唔到有 getters/setters,但因為 Lombok 已經喺 compile time 幫我地 gen 左 code,所以其實同我地自己寫既 code 冇任何分別。

3.4 運用 Lombok generate 出黎既 code

試驗一下 Lombok gen 出黎同自己寫既有冇分別,毫不意外地 Eclipse 正常 compile 到,冇報任何 error,而運行程式都可以正常咁 call 到 setters 去 set properties、call 到 getters 去 get 返出黎。

4 更多 Lombok annotations

Lombok 有以下既 annotations 都好有用:
Lombok annotation描述參考
@Getter根據 properties 去 gen getters官網
@Setter根據 properties 去 gen setters,可以加上 chain = true 去令 setters 既 return type 由 void 改為個 property 屬於既 class,從而支援 method chaining(new Person().setFirstName("Michael").setLastName("Chung")官網
@ToString根據 properties 去 gen toString method官網
@EqualsAndHashCode根據 properties 去 gen equalshashCode methods官網
@Data懶人包——包括曬 @ToString@EqualsAndHashCode@Getter@Setter@RequiredArgsConstructor官網
@Value懶人包(immutable 版)——包括曬 @ToString@EqualsAndHashCode@AllArgsConstructor@FieldDefaults(makeFinal = true, level = PRIVATE)@Getter,而呢個 class 都會係 final官網
@Builder根據 properties 去 gen 一個 inner class 叫 XxxBuilder(如 PersonBuilder),builder class 裡面有非 set 開頭既 setters 同一個 build method,畀我地用 builder 黎 construct objects,從而做到 builder pattern,亦支援 method chaining官網
@FieldDefaults為啲冇 access modifier(default)既 properties 加上 access modifier,如 private官網
@NoArgsConstructorGen 一個冇 argument 既 constructor,如 public Person() {}官網
@RequiredArgsConstructor根據 class 內 final@NonNull 既 properties 去 gen 一個 constructor官網
@AllArgsConstructorGen 一個有齊所有 properties 既 constructor官網
@Slf4jGen 一個 static 既 Slf4j log object 出黎,for 出 log 用(一般都係用 log.debuglog.info 代替 System.out.println,用 log.warnlog.error 代替 System.err.println),而個 project 需要 org.slf4jslf4j-apich.qos.logbacklogback-classic 兩個 dependencies。另外,我地可以喺 main/resources 度加個 logback.xml 檔黎設定 Logback,例子喺下面官網
logback.xml
1<?xml version="1.0" encoding="UTF-8"?> 2<configuration> 3 4 <property name="LOG_FOLDER" value="logs" /> 5 <property name="LOG_FILE" value="app" /> 6 <property name="STYLE_LOG_PATTERN" value="%magenta(%d{yyyy-MM-dd HH:mm:ss.SSS}) %highlight(%-5level) [%-5t] %cyan(%-50.50replace(%replace(%caller{1}){'Caller.*?at ', 'at '}){'(\r)?\n', ''}) - %msg%n" /> 7 <property name="PLAIN_LOG_PATTERN" value="%d{yyyy-MM-dd HH:mm:ss.SSS} %-5level [%-5t] %-50.50replace(%replace(%caller{1}){'Caller.*?at ', 'at '}){'(\r)?\n', ''} - %msg%n" /> 8 9 10 11 <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> 12 <layout class="ch.qos.logback.classic.PatternLayout"> 13 <Pattern>${STYLE_LOG_PATTERN}</Pattern> 14 </layout> 15 </appender> 16 17 18 19 <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> 20 <file>${LOG_FOLDER}/${LOG_FILE}.log</file> 21 <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder"> 22 <Pattern>${PLAIN_LOG_PATTERN}</Pattern> 23 </encoder> 24 25 <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> 26 <!-- rollover daily --> 27 <fileNamePattern>${LOG_FOLDER}/archived/${LOG_FILE}.%d{yyyy-MM-dd}.%i.log</fileNamePattern> 28 <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> 29 <maxFileSize>10MB</maxFileSize> 30 </timeBasedFileNamingAndTriggeringPolicy> 31 </rollingPolicy> 32 </appender> 33 34 35 36 <root level="info"> 37 <appender-ref ref="STDOUT" /> 38 <appender-ref ref="FILE" /> 39 </root> 40 41</configuration>

5 Lombok 配置檔

我地可以喺 project root folder 新增一個 lombok.config 檔,然後根據上述官網提及既 config properties 黎設定呢個 project 既 Lombok。
lombok.config 檔既例子:
lombok.getter.noIsPrefix=true lombok.accessors.chain=true
以上 config 帶黎既效果:
  • @Getter 為 property boolean exist gen 出黎既 getter 就會係 getExist 而唔係 isExist
  • @Setter 為 property boolean exist gen 出黎既 setter 既 return type 就會係個 property 屬於既 class 而唔係 void

6 Spring Boot Maven Plugin:JAR 檔排除 Lombok

如果我地喺 Spring Boot projects 裡面用 spring-boot-maven-plugin,我地唔需要 Lombok dependency 出現喺最終果個 artifact JAR 檔裡面。
咁係因為 compile 階段已經 generate 曬啲 code,所以最終果個 artifact JAR 檔裡面既 Lombok JAR 檔就再冇利用價值。
不過,用 Maven <dependency><scope>provided</scope> 係唔會 work,因為我地喺 Maven package phase 裡面用左 Spring Boot Maven plugin 既 repackage goal,佢依然係會將所有 dependencies 既 JAR 檔打包喺 BOOT-INF/lib 裡面。
要解決呢個問題,我地就要自行配置 Spring Boot Maven plugin 去 exclude 佢:
1<build> 2 <plugins> 3 <plugin> 4 <groupId>org.springframework.boot</groupId> 5 <artifactId>spring-boot-maven-plugin</artifactId> 6 <executions> 7 <execution> 8 <goals> 9 <goal>repackage</goal> 10 </goals> 11 </execution> 12 </executions> 13 <configuration> 14 <excludes> 15 <exclude> 16 <groupId>org.projectlombok</groupId> 17 <artifactId>lombok</artifactId> 18 </exclude> 19 </excludes> 20 </configuration> 21 </plugin> 22 </plugins> 23</build>
參考資料:

7 Java 14 既 record

Java 14 新加既 record type 嘗試做緊部分 Lombok 既功能。
record 會 gen 到以下既野:
  • equals method
  • hashCode method
  • toString method
  • private access modifier
  • final modifier
  • public constructor
參考文章:Java 14 Record Keyword