通过简单的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.mzph.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;其中主要…