Jackson进行Json反序列化对于一个小写字母开头后跟大写字母无法识别反序列成功问题

news2024/11/24 22:39:29

问题描述

json数据:{“pTargetId”:“123”}
javaBean:

    @Data
    public static class Test {
        private String pTargetId;
    }

运行下面代码:

    public static void main(String[] args) throws JsonProcessingException {
        String json = "{\"pTargetId\":\"123\"}";
        ObjectMapper objectMapper=new ObjectMapper();
        Test test = objectMapper.readValue(json, Test.class);
    }

报错:

Exception in thread "main" com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "pTargetId" 

这个报错的意思很明显,从json中没有解析出对象的pTargetId字段,但明显我们知道json中是存在这个属性字段的。

通过设置

objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//可以将jackson设置为不需要json中包含javaBean中的属性字段。

在这里插入图片描述
这里报错倒是解决了,但是本质问题还是没有解决也就是为什么json中有pTargetId,但是转换成对象后属性值确实空的。

Gson,fastjson,hutool的不存在这个问题

导致原因

jackson在识别对象的属性name时,会通过两种方式,第一通过field的name,第二种通过javaBean规范获取getXxx()方法解析属性名。
它出问题的地方是方法二,通过getXxx()解析属性名。

源码位置

public class DefaultAccessorNamingStrategy extends AccessorNamingStrategy {

	/**
	* Method called to figure out name of the property, given corresponding suggested 			name based on a method or field name.
	* Params:
	* basename – Name of accessor/mutator method, not including prefix ("get"/"is"/"set")
	*
	* 这个方法就是用来解析getXxx方法,basename:就是getXxx字符串 offset对于getXxx就是3,对于isXxx就是2
	* 下面的说明都针对 getPTargetId() 这个方法
	**/
	protected String legacyManglePropertyName(final String basename, final int offset)
    {
        final int end = basename.length();
        if (end == offset) { // empty name, nope
            return null;
        }
		
		//获取方法的首字母 也就是P        

        char c = basename.charAt(offset);
        // 12-Oct-2020, tatu: Additional configurability; allow checking that
        //    base name is acceptable (currently just by checking first character)
        if (_baseNameValidator != null) {
            if (!_baseNameValidator.accept(c, basename, offset)) {
                return null;
            }
        }

        // next check: is the first character upper case? If not, return as is
        //将首字母变更为小写
        char d = Character.toLowerCase(c);
        
        //如果首字母是小写,直接返回get后的字符串 (getaaa() 返回的就是aaa)
        if (c == d) {
            return basename.substring(offset);
        }
        // otherwise, lower case initial chars. Common case first, just one char
        StringBuilder sb = new StringBuilder(end - offset);
        //将小写的首字母放到要输出的字符串中
        sb.append(d);
        //从首字母后的字母开始
        int i = offset+1;
        for (; i < end; ++i) {
            c = basename.charAt(i);
            d = Character.toLowerCase(c);
            //如果字母为小写,则将当前以及后面的字符全部加入到输出的字符串中
            if (c == d) {
                sb.append(basename, i, end);
                break;
            }
            //如果字母为大小,则调整为小写然后加入到字符串中
            sb.append(d);
        }
        /**
        * 针对于 getPTargetId()方法,则返回的字符串为 ptargetId
		*  pTargetId 属性字段,生成get方法的规范就是get后首字母大写
		*  所以其get方法为getPTargetId()
        **/
        return sb.toString();
    }

}

那么上述方法在哪调用的呢?

public class POJOPropertiesCollector
{
	protected void collectAll()
    {
        LinkedHashMap<String, POJOPropertyBuilder> props = new LinkedHashMap<String, POJOPropertyBuilder>();

        // First: gather basic data
        //通过属性直接获取其名称
        _addFields(props); // note: populates _fieldRenameMappings
        //通过上面我们讲解的方法获取名(层级比较深)
        _addMethods(props);
        // 25-Jan-2016, tatu: Avoid introspecting (constructor-)creators for non-static
        //    inner classes, see [databind#1502]
        if (!_classDef.isNonStaticInnerClass()) {
            _addCreators(props);
        }

        // Remove ignored properties, first; this MUST precede annotation merging
        // since logic relies on knowing exactly which accessor has which annotation
        _removeUnwantedProperties(props);
        // and then remove unneeded accessors (wrt read-only, read-write)
        _removeUnwantedAccessor(props);
		
		.....忽略的代码
    }

}

上面源码的思路是,最后我们会生成一个LinkedHashMap<String, POJOPropertyBuilder> props,其中key为名称,value为对应的属性构建对象。
什么意思呢,比如我们json数据{"pTargetId":"123"},那么最后只有在map中含有key:pTargetId的builider才能进行写入。

