手机版

详细讨论Java中net.sf.json包关于json和对象转换的坑

时间:2021-09-03 来源:互联网 编辑:宝哥软件园 浏览:

在Web开发过程中,数据交互是必不可少的,因此需要指定交互数据的相关格式,这样数据才能在客户端和服务器端之间传输。通常有两种数据格式:1。xml;2、JSON .一般来说,JSON是用来传输数据的。摘要:介绍了Java中JSON与对象转换时遇到的一些问题及相关建议。

首先,很明显,JSON有两个概念:

对象。这似乎是由JavaScript定制的,但作为语法,它是独立于语言和平台的。只是指我们在客户端(浏览器)向服务器端传输数据时,通常使用JSON格式,而这种格式是用来表示JavaScript对象的。它由一系列“键值”组成,如{“id”: 1、“name”:“Kevin”},有点类似于Map键值对的存储方式。Java中描述的JSONObject实际上是指JSON Object类,在各种第三方的JSONjar包中通常以这个名字命名。不同的jar包有稍微不同的内部实现。

JSON字符串。JSON对象和JSON字符串之间的转换是一个序列化和反序列化的过程,就像Java对象的序列化和反序列化一样。在网络中,数据传输是通过字符串、二进制流等进行的。也就是说,当客户端(浏览器)需要以JSON格式传输数据时,此时是在网络中传输的string,而服务器肯定是以String(字符串类型)的形式接收数据的,所以有时需要先将JSON字符串转换为JSONObject,再进行下一步操作(字符串类型转换为JSON对象类型)。

以上两个概念的定义基本上定义了数据格式JSON,或者说JSON语法。Java中JSON的jar包有很多,最“常用”的一个就是“net.sf.json”提供的jar包。本文重点介绍这个坑包,尽管它有坑,但还是被广泛使用。其实还有其他优秀的JSON包供我们使用,比如阿里最快的JSON包——fastjson,谷歌的GSON和jackson。尝试,或者永远不要使用“net.sf.json”包。它不仅坑坑洼洼,而且非常古老。下载IDEA中的源代码太老了。Maven warehouse显示它在2010年停止了2.4版本的更新。先说说我知道的“net.sf.json”的两个bug(我觉得这是bug)以及这两个bug是怎么产生的。

Java中的JSON pit包——net.sf.json

1.当Java对象转换JSON对象时,get开头的所有方法都将被转换

这是什么意思?例如,存在以下Java对象。

