通過簡單的Spring方面擺脫null參數

什么是世界上最令人討厭的,同時也是最受歡迎的例外?

我敢打賭這是NullPointerException。

NullPointerException可以表示任何東西,從簡單的“ ups,我認為不能為空”到數小時和數天的第三方庫調試(我敢于嘗試使用Dozer進行復雜的轉換)。

有趣的是,擺脫代碼中的所有NullPointerExceptions很簡單。 這種瑣碎性是一種稱為“ 按合同設計 ”的技術的副作用。

我不會詳細介紹該理論,您可以在Wikipedia上找到所需的所有內容,但在簡而言之,按合同設計意味著:

  • 每個方法都有一個先決條件(調用前期望的條件)
  • 每個方法都有一個后置條件(它保證什么,返回什么)
  • 每個類對其狀態都有約束(類不變)

因此,在每種方法的開頭,您都要檢查是否滿足先決條件,最后檢查是否滿足后置條件和不變式,如果出了問題,則拋出異常,指出錯誤之處。

使用Spring的內部靜態方法引發適當的異常(IllegalArgumentException),它看起來可能像這樣:

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);}
}

您還可以使用來自Apache Commons的Validate類,而不是spring的notNull / hasText。

通常,我只檢查先決條件,并為后置條件和約束編寫測試。 但這仍然是所有樣板代碼。 要將其移出類,可以使用許多“按合同設計”庫,例如
SpringContracts或Contract4J 。 無論哪種方式,您最終都會檢查每種公共方法的前提條件。

你猜怎么著? 除了數據傳輸對象和某些設置器外,我編寫的每個公共方法都希望其參數不為空。

因此,為了節省一些編寫此樣板代碼的文字,如何添加一個簡單的方面(將使其在整個應用程序中不可能),將null傳遞給DTO和setter之外的其他事物呢? 沒有任何其他庫(我假設您已經在使用Spring Framework),注釋以及其他功能。

為什么我不想在參數中允許使用空值? 因為我們在現代語言中有方法重載。 認真地說,您希望多久看到一次這樣的事情:

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);


解決方案

因此,這是一個簡單的解決方案:您將一個類添加到您的項目,并添加幾行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配置在這里(請記住,要更改項目的名稱空間)。

<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>

“ &&”沒有錯誤,只是在XML中轉義了&&條件。 如果您不了解Aspectj切入點定義語法,這是一些備忘單 。

這是一個測試,告訴我們配置已成功。

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是一個簡單的類,用于啟動彈簧測試上下文。 您可以將AbstractTransactionalJUnit4SpringContextTests與@ContextConfiguration(..)結合使用。

抓住

是的,有一個陷阱。 由于spring AOP使用基于接口的J2SE動態代理或aspectj CGLIB代理,因此每個類都將需要接口(用于基于簡單代理的方面編織)或不帶任何參數的構造函數(用于cglib編織)。 好消息是構造函數可以是私有的。

參考: Solid Craft博客上的JCG合作伙伴 Jakub Nabrdalik 通過簡單的spring方面消除了空參數 。

翻譯自: https://www.javacodegeeks.com/2012/11/getting-rid-of-null-parameters-with-a-simple-spring-aspect.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/370576.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/370576.shtml
英文地址,請注明出處:http://en.pswp.cn/news/370576.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

java arraylist排序_最全Java集合筆記

集合概述什么是集合集合框架&#xff1a;用于存儲數據的容器。集合框架是為表示和操作集合而規定的一種統一的標準的體系結構。任何集合框架都包含三大塊內容&#xff1a;對外的接口、接口的實現和對集合運算的算法。接口&#xff1a;表示集合的抽象數據類型。接口允許我們操作…

【3】JVM-OutOfMemory異常重現

JVM中常見的OOM&#xff0c;那么如何通過自己編寫代碼產生這些OOM異常呢&#xff1f;通過寫代碼重現異常&#xff0c;是為了避免在工作中寫出有OOM BUG的代碼。之前雖然看過相關文章&#xff0c;但是沒自己寫過這些代碼&#xff0c;這次在編寫的實際過程中&#xff0c;由于和書…

CachedIntrospectionResults 初始化

轉載于:https://www.cnblogs.com/xiluhua/p/7862985.html

為什么有些內聯(行內)元素可以設置寬高?

為什么有些內聯&#xff08;行內&#xff09;元素如img、input可以設置寬高&#xff1f; 在說明之前我們先來了解一些定義。 塊級元素和內聯元素&#xff1a; ①塊級元素總是獨占一行&#xff0c;表現為另起一行開始&#xff0c;而且其后的元素也必須另起一行顯示。 寬度(w…

mongo數據庫和mysql數據庫的區別_Mongodb與mysql數據庫的區別

MySQLMongoDB說明mysqldmongod服務器守護進程mysqlmongo客戶端工具mysqldumpmongodump邏輯備份工具mysqlmongorestore邏輯恢復工具db.repairDatabase()修復數據庫mysqldumpmongoexport數據導出工具sourcemongoimport數據導入工具grant * privileges on *.* to …Db.addUser()Db…

在Eclipse中高效運行HTTP / REST集成測試

最近&#xff0c;我有機會使用由我親愛的Holger Staudacher編寫的OSGi-JAX-RS-Connector庫。 通過連接器&#xff0c;您可以通過將Path注釋的類型注冊為OSGi服務來輕松發布資源-實際上&#xff0c;它工作得很好。 對于我來說&#xff0c;使用普通的JUnit測試編寫驅動的服務類測…

Eclipse安裝TestNG插件