而这个map的生成可以通过_addFields(props)方法,去解析类的属性名称来进行获取到,也可以通过_addMethods(props),刚才说的通过解析getXxx()方法来获取到。

所以到这里我们的Test类的map应该有两个值,一个是通过属性解析出来的pTargetId和通过方法解析出来的ptargetId
在这里插入图片描述
那么虽然通过方法获取的key错误了(ptargetId),但不是还有通过属性正确获取的吗(pTargetId),为什么最后还是没赋值进去?这是因为下面这个方法:

        _removeUnwantedProperties(props);

这个方法将会把某些不合规的属性值给移除掉,针对于属性类型获取的key,如果你的属性范围为private,那么就会将你过滤掉(过滤逻辑比较简单,可以自己追下去看看)
在这里插入图片描述
所以最后只有错误的ptargetId存在。

解决方案

原因知道了,方案就很简单了,就是想办法将它的key变更对(非常不符合直觉,满足json规范,满足javaBean规范,最后却不能正确转成功,因该是Bug范畴了吧)

  1. 换工具,Gson,fastjson符合直觉,能填充成功(Gson这块代码非常清晰,思路符合直觉)
  2. private pTargetId修改为public pTargetId
  3. 自己实现get方法
        public String getpTargetId() {
           return pTargetId;
       }
  1. 使用@JsonProperty(value = "pTargetId")注解
    等等

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1343365.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

docker入门概念详解

本篇文章对docker的一些基础概念和周边概念进行了详细解释。帮助你可以很好的理解docker是用来干什么的&#xff0c;docker是怎么工作的。其中有docker所运用到的技术解释&#xff0c;docker的不同发展版本&#xff0c;dokcer的架构&#xff0c;docker的生态等等详解。希望本片…

flink generic log-based incremental checkpoints 设计

背景 flink 在1.15版本后开始提供generic log-based incremental checkpoints的检查点方案&#xff0c;目的在于减少checkpoint的耗时&#xff0c;尽量缩短端到端的数据处理延迟&#xff0c;本文就来看下这种新类型的checkpoint的设计 generic log-based incremental checkpo…

GPT-3: Language Models are Few-Shot Learners

GPT-3 论文 数据集 CommonCrawl&#xff1a;文章通过高质量参考语料库对CommonCrawl数据集进行了过滤&#xff0c;并通过模糊去重对文档进行去重&#xff0c;且增加了高质量参考语料库以增加文本的多样性。WebText&#xff1a;文章采用了类似GPT-2中的WebText文档收集清洗方…

【FFI】N-API的JS堆对象生命周期管理

N-API的JS堆对象生命周期管理 N-API是Node API的简写&#xff0c;同时也是nodejs的JS VM&#xff08;链&#xff09;接入原生模块.node文件的应用程序二进制接口(i.e. ABI)。借助N-API引入的抽象隔离&#xff0c;升级nodejs运行时&#xff08;虚拟机&#xff09; 【编译】不要求…

米表网PHP域名销售管理系统网站源码 自适应电脑+手机端

PHP域名销售管理系统网站源码 自适应电脑手机端 功能使用简单&#xff0c;不复杂&#xff0c;非常适合个人米表使用&#xff0c;带广告栏 源码下载&#xff1a;https://download.csdn.net/download/m0_66047725/88646799

Spring Boot整合GraphQL

RPC选型入门测试系列文章 GraphQL是一种用于API开发的查询语言和运行时环境。它由Facebook开发并于2015年开源。GraphQL的主要目标是提供一种更高效、灵活和易于使用的方式来获取和操作数据。与传统的RESTful API相比&#xff0c;GraphQL允许客户端精确地指定需要的数据&#…

C语言实例_stdlib.h库函数功能及其用法详解

一、前言 C语言作为一种高效、灵活的编程语言&#xff0c;标准库的使用对于开发人员来说是不可或缺的。其中&#xff0c;stdlib.h是C语言中一个重要的标准库头文件&#xff0c;提供了许多常用的函数和工具&#xff0c;以便开发人员能够更加便捷地进行内存管理、字符串处理、随…

《深入理解JAVA虚拟机笔记》运行时栈帧、方法分派、动态类型

运行时栈帧结构 Java 虚拟机以方法作为最基本的执行单元&#xff0c;“栈帧”&#xff08;Stack Frame&#xff09;则是用于支持虚拟机进行方法调用和方法执行背后的数据结构&#xff0c;它也是虚拟机运行时数据区中的虚拟机栈的栈元素。栈帧存储了方法的局部变量表、操作数栈…

电气产品外壳常用材质PA、PC、PBT、ABS究竟是什么?