包装sfjson导入Java . util . list;/** *凯文于2017年12月1日创建。*/public class Student { private int id;私人列表长课程号;public int GetID(){ return id;} public void SetID(int id){ this . id=id;} public ListLong getCourseIds(){ return courseIds;} public void setCourseIds(ListLong courseIds){ this . courseIds=courseIds;} public String getSql() {//没有对应的属性字段返回“这是Sql。”;}}当我们将Student对象转换为JSON对象时,希望转换后的JSON格式应该是:

{'id' : 1,' courseids' : [1,2,3]}但是,JSON对象JSON=JSON对象。使用“net.sf.json”包的from对象(学生);API转换的结果是:

也就是说,可以猜测“net.sf.json”在Java对象中获取公共修饰符get开头的方法,并将其后缀定义为json对象的“key”,而get开头的方法返回值定义为key对应的“value”。请注意,它是公共修饰符get开头的方法,并且有一个返回值。

我认为这是一个不合理的转换规则。如果我在Java对象中定义一个方法,就因为这个方法以“get”开头,有返回值,就作为转换后的JSON对象的“键值”,岂不是暴露了?还是返回客户端(浏览器)时直接暴露在前控制台?作者指定了这个转换规则,我认为可能的原因是,既然您将它定义为公共方法并将其命名为get,那么您就有意公开了这个方法,以便调用它的客户端可以获取它。但我还是觉得不合理,甚至我把它定义为bug。我这样定义可能不太合理,因为根据我的实际测量,不仅“net.sf.json”包会按照这个规则进行转换,fastjson和jackson也会遵循这个规则,但是谷歌的GSON并不会按照这个规则将对象转换成json。

传递jsonobject JSON=jsonobject。fromobject(学生);将构造的Student对象转换为JSON对象,Student如上所述。输入此方法后,将继续调用fromObject(Object,JsonConfig)的重载方法。在这种重载的方法中,要转换的Object对象是否是枚举、标注等类型将由instanceOf来判断,这些特殊类型会有特殊的判断方法。在这种情况下,它是一个常见的Java POJO对象,所以它会进入_fromObject(Object,JsonConfig),在这个方法中会有一些判断。最后,JSON对象将通过调用defaultBeanProcessing来创建。这个方法是关键,并且“PropertyDescriptor”将通过propertyutils获得。getpropertydescriptors (bean)方法,它实际上是一个带有get的方法,在这里封装为propertydescriptor。这个班有四个学生:getClass、getId、getCourseIds和getSql。

实际上,PropertyDescriptor已经被详细封装了,所有的读写方法都已经分配好了。

例如,这个getSql方法已经被解析为上图中的PropertyDescriptor。后来,一些方法通过这个类被过滤掉了。例如,getClass方法不是POJO中的方法,所以没有必要将其转换为JSON对象。而PropertyDescriptor是通过BeanInfo # getpropertydescriptors获取的,而BeanInfo是通过新的内省器(beanclass,null,use _ all _ beaninfo)获取的。getbeanfo();深入下去,最终会得出以下方法。

private BeanInfo getBeanInfo()引发IntraspectionException {…method descriptor MDS[]=GetTargetMethodInfo();//这个方法中会调用getPublicDeclaredMethods,可以看出它确实是一个搜索公共方法,而且是所有的公共方法,包括wait等property descriptors PDS[]=gettargetpropertytinfo();//按照一定的规则过滤。过滤规则都在这个方法中,即选择带有get前缀和返回值的公共修饰符的方法.简单分析了net.sf.json的源代码后发现,正如猜测的那样,具体的源代码有很多,需要自己去查,自己去跟踪。

2.当JSON对象被转换成Java对象时,ListLong会有转换错误

标题一句话也解释不清楚。我绝对认为这个问题是个bug。

有一个JSON字符串为{'id' : 1,' courseids' : [1,2,3]},需要转换成上面提到的Student对象。Student对象中有两个int和ListLong类型的属性字段,这意味着这个JSON字符串应该转换成相应的数据类型。

String json=' { \ ' id \ ' : 1,\ ' courseIdS ' :[1,2,3]} ';Student Student=(Student)JSON object . toban(JSON object . from object(JSON),Student . class);system . out . println(student . getcourseids()。获取(0)个Long的实例;

上面的输出应该是真的,但不幸的是它是假的。准确地说,它在编译时是Long,在运行时是Integer。这不得不说是一个坑,其他三个JSON包都没有这样的错误。所以我确定这是一个bug。让我们看看这个bug是如何在net.sf.json中发生的。您还需要通过比较源代码来检查它。当我深入断点调试时,当我发现net.sf.json正在处理整数数据时,我发现了这个方法,NumberUtils#createNumber。这个类在从字符串中取出数据时判断数据类型。原意是把后面跟“L”或“L”的数字当作Long类型。从这个角度来看,最后的结果应该是正确的。

case ' L ' : case ' L ' : if(dec==null exp==null(numeric . charat(0)='-' isDigits(numeric . substring(1))| | isDigits(numeric))){ try { return createLong(numeric);} catch(NumberformatException var11){ return createBigInteger(数值型);} } else { throw new numberformateexception(str)不是有效的数字。);}截至目前,net.sf.json已经通过编号后的标识符准确判断了数据类型。问题在于获取这个值及其数据类型后,需要存储在JSONObject中,存储过程中存在方法JSONUtils#transformNumber。至少目前来看,这种方法的存在纯粹是多余的。

公共静态数字转换数字(数字输入)Float的输入实例){返回新的Double(input . tostring());} else if(Short的输入实例){返回新的Integer(input . int value());} else if(输入instanceof Byte) {返回新的整数(input . int value());} else { if(Long的输入实例){ Long max=new Long(2147483647 L);If(输入。long value()=max . long value(). input . long value()=-2147483648 l){//即使原始类型很长,只要在Integer范围内,最终都会转换为Integer。返回新的整数(input . int value());} }返回输入;}}上面的代码很清楚的说明了罪魁祸首,不管是Long类型(整数范围内的Long类型),包括Byte和Short,都会转换为Integer。我不知道这个代码是什么意思。确切的数据类型要根据数字后面的字母来确定,然后确切的数据类型要转换一次,导致了开头提到的bug。这个问题几乎是不可避免的,所以最好的办法就是不用。

这两个坑是偶然发现的,建议不要使用长期没有维护的net.sf.json的JSON包。另外,net.sf.json包对JSON格式的验证没有那么严格,如果这样的格式是“{'ID' : 1,' Course IDs' :' [1,2,3]'}”,

以上关于JSON的坑和Java net . SF . JSON包中对象传递的细节,都是边肖分享的内容。希望能给大家一个参考,多支持我们。

版权声明:详细讨论Java中net.sf.json包关于json和对象转换的坑是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。