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