在如今工业制造领域&#xff0c;各种改性塑料、复合材料以及轻质合金材料的运用日趋成熟。在电气领域&#xff0c;不同电气产品的外壳、组件材质采用不同材料&#xff0c;以同为科技&#xff08;TOWE&#xff09;电气产品为例&#xff0c;工业连接器系列产品采用PA6外壳材质、机…

python+django网上购物商城系统o9m4k

语言&#xff1a;Python 框架&#xff1a;django/flask可以定制 软件版本&#xff1a;python3.7.7 数据库&#xff1a;mysql 数据库工具&#xff1a;Navicat 开发工具pycharm/vscode都可以 前端框架:vue.js 系统使用过程主要涉及到管理员和用户两种角色&#xff0c;主要包含个…

javascript实现数据双向绑定

ES5中的双向绑定 ES5中的对象属性类型有两种&#xff1a;分别是数据属性和访问器属性 一&#xff0c;数据属性 数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有4个描述其行为的特性 1&#xff0c;configurable:表示能否通过delete删除属性而重新定义…

利用Pandas进行高效网络数据获取

利用Pandas进行高效网络数据获取 背景&#xff1a; ​ 最近看到一篇关于使用Pandas模块进行爬虫的文章&#xff0c;觉得很有趣&#xff0c;这里为大家详细说明。 基础铺垫&#xff1a; ​ pd.read_html pandas 库中的一个函数&#xff0c;用于从 HTML 页面中读取表格数据并…

CEC2017(Python):五种算法(PSO、RFO、SSA、DE、HHO)求解CEC2017

一、5种算法简介 1、粒子群优化算法PSO 2、红狐优化算法RFO 3、麻雀搜索算法SSA 4、差分进化算法DE 5、哈里斯鹰优化算法HHO 二、CEC2017简介 参考文献&#xff1a; [1]Awad, N. H., Ali, M. Z., Liang, J. J., Qu, B. Y., & Suganthan, P. N. (2016). “Problem de…

详解“量子极限下运行的光学神经网络”——相干伊辛机

量子计算和量子启发计算可能成为解答复杂优化问题的新前沿&#xff0c;而经典计算机在历史上是无法解决这些问题的。 当今最快的计算机可能需要数千年才能完成高度复杂的计算&#xff0c;包括涉及许多变量的组合优化问题&#xff1b;研究人员正在努力将解决这些问题所需的时间缩…

白话机器学习的数学-2-分类

1、设置问题 图片分类&#xff1a;只根据尺寸把它分类为 纵向图像和横向图像。 如果只用一条线将图中白色的点和黑色的点分开&#xff1a; 这次分类的目的就是找到这条线。 2、内积 找到一条线&#xff0c;这是否意味着我们要像学习回归时那样&#xff0c;求出一次函数的斜率…

写在2023岁末:敏锐地审视量子计算的当下

本周&#xff0c;《IEEE Spectrum》刊登了一篇出色的文章&#xff0c;对量子计算&#xff08;QC&#xff09;的近期前景进行了深入探讨。 文章的目的并不是要给量子计算的前景泼冷水&#xff0c;而是要说明量子计算的前景还很遥远&#xff0c;并提醒读者量子计算的用例可能很窄…

【Minikube Prometheus】基于Prometheus Grafana监控由Minikube创建的K8S集群

文章目录 1. 系统信息参数说明2. Docker安装3. minikube安装4. kubectl安装5. Helm安装6. 启动Kubernetes集群v1.28.37. 使用helm安装Prometheus8. 使用helm安装Grafana9. Grafana的Dashboard设定10. 设定Prometheus数据源11. 导入Kubernetes Dashboard12. 实验过程中的常见问题…

RabbitMQ之快速入门、上手

前言 学习一样新技术、新框架&#xff0c;最重要的是学习其思想、原理。即原理性思维。 如果是因为工作原因&#xff0c;需要快速上手RabbitMQ&#xff0c;本篇或许适合你。 核心概念 Connection&#xff1a;publisher&#xff0f;consumer 和 broker 之间的 TCP 连接Channel…

亚信安慧AntDB数据并行加载工具的实现(一)

1.概述 数据加载速度是评判数据库性能的重要指标&#xff0c;能否提高数据加载速度&#xff0c;对文件数据进行并行解析&#xff0c;直接影响数据库运维管理效率。基于此&#xff0c;AntDB分布式数据库提供了两种数据加载方式&#xff1a; 一是类似于PostgreSQL的Copy命令&am…

java spring boot 自定义 aop

以一个锁的加锁和释放为例 1、先定义注解 /*** 锁切面* author fmj*/ Retention(RetentionPolicy.RUNTIME) Target(ElementType.METHOD) public interface VersionLockAOP { }2、然后定义切面类以及切点 /*** 切面*/ Component Aspect Slf4j public class VersionLockAOPAspe…