javascript
通过简单的Spring方面摆脱null参数
什么是世界上最令人討厭的,同時(shí)也是最受歡迎的例外?
我敢打賭這是NullPointerException。
NullPointerException可以表示任何東西,從簡(jiǎn)單的“ ups,我認(rèn)為不能為空”到數(shù)小時(shí)和數(shù)天的第三方庫(kù)調(diào)試(我敢于嘗試使用Dozer進(jìn)行復(fù)雜的轉(zhuǎn)換)。
有趣的是,擺脫代碼中的所有NullPointerExceptions很簡(jiǎn)單。 這種瑣碎性是一種稱為“ 按合同設(shè)計(jì) ”的技術(shù)的副作用。
我不會(huì)詳細(xì)介紹該理論,您可以在Wikipedia上找到所需的所有內(nèi)容,但在簡(jiǎn)而言之,按合同設(shè)計(jì)意味著:
- 每個(gè)方法都有一個(gè)先決條件(調(diào)用前期望的條件)
- 每個(gè)方法都有一個(gè)后置條件(它保證什么,返回什么)
- 每個(gè)類對(duì)其狀態(tài)都有約束(類不變)
因此,在每種方法的開(kāi)頭,您都要檢查是否滿足先決條件,最后檢查是否滿足后置條件和不變式,如果出了問(wèn)題,則拋出異常,指出錯(cuò)誤之處。
使用Spring的內(nèi)部靜態(tài)方法引發(fā)適當(dāng)?shù)漠惓?#xff08;IllegalArgumentException),它看起來(lái)可能像這樣:
import static org.springframework.util.Assert.notNull; import static org.springframework.util.StringUtils.hasText;public class BranchCreator {public Story createNewBranch(Story story, User user, String title) {verifyParameters(story, user, title);Story branch = //... the body of the class returnig an objectverifyRetunedValue(branch);return branch;}private void verifyParameters(Story story, User user, String title) {notNull(story);notNull(user);hasText(title);}private void verifyRetunedValue(Story branch) {notNull(branch);} }您還可以使用來(lái)自Apache Commons的Validate類,而不是spring的notNull / hasText。
通常,我只檢查先決條件,并為后置條件和約束編寫(xiě)測(cè)試。 但這仍然是所有樣板代碼。 要將其移出類,可以使用許多“按合同設(shè)計(jì)”庫(kù),例如
SpringContracts或Contract4J 。 無(wú)論哪種方式,您最終都會(huì)檢查每種公共方法的前提條件。
你猜怎么著? 除了數(shù)據(jù)傳輸對(duì)象和某些設(shè)置器外,我編寫(xiě)的每個(gè)公共方法都希望其參數(shù)不為空。
因此,為了節(jié)省一些編寫(xiě)此樣板代碼的文字,如何添加一個(gè)簡(jiǎn)單的方面(將使其在整個(gè)應(yīng)用程序中不可能),將null傳遞給DTO和setter之外的其他事物呢? 沒(méi)有任何其他庫(kù)(我假設(shè)您已經(jīng)在使用Spring Framework),注釋以及其他功能。
為什么我不想在參數(shù)中允許使用空值? 因?yàn)槲覀冊(cè)诂F(xiàn)代語(yǔ)言中有方法重載。 認(rèn)真地說(shuō),您希望多久看到一次這樣的事情:
Address address = AddressFactory.create(null, null, null, null);而且這也不是更好
Microsoft.Office.Interop.Excel.Workbook theWorkbook = ExcelObj.Workbooks.Open(openFileDialog.FileName, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
解決方案
因此,這是一個(gè)簡(jiǎn)單的解決方案:您將一個(gè)類添加到您的項(xiàng)目,并添加幾行spring IoC配置。
類(方面)如下所示:
import org.aspectj.lang.JoinPoint; import static org.springframework.util.Assert.notNull;public class NotNullParametersAspect {public void throwExceptionIfParametersAreNull(JoinPoint joinPoint) {for(Object argument : joinPoint.getArgs()) {notNull(argument);}} }Spring配置在這里(請(qǐng)記住,要更改項(xiàng)目的名稱空間)。
<aop:config proxy-target-class='true'> <aop:aspect ref='notNullParametersAspect'><aop:pointcut expression='execution(public * eu.solidcraft.*..*.*(..))&& !execution(public * eu.solidcraft.*..*Dto.*(..))&& !execution(public * eu.solidcraft.*..*.set*(..))' id='allPublicApplicationOperationsExceptDtoAndSetters'> <aop:before method='throwExceptionIfParametersAreNull' pointcut-ref='allPublicApplicationOperationsExceptDtoAndSetters'></aop:before> </aop:pointcut> <task:annotation-driven><bean class='eu.solidcraft.aspects.NotNullParametersAspect' id='notNullParametersAspect'></bean></task:annotation-driven></aop:aspect> </aop:config>“ &&”沒(méi)有錯(cuò)誤,只是在XML中轉(zhuǎn)義了&&條件。 如果您不了解Aspectj切入點(diǎn)定義語(yǔ)法,這是一些備忘單 。
這是一個(gè)測(cè)試,告訴我們配置已成功。
public class NotNullParametersAspectIntegrationTest extends AbstractIntegrationTest {@Resource(name = 'userFeedbackFacade')private UserFeedbackFacade userFeedbackFacade;@Test(expected = IllegalArgumentException.class)public void shouldThrowExceptionIfParametersAreNull() {//whenuserFeedbackFacade.sendFeedback(null);//then exception is thrown}@Testpublic void shouldNotThrowExceptionForNullParametersOnDto() {//whenUserBookmarkDto userBookmarkDto = new UserBookmarkDto();userBookmarkDto.withChapter(null);StoryAncestorDto ancestorDto = new StoryAncestorDto(null, null, null, null);//then no exception is thrown} }AbstractIntegrationTest是一個(gè)簡(jiǎn)單的類,用于啟動(dòng)彈簧測(cè)試上下文。 您可以將AbstractTransactionalJUnit4SpringContextTests與@ContextConfiguration(..)結(jié)合使用。
抓住
是的,有一個(gè)陷阱。 由于spring AOP使用基于接口的J2SE動(dòng)態(tài)代理或aspectj CGLIB代理,因此每個(gè)類都將需要接口(用于基于簡(jiǎn)單代理的方面編織)或不帶任何參數(shù)的構(gòu)造函數(shù)(用于cglib編織)。 好消息是構(gòu)造函數(shù)可以是私有的。
參考: Solid Craft博客上的JCG合作伙伴 Jakub Nabrdalik 通過(guò)簡(jiǎn)單的spring方面消除了空參數(shù) 。
翻譯自: https://www.javacodegeeks.com/2012/11/getting-rid-of-null-parameters-with-a-simple-spring-aspect.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的通过简单的Spring方面摆脱null参数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 开放式理财最低持有几天什么意思?
- 下一篇: 开放式理财多久结算利息?