BeanUtils.copyProperties()在Tomcat抛出NullPointerException,本地运行正常
解决BeanUtils.copyProperties()在Tomcat环境抛出NullPointerException的问题
这种情况我之前排查过好几次,大概率是版本差异或者类加载冲突导致的——毕竟本地和Tomcat环境的依赖加载逻辑不一样,咱们一步步来解决:
可能的原因分析
- Apache Commons BeanUtils版本问题:旧版本(比如1.8.0及之前)的BeanUtils在处理枚举类型(比如你User类里的
Role枚举)时,如果源对象的枚举属性为null,会触发NullPointerException。而你本地环境可能用的是修复了这个问题的新版本(比如1.9.x),所以运行正常。 - Tomcat类加载器冲突:Tomcat的全局
lib目录里可能存在一个旧版本的commons-beanutils.jar,项目部署后,Tomcat优先加载了全局库的旧版本类,导致和你项目依赖的版本不一致,触发异常。
具体解决方案
1. 统一并升级BeanUtils版本
确保项目依赖的是修复了null值处理问题的新版本,比如1.9.4(这个版本稳定性很好):
如果是Maven项目,在pom.xml里明确指定版本:
<dependency> <groupId>commons-beanutils</groupId> <artifactId>commons-beanutils</artifactId> <version>1.9.4</version> </dependency>
Gradle项目则在build.gradle里添加:
implementation 'commons-beanutils:commons-beanutils:1.9.4'
同时检查Tomcat的${CATALINA_HOME}/lib目录,如果发现旧版本的commons-beanutils.jar,直接删除,避免类加载冲突。
2. 替换为Spring的BeanUtils实现
如果你的项目本身依赖Spring框架,直接用Spring提供的org.springframework.beans.BeanUtils会更省心——它对null值、枚举类型的处理更健壮,几乎不会出现这种莫名的NPE:
修改你的saveUser方法:
import org.springframework.beans.BeanUtils; public void saveUser(UserDTO dto) { User user = new User(); // 换成Spring的BeanUtils BeanUtils.copyProperties(dto, user); session.beginTransaction(); session.save(user); session.getTransaction().commit(); }
注:Spring的copyProperties参数顺序和Apache的一致(源对象在前,目标对象在后),直接替换import即可,不用改方法参数顺序。
3. 手动处理枚举属性(临时方案)
如果暂时不能换版本或替换实现,可以先手动处理枚举属性,再调用BeanUtils:
public void saveUser(UserDTO dto) { User user = new User(); // 先手动设置枚举属性,避免BeanUtils处理null时抛NPE if (dto.getRole() != null) { user.setRole(dto.getRole()); } // 复制其他属性 BeanUtils.copyProperties(dto, user); session.beginTransaction(); session.save(user); session.getTransaction().commit(); }
不过这种方法比较繁琐,不推荐长期使用。
验证步骤
- 清理项目的依赖缓存(Maven执行
mvn clean install -U,Gradle执行clean build) - 打包war包后,解压查看
WEB-INF/lib目录,确认commons-beanutils的版本是你指定的新版本 - 重启Tomcat,重新部署测试
内容的提问来源于stack exchange,提问作者Pakanon Pantisawat
相关产品推荐
相关产品推荐

