delphi djson 类与JSON 互转,与 Java、Golang 一致写法

news/2025/1/5 17:14:05/文章来源:https://www.cnblogs.com/feng88/p/18650386

前因

为什么要开发这个 JSON库?原因是 delphi 官方的 json 既没有处理 null(也叫零值)的问题;举例说明吧:

开发者 往往 需要 类与JSON 之间 进行序列化 和 反序列化;接下来我们举个例子:

Person {id: Int64; // IDname: string; //姓名desc: string; //描述}

这样一个类 在 不同 语言里 如何 与 json 进行序列化 和 反序列化;

java 语言

在Java中,我们使用 json 往往很方便,因为 Java的 基本类型是包装类,具有自动装箱和拆箱功能,可以轻易解决 零值的问题;fastjson gson jackson 都可以,以 jackson举例:

public class Person {private Long id;private String name;private String desc;public Long getId() {return id;}public void setId(Long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getDesc() {return desc;}public void setDesc(String desc) {this.desc = desc;}
}

开始序列化和反序列化:

public class Test {public static void main(String[] args) throws JsonProcessingException {ObjectMapper objectMapper = new ObjectMapper();objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);Person person = new Person();person.setId(123L);person.setName("欧阳疯");//person.setDesc(""); 不设置,让其忽略 null 值//序列化String json = objectMapper.writeValueAsString(person);System.out.println(json); //{"id":123,"name":"欧阳锋"} 已忽略了 null值//反序列化Person person1 = objectMapper.readValue(json, Person.class);if(person1.getDesc() != null){ //反序列化后通过这个可以判断是否是nil值System.out.println("有设置");}else {//说明这个字段是未设置状态System.out.println("nil");}}
}

image

golang 语言

package mainimport ("encoding/json""fmt"
)type Person struct {Id   string  `json:"id"`Name string  `json:"name,omitempty"`Desc *string `json:"desc,omitempty"` //注意这里使用 *string + omitempty 来解决零值的问题
}func main() {// 赋值给 Person 结构体person := Person{Id:   "123",Name: "欧阳疯",//Desc: &desc, 使用指针赋值}//序列化为 JSONjsonData, err := json.Marshal(person)if err != nil {return}fmt.Println(string(jsonData)) //结果:{"id":"123","name":"欧阳疯"} 可见golang的序列化已给开发者忽略了 Nil值//反序列化var person1 Personerr = json.Unmarshal([]byte(jsonData), &person1)if err != nil {return}if person1.Desc != nil { //通过这样就可以判断是否是nilfmt.Println("有设置")} else {fmt.Println("nil")}
}

image

可见 golang 官方的 json库 针对 基本类型的指针类型,也自动给开发者专一处理了;也非常方便使用 json 与 结构体之间的转换;

delphi 语言

例子就不上了,目前无论是官方的 System.JSON 还是其它第三方的,都做不到 类 与 Json 的互转,并同时处理 ”零值“ 的问题;之所以不想上官方的例子了,是因为官方的 System.JSON 使用起来非常复杂,仅仅是一个 类的序列化 都需要很长的代码,甚至还得手工写字段名;估计这个 System.JSON 也没有人使用吧,为了节省篇幅,不上官方的例子了;

djson

在以上背景下,我们知道了 Java、C# 这类具有基本类型的包装类,自动拆箱和装箱的语言,对于JSON里的 null 值天生解决了;而对于 golang、c++、delphi 这类没有包装类的语言,就得想法解决了,最好是语言层面给解决;golang 就是这样,通过 指针 + golang官方的注解,就解决掉了 nil 的问题;而 delphi 目前官方的 json 库,并没有给出解决方案;于是就开发了 djson,设计JSON底层数据模型,并大量使用了 向量化(SIMD)指令(System.Math.Vectors)来加速;还是上面的那个例子,我们看下 djson 如何实现,用 delphi 可以实现类似 Java 的写法,也可以实现 类似 golang的写法,个人感觉 还是 Java的写法 更优雅些,决定采用 Java 的写法了;

  1. 与Java 一样,先定义一个 Person 类;
unit person;interfaceuses System.SysUtils;typeTPerson = classprivateid: PInt64;name: PString;desc: PString;publicdestructor Destroy; override;function idIsNull: Boolean;function getId: Int64;procedure setId(value: Int64);function nameIsNull: Boolean;function getName: string;procedure setName(value: string);function descIsNull: Boolean;function getDesc: string;procedure setDesc(value: string);end;implementationconst//可以定义在公共单元里nullMsg = '开发人员错误,此字段可能为Null,获取前要进行fieldIsNull判断,从而给其默认值或做出处理!';destructor TPerson.Destroy;
beginif id <> nil thenbeginDispose(id);end;if name <> nil thenbeginDispose(name);end;if desc <> nil thenbeginDispose(desc);end;inherited;
end;function TPerson.idIsNull: Boolean;
beginResult := (id = nil);
end;function TPerson.getId: Int64;
beginif id = nil thenbeginraise Exception.Create(nullMsg);end;Result := id^;
end;procedure TPerson.setId(value: Int64);
beginif id = nil thenbeginNew(id);end;id^ := value;
end;function TPerson.nameIsNull: Boolean;
beginResult := (name = nil);
end;function TPerson.getName: string;
beginif name = nil thenbeginraise Exception.Create(nullMsg);end;Result := name^;
end;procedure TPerson.setName(value: string);
beginif name = nil thenbeginNew(name);end;name^ := value;
end;function TPerson.descIsNull: Boolean;
beginResult := (desc = nil);
end;function TPerson.getDesc: string;
beginif desc = nil thenbeginraise Exception.Create(nullMsg);end;Result := desc^;
end;procedure TPerson.setDesc(value: string);
beginif desc = nil thenbeginNew(desc);end;desc^ := value;
end;end.
  1. 开始序列化 和 反序列化

    uses djson, person;procedure TFormMain.Button1Click(Sender: TObject);
    beginvar dj := TDJson.Create;try//序列化var person := TPerson.Create;person.setId(123);person.setName('欧阳疯');//person.setDesc() 不设置 忽略 null 值var json := dj.objToJson(person); //这一句 就行了Memo1.Lines.Add(json); //序列化后的结果//开始反序列化var person2 := TPerson.Create;dj.jsonToObj(json, person2);if not person2.descIsNull thenbeginMemo1.Lines.Add('有设置');end else begin //说明是nullMemo1.Lines.Add('nil');end;person.Free;person2.Free;finallydj.Free;end;
    end;
    

可见写法 几乎 与 Java 一模一样了,与 golang 也基本一样!!!使用起来非常简单;关于 那个 person 类的代码生成,Java Ide 是可以轻松生成的,但是 delphi 的IDE 无法生成,你可以自己写一个 生成器(不是IDE插件),而是一个软件,专一生成这种格式的 delphi 类;这样以后 你就可以快速 生成 各种 delphi 类,并将其 与 json 互转,且有 ”零值" 如:nameIsNull 的处理;另外我上面给的这个例子是简单的,你完全可以类与类互相嵌套,组成复杂的 类 ,依然可以 与 JSON 互转,包括 array、枚举等 都可以互相嵌套的;我下一篇博客会做一个 复杂的 嵌套类的例子;

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Windows更改远程桌面端口.241202

为了远程安全,默认在3389改为别的端口。 本示例为3389改为533891、步骤:打开“开始→运行”,输入“regedit”,打开注册表,进入以下路径: [HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server\Wds\rdpwd\Tds\tcp]修改PortNamber修改成所希望的端口即可…

数据分层 ODS DW DM层级.241203

在数据仓库的设计过程中,数据分层是一种重要的组织方式,能够提高数据处理效率和数据质量。数据分层通常包括原始数据(Operational Data Store,ODS)、明细数据(Data Warehouse,DW)和汇总数据(Data Mart,DM)三个层级。下面将详细介绍这三个层级的作用以及如何优雅地设…

OpenEuler文件被锁定的解决方法网卡修改不生效的解决办法.241202

欧拉系统(含centos等linux系统)修改文件,一直提示readonly,不让改。原因有可能是这个文件给锁定了。解决方法: 使用以下两个命令: • chattr 改变文件属性 • lsattr 文件 查看文件属性 例如: • chattr +i 将文件锁住,任何用户都不能进行修改 • chattr +a 只能向文件…

哈迪-温伯格平衡及拓展

哈迪-温伯格平衡及不符合一些条件时的变式目录五个条件:特殊情况基因频率父本≠母本伴X遗传法一法二拓展1. 有突变2. 有选择2.1. 定向选择2.1.1 对\(aa\)不利极端情况:\(s=1\)加上突变2.1.2 对\(A\_\)不利2.2 分裂选择2.3 稳定选择3. 有迁移法一法二 设 \(P(A)=p,P(a)=q\) 自…

MongoDB备份脚本.241217

#!/bin/bash #backup MongoDB #mongodump命令路径 DUMP=/home/mongodb/bin/mongodump #临时备份目录 OUT_DIR=/home/mongodb_bak/mongodb_bak_now #备份存放路径 TAR_DIR=/home/mongodb_bak/mongodb_bak_list #获取当前系统时间 DATE=`date +%Y_%m_%d` #数据库账号 DB_USER=roo…

MySQL备份脚本.241217

MYSQL备份,每天全量备份(排除由于GTID的缘故造成恢复问题的系统库),然后通过Gzip进行压缩。 #!/bin/bash#DEFINE VARIABLES BACKUPUSER=root BACKUPPASS=root密码 BACKUPPORT=mysql端口 #BACKUPSOCKET=/home/data/$BACKUPPORT/logs/mysql.sock BACKUPIP=localhost MYSQL=/…

欧拉OpenEuler安装JAVA.241227

1. 安装java mkdir -p /home/java tar -zxvf jdk-8u391-linux-x64.tar.gz -C /home/java cd /home/java cd jdk1.8.0_391/2. 配置java vim /etc/profile ,最后加上export JAVA_HOME=/home/java/jdk1.8.0_391export CLASSPATH=.:$JAVA_HOME/libexport PATH="$PATH:$JAVA_…

PCIe扫盲——基地址寄存器(BAR)详解

基地址寄存器(BAR)在配置空间(Configuration Space)中的位置如下图所示:其中Type0 Header最多有6个BAR,而Type1 Header最多有两个BAR。这就意味着,对于Endpoint来说,最多可以拥有6个不同的地址空间。但是实际应用中基本上不会用到6个,通常1~3个BAR比较常见。 主要注意…

使用标签策略规范资源上的标签

阿里云标签服务提供了标签策略功能,能够帮助企业解决在标签使用过程中遇到的漏打标签、标签拼写错误等问题,同时为用户提供了自动打标的能力。引言 阿里云标签服务提供了标签策略功能,能够帮助企业解决在标签使用过程中遇到的漏打标签、标签拼写错误等问题,同时为用户提供了…

java字符串拼接遇到null你会处理吗

现有一个场景,对于发票信息,需要把信息中的地址和电话进行拼接,开户号和账号进行拼接,那应该怎么做?最简单的方法是使用+拼接,但问题是如果有个字段为空,是null,那么拼接结果是什么样的?来个下面的示例public static void main(String[] args) {String a = null;Strin…

欧拉OpenEuler安装tomcat.241227

1. 安装tomcat unzip tomcat.zip mv tomcat /home/ cd /home/tomcat chmod +x *.sh cd bin chmod +x *.sh/home/tomcat下 三个sh 进行启动关闭 2. 开web端口 firewall-cmd --list-ports firewall-cmd --permanent --add-port=9090/tcp firewall-cmd --reload.zstitle { width:…