Eclipse安裝TestNG插件 TestNG是什么? TestNG按照其文檔的定義是&#xff1a; TestNG是一個測試框架&#xff0c;其靈感來自JUnit和NUnit的&#xff0c;但引入了一些新的功能&#xff0c;使其功能更強大&#xff0c;使用更方便。 TestNG是一個開源自動化測試框架;TestNG表示下…

basicdatasourcefactory mysql_Java基礎-DBCP連接池(BasicDataSource類)詳解

Java基礎-DBCP連接池(BasicDataSource類)詳解作者&#xff1a;尹正杰版權聲明&#xff1a;原創作品&#xff0c;謝絕轉載&#xff01;否則將追究法律責任。實際開發中“獲得連接”或“釋放資源”是非常消耗系統資源的兩個過程&#xff0c;為了解決此類性能問題&#xff0c;通常…

生物神經網絡衍生出的算法

一個生物神經網絡的基本結構&#xff1a; 生物神經網絡由大量神經元組成&#xff0c;這些神經元之間通過突觸相互連接。神經元可以接收來自其他神經元的信號&#xff0c;并根據信號的強度和類型來調整自己的輸出信號。這種神經元之間的相互連接和信號傳遞形成了生物神經網絡的基…

echart實例數據 本地加載_JVM 類加載概述

來源&#xff1a;SegmentFault 思否社區作者&#xff1a;又壞又迷人JVM簡介JVM是Java Virtual Machine(Java虛擬機)的縮寫&#xff0c;JVM是一種用于計算設備的規范&#xff0c;它是一個虛構出來的計算機&#xff0c;是通過在實際的計算機上仿真模擬各種計算機功能來實現的。Ja…

JPA / Hibernate:基于版本的樂觀并發控制

本文是Hibernate和JPA中基于版本的樂觀并發控制的簡介。 這個概念已經很老了&#xff0c;上面已經寫了很多東西&#xff0c;但是無論如何我都看到了它被重新發明&#xff0c;誤解和濫用。 我在編寫它只是為了傳播知識&#xff0c;并希望引起人們對并發控制和鎖定的興趣。 用例…

高可用集群搭建

高可用集群搭建  創建hadoop賬戶 創建hadoop賬戶&#xff08;#注意&#xff0c;接下來的操作均在hadoop賬戶下運行&#xff09; # useradd hadoop # passwd hadoopsu - hadoopmkdir soft disk1 disk2mkdir -p disk{1,2}/dfs/{dn,nn}mkdir -p disk{1,2}/nodemgr/local 將本地目…

scrt如何切換成英文版_英文版SecureCRT顯示亂碼解決

英文版SecureCRT顯示亂碼解決系統環境&#xff1a;CentOS&#xff15;.&#xff16;以前Linux都是默認安裝在英文環境下&#xff0c;用英文版的SecureCRT查看系統內容輸出的也都是英文的&#xff0c;不會出現亂碼問題。今天同事在服務器安裝時默認選擇了簡體中文&#xff0c;這…

java try catch_Java捕獲異常

大家好&#xff0c;歡迎來到樂字節小樂的Java技術分享園地在Java中&#xff0c;凡是可能拋出異常的語句&#xff0c;都可以用try ... catch捕獲。把可能發生異常的語句放在try { ... }中&#xff0c;然后使用catch捕獲對應的Exception及其子類。多catch語句可以使用多個catch語…

haproxy文件操作

import os #導入os模塊def search(): #定義查找函數 with open(haproxy.txt,r) as f: #只讀方式打開文件 value input(請輸入您…

多語言持久性:帶有MongoDB和Derby的EclipseLink

從現在開始&#xff0c;多語種持久性一直是新聞。 從2011年底開始&#xff0c;在著名的Fowler帖子的推動下&#xff0c;我看到了更多更好的主意。 最新的一個是公司內部的學生項目&#xff0c;我們在其中使用Scala作為后端數據&#xff0c;將數據持久存儲到MongoDB&#xff0c;…

web前端開發最佳實踐--(筆記之JavaScript最佳實踐)

如何避免全局變量污染&#xff1f; 避免定義全局變量或全局函數用一個變量進行封裝&#xff0c;并返回外部需要訪問的接口如何寫出高維護的js代碼 配置數據和代碼邏輯分離 如&#xff1a; 改成&#xff1a; ---用js模板mustachehandlebarsjsMVC的數據模式 model&#xff1a;數據…

yum mysql5.7位置_CentOS yum 安裝 Mysql5.7

1 Steps for a Fresh Installation of MySQL# wget https://dev.mysql.com/get/mysql57-community-release-el6-9.noarch.rpm# yum localinstall mysql57-community-release-el6-9.noarch.rpm以上步驟其實是把 MySQL Yum repository 添加到了系統的 repository list 里去了。ll…

HTML/CSS基礎知識(四)

WEB標準和W3C的理解與認識 Web標準是一系列標準的集合。 網頁主要由三部分組成&#xff1a;結構&#xff08;Structure&#xff09;、表現&#xff08;Presentation&#xff09;和行為&#xff08;Behavior&#xff09;。 對應的標準也分三方面&#xff1a;結構化標準語言主要包…

python做一個系統代碼_python初學者,用python3實現基本的學生管理系統代碼實例...

這篇文章分享了管理系統&#xff0c;python學生管理系統的使用&#xff0c;這篇文章非常詳細地介紹了通過示例代碼實現的學生管理系統&#xff0c;該系統對每個人的研究或工作都有一定的參考學習價值。 這個是用python實現的基本的增刪改查的學生管理系統吧&#xff0c;其中主要…