apache的BeanUtils的Converter被相互污染覆盖问题
问题描述
apache的BeanUtils工具集中用来把map对象转换为java对象的BeanUtils#populate方法会因为单例的原因其转换器Converter被相互污染覆盖问题
maven依赖
<dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</artifactId><version>1.9.4</version>
</dependency>
方法源码
public static void populate(final Object bean, final Map<String, ? extends Object> properties)throws IllegalAccessException, InvocationTargetException {// 源码此处获取的是单例对象BeanUtilsBean.getInstance().populate(bean, properties);
}
测试场景
场景一
map不存在属性时
测试代码
/*** map没有age属性*/
public static void test1() throws Exception {DemoObj fromObj = new DemoObj();Map<String, Object> map = Maps.newHashMap();map.put("name", "张三");BeanUtils.populate(fromObj, map);System.out.println(Thread.currentThread().getName() + ":没有age属性,转换器不生效:"+ JsonUtil.toStr(fromObj));
}
输出结果
main:没有age属性,转换器不生效:{"age":null,"name":"张三"}
场景二
map存在age属性,自带的转换器默认值为0
测试代码
/*** map存在age属性,自带的转换器默认值为0*/
public static void test2() throws Exception {DemoObj fromObj = new DemoObj();Map<String, Object> map = Maps.newHashMap();map.put("name", "李四");map.put("age", null);BeanUtils.populate(fromObj, map);System.out.println(Thread.currentThread().getName() +":自带的转换器默认值为0:"+JsonUtil.toStr(fromObj));
}
输出结果
main:自带的转换器默认值为0:{"age":0,"name":"李四"}
场景三
静态代码块注入自定义转换器,默认值设置为null
测试代码
static {ConvertUtils.register(new IntegerConverter(null), Integer.class);
}public static void test2() throws Exception {DemoObj fromObj = new DemoObj();Map<String, Object> map = Maps.newHashMap();map.put("name", "李四");map.put("age", null);BeanUtils.populate(fromObj, map);System.out.println(Thread.currentThread().getName() +":转换器默认值为:"+JsonUtil.toStr(fromObj));
}
输出结果
main:转换器默认值为:{"age":null,"name":"李四"}
场景四
在场景三的基础上,我们增加了一个转换器重新注册的函数调用,该函数会重置转换器对象
转换器重置的源代码
public static void deregister() {ConvertUtilsBean.getInstance().deregister();}// 获取的依旧是单例对象protected static ConvertUtilsBean getInstance() {return BeanUtilsBean.getInstance().getConvertUtils();}public void deregister() {converters.clear();registerPrimitives(false);registerStandard(false, false);registerOther(true);registerArrays(false, 0);register(BigDecimal.class, new BigDecimalConverter());register(BigInteger.class, new BigIntegerConverter());}
测试代码
static {ConvertUtils.register(new IntegerConverter(null), Integer.class);
}public static void test2() throws Exception {DemoObj fromObj = new DemoObj();Map<String, Object> map = Maps.newHashMap();map.put("name", "李四");map.put("age", null);BeanUtils.populate(fromObj, map);System.out.println(Thread.currentThread().getName() +":转换器默认值为:"+JsonUtil.toStr(fromObj));
}public static void test3() throws Exception {DemoObj fromObj = new DemoObj();Map<String, Object> map = Maps.newHashMap();map.put("name", "王五");map.put("age", null);BeanUtils.populate(fromObj, map);System.out.println(Thread.currentThread().getName() + ":age被赋值默认值:"+ JsonUtil.toStr(fromObj));// 重置转换器ConvertUtils.deregister();
}public static void main(String[] args) throws Exception {new Thread(()-> {try {// 睡眠,等test2先跑完Thread.sleep(1000);test2();} catch (Exception e) {throw new RuntimeException(e);}}).start();new Thread(()-> {try {test3();} catch (Exception e) {throw new RuntimeException(e);}}).start();}
输出结果
当前线程执行时,转换器还是静态代码块所注册的默认值为null的转换器,但是在test3执行完后会重置单例的转换器对象Thread-2:age被赋值默认值:{"age":null,"name":"王五"}所以线程睡眠结束后再执行转换时,发现转换器已被污染,转换的属性默认值非预期值Thread-1:转换器默认值为:{"age":0,"name":"李四"}
场景五
在场景四的基础上重新创建一个单例对象,并且该单例提前注册一个自定义默认值为null的的转换器
新增类
public class CustBeanUtils {private static final BeanUtilsBean beanUtilsBean;public CustBeanUtils() {}public static void populate(Object bean, Map<String, ? extends Object> properties) throws Exception {beanUtilsBean.populate(bean, properties);}static {ConvertUtilsBean convertUtilsBean = new ConvertUtilsBean();convertUtilsBean.register(new IntegerConverter(null), Integer.class);beanUtilsBean = new BeanUtilsBean(convertUtilsBean, new PropertyUtilsBean());}
}
测试代码
static {ConvertUtils.register(new IntegerConverter(null), Integer.class);
}public static void test2() throws Exception {DemoObj fromObj = new DemoObj();Map<String, Object> map = Maps.newHashMap();map.put("name", "李四");map.put("age", null);BeanUtils.populate(fromObj, map);System.out.println(Thread.currentThread().getName() +":转换器默认值为:"+JsonUtil.toStr(fromObj));
}public static void test3() throws Exception {DemoObj fromObj = new DemoObj();Map<String, Object> map = Maps.newHashMap();map.put("name", "王五");map.put("age", null);BeanUtils.populate(fromObj, map);System.out.println(Thread.currentThread().getName() + ":age被赋值默认值:"+ JsonUtil.toStr(fromObj));// 重置转换器ConvertUtils.deregister();
}public static void test4() throws Exception {DemoObj fromObj = new DemoObj();Map<String, Object> map = Maps.newHashMap();map.put("name", "赵六");map.put("age", null);CustBeanUtils.populate(fromObj, map);System.out.println(Thread.currentThread().getName() + ":CustBeanUtils 新建了一个BeanUtilsBean,不受其影响,age也不会被赋值默认值0:"+ JsonUtil.toStr(fromObj));
}public static void main(String[] args) throws Exception {new Thread(()-> {try {Thread.sleep(1000);test2();} catch (Exception e) {throw new RuntimeException(e);}}).start();new Thread(()-> {try {test3();} catch (Exception e) {throw new RuntimeException(e);}}).start();new Thread(()-> {try {Thread.sleep(2000);test4();} catch (Exception e) {throw new RuntimeException(e);}}).start();}
输出结果
线程2执行时,转换器还是静态代码块所注册的默认值为null的转换器,但是在test3执行完后会重置单例的转换器对象Thread-2:age被赋值默认值:{"age":null,"name":"王五"}所以线程1睡眠结束后再执行转换时,发现转换器已被污染,转换的属性默认值非预期值Thread-1:转换器默认值为:{"age":0,"name":"李四"}由于线程3用的是一个新的单例对象,所以其转换结果并不受原生的工具集中转换器重置的函数所影响Thread-3:CustBeanUtils 新建了一个BeanUtilsBean,不受其影响,age也不会被赋值默认值0:{"age":null,"name":"赵六"}
相关文章:
apache的BeanUtils的Converter被相互污染覆盖问题
问题描述 apache的BeanUtils工具集中用来把map对象转换为java对象的BeanUtils#populate方法会因为单例的原因其转换器Converter被相互污染覆盖问题 maven依赖 <dependency><groupId>commons-beanutils</groupId><artifactId>commons-beanutils</…...
TCP的“可靠性”(上)
目录 TCP的“可靠性”(上)确认应答(可靠性传输的基础)超时重传连接管理(三次握手,四次挥手) TCP的“可靠性”(上) 想必大家都或多或少的听说过TCP的特性:有连…...
超标量处理器设计笔记(5)虚拟存储器、地址转换、page fault
虚拟存储器 概述地址转换单级页表多级页表案例最好情况:虚拟地址是连续的最差情况:每个第二级 PT 都装有一项 增加级数 Page Fault 程序保护 概述 当程序比物理内存空间更大时,无法全部装在物理内存中,需要对程序进行切片 虚拟…...
SparkSQL 读写数据攻略:从基础到实战
目录 一、输入Source 1)代码演示最普通的文件读取方式: 2) 通过jdbc读取数据库数据 3) 读取table中的数据【hive】 二、输出Sink 实战一:保存普通格式 实战二:保存到数据库中 实战三:将结果保存在h…...
react 使用状态管理调用列表接口渲染列表(包含条件查询,统一使用查询按钮,重置功能),避免重复多次调用接口的方法
react开发调用api接口一般使用useEffect来监听值的变化,通过值的变化与否来进行接口调用。 比如我们要进行一个查询接口 const [pageParams, setPage] useState({name: ,id: ,});const [dataList, setDataList] useState([]);const getList async () > {const…...
Stable Audio Open模型部署教程:用AI打造独家节拍,让声音焕发新活力!
Stable Audio Open 是一个开源的文本到音频模型,允许用户从简单的文本提示中生成长达 47 秒的高质量音频数据。该模型非常适合创建鼓点、乐器即兴演奏、环境声音、拟音录音和其他用于音乐制作和声音设计的音频样本。用户还可以根据他们的自定义音频数据微调模型&…...
加油站-(贪心算法)
题目描述 在一条环路上有 n 个加油站,其中第 i 个加油站有汽油 gas[i] 升。 你有一辆油箱容量无限的的汽车,从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发,开始时油箱为空。 给定两个整数数组 gas…...
k8s-持久化存储PV与PVC(1)
1、概述 为什么 kubernetes 要持久化存储? 在 kubernetes 中部署应用都是以 Pod 的容器运行的,而 Pod 是有生命周期,一旦 Pod 被删除或重启后,这些数据也会随着丢失,则需要对这些数据进行持久化存储。 PV࿱…...
Linux Red Hat Enterprise
下载 https://developers.redhat.com/products/rhel/download 安装...
《中型 Vue 项目:挑战与成长》
一、引言 在当今的前端开发领域,Vue 作为一款渐进式 JavaScript 框架,以其强大的功能和灵活性备受开发者青睐。对于中型 Vue 项目而言,其重要性不言而喻。中型 Vue 项目通常在功能复杂度和规模上介于小型项目和大型项目之间,既需要…...
配置 DNS over HTTPS阻止DNS污染
概念介绍 DOH简介 DNS(域名系统)的主要功能是将域名解析成IP地址,域名的解析工作由DNS服务器完成。从安全角度来看,域名解析的请求传输时通常不进行任何加密,这导致第三方能够很容易拦截用户的DNS,将用…...
Facebook广告文案流量秘诀
Facebook 广告文案是制作有效 Facebook 广告的关键方面。它侧重于伴随广告视觉元素的文本内容。今天我们的博客将深入探讨成功的 Facebook 广告文案的秘密! 一、广告文案怎么写? 正文:这是帖子的正文,出现在您姓名的正下方。它可…...
22. 五子棋小游戏
文章目录 概要整体架构流程技术名词解释技术细节小结 1. 概要 🔊 JackQiao 对 米粒 说:“今天咱们玩个五子棋小游戏,电脑与你轮流在一个 nn 的网格上放置棋子(X 或 O),网格由你输入的正整数n决定࿰…...
fastadmin框架同时使用 阿里云oss和阿里云点播
背景 项目的实际需求中既要用到阿里云oss产品又用到阿里云点播系统,实现完美的统一。设置两个地址downUrl,thirdCode。分别代表阿里云oss上传路径和阿里云点播系统vId。 实现 默认框架你已经集成好阿里云oss集成工作,前端html页面实现 <…...
Java-JMX 组件架构即详解
JMX架构由三个主要组件构成: MBeans(Managed Beans):代表可管理的资源,是JMX的核心。MBean可以是Java类或接口,提供了管理操作的接口,如获取系统信息、设置参数等。MBeanServer&#x…...
unity打包web,发送post请求,获取地址栏参数,解决TypeError:s.replaceAll is not a function
发送post请求 public string url "http://XXXXXXXXX";// 请求数据public string postData "{\"user_id\": 1}";// Start is called before the first frame updatevoid Start(){// Post();StartCoroutine(PostRequestCoroutine(url, postData…...
java+ssm+mysql校园物品租赁网
项目介绍: 使用javassmmysql开发的校园物品租赁网,系统包含管理员、用户角色,功能如下: 管理员:用户管理;物品管理(物品种类、物品信息、评论信息);订单管理࿱…...
Spring Boot中实现JPA多数据源配置指南
本文还有配套的精品资源,点击获取 简介:本文详细介绍了在Spring Boot项目中配置和使用JPA进行多数据源管理的步骤。从引入依赖开始,到配置数据源、创建DataSource bean、定义实体和Repository,最后到配置事务管理器和使用多数据…...
服务器加固
1.服务器密码复杂度 密码最小长度,密码复杂度策略 vim /etc/pam.d/system-auth --------------- #密码配置 #ucredit:大写字母个数;lcredit:小写字母个数;dcredit:数字个数;ocredit:…...
探索CSS中的背景图片属性,让你的网页更加美观
导语:在网页设计中,背景图片的运用能够丰富页面视觉效果,提升用户体验。本文将详细介绍CSS中背景图片的相关属性,帮助大家更好地掌握这一技能。 一、背景图片基本属性 1、background-image 该属性用于设置元素的背景图片。语法如…...
FTDI FT2232H USB转JTAG实战指南:MPSSE配置与多设备调试
1. FT2232H与JTAG基础入门 第一次接触FT2232H这块芯片时,我完全被它的多功能性震惊了。这块小小的USB转接芯片不仅能处理UART通信,还能通过MPSSE引擎模拟JTAG、SPI、I2C等多种协议。对于嵌入式开发者来说,这简直就是调试神器。 FT2232H最吸引…...
c++ 字符大小写转化
#include <iostream> using namespace std;int main() {char a;cin >> a;//a-z-97-122//A-Z-65-90//差32//小写转大写 if(97<(int)a && (int)a<122){a(int)a-32;cout << a; return 0; }//大写转小写 if(65<(int)a && (int)a<90)…...
all-MiniLM-L6-v2保姆级教程:Ollama模型卸载、版本回滚与缓存清理指南
all-MiniLM-L6-v2保姆级教程:Ollama模型卸载、版本回滚与缓存清理指南 1. 为什么需要管理你的Ollama模型? 你可能已经用Ollama成功部署了all-MiniLM-L6-v2,体验了它轻量高效的句子嵌入能力。但用久了你会发现,硬盘空间在悄悄减少&…...
【CPython 3.13无锁并发白皮书】:全球首批实测团队披露的4类典型崩溃场景与修复参数
第一章:Python 无锁 GIL 环境下的并发模型配置概览Python 的全局解释器锁(GIL)本质上限制了 CPython 中多线程对 CPU 密集型任务的并行执行能力。然而,“无锁 GIL 环境”并非指 GIL 被移除,而是指通过绕过 GIL 依赖的并…...
【Python SM9性能生死线】:当SM9签名延迟突破120ms,你必须立即检查的4个Cython绑定陷阱
第一章:Python SM9性能生死线的临界认知SM9作为我国自主设计的标识密码算法标准(GB/T 38635–2020),其在Python生态中的实现常因底层运算瓶颈而陷入“可运行但不可用”的灰色地带。性能临界点并非由单一因素决定,而是密…...
上周刚把三菱PLC+MCGS的电机测速课设收尾,趁着热乎劲把细节唠唠,顺便把踩过的坑也记一下,省得下次忘光
No.1235 基于三菱 PLC和MCGS组态电机测速系统控制设计这个项目说白了就是用三菱PLC算电机的转速,再用MCGS组态屏把转速实时显示出来,用到的东西挺基础:FX3U PLC、1000线增量式编码器、直流减速电机、MCGS组态屏,再加一根USB转RS48…...
Umi-OCR插件技术方案:5款引擎深度对比与实战配置指南
Umi-OCR插件技术方案:5款引擎深度对比与实战配置指南 【免费下载链接】Umi-OCR_plugins Umi-OCR 插件库 项目地址: https://gitcode.com/gh_mirrors/um/Umi-OCR_plugins Umi-OCR插件库为开源OCR工具提供了丰富的引擎选择,从本地CPU加速到云端AI识…...
OpenClaw终端整合:QwQ-32B命令行操作增强方案
OpenClaw终端整合:QwQ-32B命令行操作增强方案 1. 为什么需要终端智能助手 作为开发者,我们每天要处理大量命令行操作。从简单的目录跳转、文件操作,到复杂的管道命令组合,再到调试报错信息,这些重复性工作消耗了大量…...
AI 开发实战:给团队定一套能落地的 AI 使用规范
AI 开发实战:给团队定一套能落地的 AI 使用规范 一、为什么团队用了 AI 反而容易更乱? 因为每个人都在各自试: 有人用来写代码有人用来写文档有人用来查错有人输出直接复制上线 如果没有基本规范,效率可能提升了,但风险…...
WorkBuddy杀疯了?一群AI专家帮我打工,我在微信里当赛博虾工头!
梦瑶 发自 凹非寺量子位 | 公众号 QbitAI到底是谁说,给老板打工自己就当不成老板的?又是谁说,龙虾不好用、还不听使唤的?反正这些事儿,现在跟我没啥关系了。毕竟现在的我,已经转头当起了「虾工头」…...
