解決lombok 父類和子類builder不兼容的問題
遇到的問題
在寫代碼時(shí),有時(shí)因?yàn)樾枰x一些重復(fù)的參數(shù),為了復(fù)用之前傳參的DTO,會(huì)對(duì)原有的類進(jìn)行繼承,從而達(dá)到避免重復(fù)代碼的效果。
但是,當(dāng)父類中使用了lombok的@Builder注解,子類也需要@builder注解時(shí),就會(huì)出現(xiàn)異常
排查和解決
由于實(shí)際的代碼存在敏感信息,這里分別定義兩個(gè)類Parent和Child來進(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í)在嘗試使用子類的builder方法時(shí),發(fā)現(xiàn)沒有辦法鏈?zhǔn)秸{(diào)用,使用時(shí)只能初始化子類中的變量,編譯時(shí)會(huì)直接失敗,拋出異常
Error:(160, 1) java: 無法將類 org.example.Parent中的構(gòu)造器 Parent應(yīng)用到給定類型;
需要: java.lang.String,java.lang.String
找到: 沒有參數(shù)
原因: 實(shí)際參數(shù)列表和形式參數(shù)列表長(zhǎng)度不同
這是在編譯子類的@Builder注解時(shí)出現(xiàn)的異常,原因直觀的看起來是找不到構(gòu)造器,在Parent類上加上@NoArgsConstructor和@AllArgsConstructor這兩個(gè)注解就能解決這個(gè)問題,但是同時(shí)會(huì)出現(xiàn)新的編譯問題,是什么問題先按下不表。
想要簡(jiǎn)單的解決加上@Builder之后就會(huì)報(bào)錯(cuò)的問題,那么直接把父類的@Builder這個(gè)注解拿掉就行了,不過這時(shí)無法設(shè)置父類的屬性,如果還想在子類中使用構(gòu)建器模式來初始化父類的屬性,還有另一種方法,在子類中實(shí)現(xiàn)一個(gè)能夠初始化父類屬性的構(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; ? ? } }
不過使用這種方法只能解決子類使用@Builder的問題,但是在更多的時(shí)候,父類也是需要@Builder這個(gè)注解的,那么在這種情況下應(yīng)該怎么解決呢?
而且這時(shí)還會(huì)有另一個(gè)新的問題出現(xiàn),使用了@Data注解和@Builder注解的子類無法使用無參構(gòu)造器來創(chuàng)建對(duì)象,這時(shí)需要在子類上顯式的加上@NoArgsConstructor這個(gè)注解才能解決。
如果要更細(xì)致的分析,就得從從@Builder的原理說起,了解@Builder到底生成了哪些代碼?
這一步可以自己編譯代碼看看,當(dāng)然如果自己寫過builder建造者模式的實(shí)現(xiàn),應(yīng)該能想到他是實(shí)現(xiàn)了一個(gè)名稱以Builder為后綴的靜態(tài)內(nèi)部類,在調(diào)用build()方法的時(shí)候調(diào)用外部類的全參構(gòu)造方法來生成外部類的實(shí)例。
回到之前的問題,當(dāng)子類和父類同時(shí)存在@Builder注解時(shí),在解決了構(gòu)造器異常之后,如果編譯代碼,會(huì)出現(xiàn)異常:
Error:(164, 5) java: org.example.Child中的builder()無法覆蓋org.example.Parent中的builder()
返回類型org.example.Child.ChildBuilder與org.example.Parent.ParentBuilder不兼容
這里的問題就簡(jiǎn)單一些了,父類的builder()方法返回的是ParentBuilder這個(gè)靜態(tài)內(nèi)部類類型的對(duì)象,而子類生成的builder()方法返回的是ChildBuilder這個(gè)類型的對(duì)象。
兩者的名稱重復(fù)了,而由于返回類型不兼容而無法按覆蓋。
根據(jù)@Builder注解的源碼可以發(fā)現(xiàn)名稱是可以自定義的,于是可以通過給子類builder方法自定義名稱的方式來解決這個(gè)問題。
最終的代碼:
@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來解決這個(gè)問題,不過我沒有用過,而且從網(wǎng)上搜索出來的結(jié)果來看,還是存在一些問題的,建議謹(jǐn)慎升級(jí)。
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java動(dòng)態(tài)規(guī)劃之硬幣找零問題實(shí)現(xiàn)代碼
這篇文章主要介紹了Java動(dòng)態(tài)規(guī)劃之硬幣找零問題實(shí)現(xiàn)代碼,具有一定參考價(jià)值,需要的朋友可以了解下。2017-11-11SpringBoot中基于JWT的單token授權(quán)和續(xù)期方案步驟詳解
在前后端分離架構(gòu)中,用戶登錄后,后端生成JWT?Token返給前端存于LocalStorage,每次請(qǐng)求攜帶Token驗(yàn)證身份,后端校驗(yàn)其有效性,本文給大家介紹SpringBoot中基于JWT的單token授權(quán)和續(xù)期方案步驟詳解,感興趣的朋友一起看看吧2024-09-09MyBatis-Plus中自動(dòng)填充功能的用法示例詳解
有些時(shí)候我們可能會(huì)有這樣的需求,插入或者更新數(shù)據(jù)時(shí),希望有些字段可以自動(dòng)填充數(shù)據(jù),比如密碼、version、注冊(cè)時(shí)默認(rèn)的用戶角色等,在MP中提供了這樣的功能,可以實(shí)現(xiàn)自動(dòng)填充功能,需要的朋友可以參考下2022-12-12SpringSecurity數(shù)據(jù)庫進(jìn)行認(rèn)證和授權(quán)的使用
本文主要介紹了用戶的賬號(hào)、密碼以及角色信息在數(shù)據(jù)庫中的認(rèn)證和授權(quán),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08SpringBoot異常錯(cuò)誤頁面實(shí)現(xiàn)方法介紹
在項(xiàng)目訪問的時(shí)候我們經(jīng)常會(huì)發(fā)生錯(cuò)誤或者頁面找不到,比如:資源找不到404,服務(wù)器500錯(cuò)誤,默認(rèn)情況下springboot的處理機(jī)制都是去跳轉(zhuǎn)內(nèi)部的錯(cuò)誤地址:/error 和與之對(duì)應(yīng)的一個(gè)錯(cuò)誤頁面2022-09-09SpringBoot導(dǎo)入mail依賴報(bào)錯(cuò)問題解決
這篇文章主要介紹了SpringBoot導(dǎo)入mail依賴報(bào)錯(cuò)問題解決,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10springboot中使用過濾器,jsoup過濾XSS腳本詳解
這篇文章主要介紹了springboot中使用過濾器,jsoup過濾XSS腳本詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12