解決lombok 父類(lèi)和子類(lèi)builder不兼容的問(wèn)題
遇到的問(wèn)題
在寫(xiě)代碼時(shí),有時(shí)因?yàn)樾枰x一些重復(fù)的參數(shù),為了復(fù)用之前傳參的DTO,會(huì)對(duì)原有的類(lèi)進(jìn)行繼承,從而達(dá)到避免重復(fù)代碼的效果。
但是,當(dāng)父類(lèi)中使用了lombok的@Builder注解,子類(lèi)也需要@builder注解時(shí),就會(huì)出現(xiàn)異常
排查和解決
由于實(shí)際的代碼存在敏感信息,這里分別定義兩個(gè)類(lèi)Parent和Child來(lái)進(jìn)行場(chǎng)景的模擬
@Data
@Builder
class Parent {
? ? private String parentProperty1;
? ? private String parentProperty2;
}
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
class Child extends Parent {
? ? private String childProperty1;
}這時(shí)在嘗試使用子類(lèi)的builder方法時(shí),發(fā)現(xiàn)沒(méi)有辦法鏈?zhǔn)秸{(diào)用,使用時(shí)只能初始化子類(lèi)中的變量,編譯時(shí)會(huì)直接失敗,拋出異常
Error:(160, 1) java: 無(wú)法將類(lèi) org.example.Parent中的構(gòu)造器 Parent應(yīng)用到給定類(lèi)型;
需要: java.lang.String,java.lang.String
找到: 沒(méi)有參數(shù)
原因: 實(shí)際參數(shù)列表和形式參數(shù)列表長(zhǎng)度不同
這是在編譯子類(lèi)的@Builder注解時(shí)出現(xiàn)的異常,原因直觀的看起來(lái)是找不到構(gòu)造器,在Parent類(lèi)上加上@NoArgsConstructor和@AllArgsConstructor這兩個(gè)注解就能解決這個(gè)問(wèn)題,但是同時(shí)會(huì)出現(xiàn)新的編譯問(wèn)題,是什么問(wèn)題先按下不表。
想要簡(jiǎn)單的解決加上@Builder之后就會(huì)報(bào)錯(cuò)的問(wèn)題,那么直接把父類(lèi)的@Builder這個(gè)注解拿掉就行了,不過(guò)這時(shí)無(wú)法設(shè)置父類(lèi)的屬性,如果還想在子類(lèi)中使用構(gòu)建器模式來(lái)初始化父類(lèi)的屬性,還有另一種方法,在子類(lèi)中實(shí)現(xiàn)一個(gè)能夠初始化父類(lèi)屬性的構(gòu)造器,并在這個(gè)構(gòu)造方法上添加@Builder注解。
這時(shí)的代碼:
@Data
@NoArgsConstructor
@AllArgsConstructor
class Parent {
? ? private String parentProperty1;
? ? private String parentProperty2;
}
@Data
class Child extends Parent {
? ? private String childProperty1;
? ? @Builder
? ? public Child(String parentProperty1, String parentProperty2, String childProperty1){
? ? ? ? super(parentProperty1, parentProperty2);
? ? ? ? this.childProperty1 = childProperty1;
? ? }
}不過(guò)使用這種方法只能解決子類(lèi)使用@Builder的問(wèn)題,但是在更多的時(shí)候,父類(lèi)也是需要@Builder這個(gè)注解的,那么在這種情況下應(yīng)該怎么解決呢?
而且這時(shí)還會(huì)有另一個(gè)新的問(wèn)題出現(xiàn),使用了@Data注解和@Builder注解的子類(lèi)無(wú)法使用無(wú)參構(gòu)造器來(lái)創(chuàng)建對(duì)象,這時(shí)需要在子類(lèi)上顯式的加上@NoArgsConstructor這個(gè)注解才能解決。
如果要更細(xì)致的分析,就得從從@Builder的原理說(shuō)起,了解@Builder到底生成了哪些代碼?
這一步可以自己編譯代碼看看,當(dāng)然如果自己寫(xiě)過(guò)builder建造者模式的實(shí)現(xiàn),應(yīng)該能想到他是實(shí)現(xiàn)了一個(gè)名稱(chēng)以Builder為后綴的靜態(tài)內(nèi)部類(lèi),在調(diào)用build()方法的時(shí)候調(diào)用外部類(lèi)的全參構(gòu)造方法來(lái)生成外部類(lèi)的實(shí)例。
回到之前的問(wèn)題,當(dāng)子類(lèi)和父類(lèi)同時(shí)存在@Builder注解時(shí),在解決了構(gòu)造器異常之后,如果編譯代碼,會(huì)出現(xiàn)異常:
Error:(164, 5) java: org.example.Child中的builder()無(wú)法覆蓋org.example.Parent中的builder()
返回類(lèi)型org.example.Child.ChildBuilder與org.example.Parent.ParentBuilder不兼容
這里的問(wèn)題就簡(jiǎn)單一些了,父類(lèi)的builder()方法返回的是ParentBuilder這個(gè)靜態(tài)內(nèi)部類(lèi)類(lèi)型的對(duì)象,而子類(lèi)生成的builder()方法返回的是ChildBuilder這個(gè)類(lèi)型的對(duì)象。
兩者的名稱(chēng)重復(fù)了,而由于返回類(lèi)型不兼容而無(wú)法按覆蓋。
根據(jù)@Builder注解的源碼可以發(fā)現(xiàn)名稱(chēng)是可以自定義的,于是可以通過(guò)給子類(lèi)builder方法自定義名稱(chēng)的方式來(lái)解決這個(gè)問(wèn)題。
最終的代碼:
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
class Parent {
? ? private String parentProperty1;
? ? private String parentProperty2;
}
@Data
class Child extends Parent {
? ? private String childProperty1;
? ? @Builder(builderMethodName = "childBuilder")
? ? public Child(String parentProperty1, String parentProperty2, String childProperty1){
? ? ? ? super(parentProperty1, parentProperty2);
? ? ? ? this.childProperty1 = childProperty1;
? ? }
}結(jié)尾
值得一提的是,1.8.2之后版本的lombok提供了一個(gè)新的注解@SuperBuilder來(lái)解決這個(gè)問(wèn)題,不過(guò)我沒(méi)有用過(guò),而且從網(wǎng)上搜索出來(lái)的結(jié)果來(lái)看,還是存在一些問(wèn)題的,建議謹(jǐn)慎升級(jí)。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringMVC實(shí)現(xiàn)Controller的三種方式總結(jié)
這篇文章主要介紹了SpringMVC實(shí)現(xiàn)Controller的三種方式總結(jié),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
比較java中Future與FutureTask之間的關(guān)系
在本篇文章里我們給大家分享了java中Future與FutureTask之間的關(guān)系的內(nèi)容,有需要的朋友們可以跟著學(xué)習(xí)下。2018-10-10
MyBatis實(shí)現(xiàn)模糊查詢(xún)的幾種方式
這篇文章主要介紹了MyBatis實(shí)現(xiàn)模糊查詢(xún)的幾種方式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08
MybatisGenerator文件生成不出對(duì)應(yīng)文件的問(wèn)題
本文介紹了使用MybatisGenerator生成文件時(shí)遇到的問(wèn)題及解決方法,主要步驟包括檢查目標(biāo)表是否存在、是否能連接到數(shù)據(jù)庫(kù)、配置生成器的路徑等,通過(guò)在項(xiàng)目結(jié)構(gòu)中引入相應(yīng)的jar包,并在GeneratorSqlmap.java文件中運(yùn)行,可以成功生成對(duì)應(yīng)的文件2025-01-01
詳細(xì)介紹高性能Java緩存庫(kù)Caffeine
本篇文章主要介紹了詳細(xì)介紹高性能Java緩存庫(kù)Caffeine,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-02-02
SpringCloud?Gateway中GatewayFilterChain執(zhí)行流程詳解
Spring?Cloud?Gateway旨在為微服務(wù)架構(gòu)提供一種簡(jiǎn)單有效的、統(tǒng)一的?API?路由管理方式。Spring?Cloud?Gateway?作為?Spring?Cloud?生態(tài)系中的網(wǎng)關(guān),它不僅提供統(tǒng)一的路由方式,并且基于?Filter?鏈的方式提供了網(wǎng)關(guān)基本的功能,例如:安全、監(jiān)控/埋點(diǎn)和限流等2022-10-10
java中List接口與實(shí)現(xiàn)類(lèi)介紹
大家好,本篇文章主要講的是java中List接口與實(shí)現(xiàn)類(lèi)介紹,感興趣的同學(xué)趕快來(lái)看一看吧,對(duì)你有幫助的話(huà)記得收藏一下,方便下次瀏覽2021-12-12
springboot中PostMapping正常接收json參數(shù)后返回404問(wèn)題
這篇文章主要介紹了springboot中PostMapping正常接收json參數(shù)后返回404問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-05-05

