Java和Rust实现JSON序列化互转的解决方案详解

 更新时间:2024年03月12日 08:32:36   作者:蚂蚁背大象  
这篇文章主要为大家详细介绍了Java和Rust实现JSON序列化互转的解决方案,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

1.背景

最近在使用Rust实现Rocketmq的项目 rocketmq-rust,在实现的过程中就会遇到请求头以及相关的数据JSON序列化在两个不同语言中的序列化和反序列的情况。在这种情况下遇到下面的问题:Java中存在继承,例如

public class Test {

    public static void main(String[] args) {
        Student object = new Student();
        object.setName("mxsm");
        object.setAge("18");
        object.setSchool("杭州电子科技大学");
        System.out.println(JSON.toJSONString(object));
    }
    
    public static class Person {
        private String name;
        private String age;
		//ignore get set method
    }

    public static class Student extends Person {
        private String school;
		//ignore get set method
    }
}

那么在Java中序列化就会打印成这样:

{"age":"18","name":"mxsm","school":"杭州电子科技大学"}

问题就来了。在Rust中没有这样的继承关系该如何处理这样的代码情况。随着跨语言开发的流行,将数据在不同编程语言之间进行序列化和反序列化变得越来越重要。本文将探讨如何在Java和Rust之间实现JSON数据的序列化互转,并解决在Rust中处理Java继承序列化的挑战。

2. Java和Rust之间的JSON序列化互转

Java中有许多库可以用于JSON序列化,其中最流行的是Jackson和Gson以及Fastjson。我们将以Fastjson为例进行介绍(Rocketmq中使用的就是Fastjson进行序列)。Rust中使用serde作为例子,在 Rocketmq-rust 项目中JSON序列化使用的是 serde 。

2.1 无继承的简单数据结构

Java示例代码:

 public static class Person {
        private String name;
        private String age;
     	private String homeAddress
		//ignore get set method
 }

转换成对应的Rust代码

#[derive(Clone,Debug,Serialize,Deserialize)]
#[serde(rename_all="camelCase")]
pub struct Person{
    name: String,
    age: String,
    home_address: String
}

这里有个需要说明,在Java规范中字段的命名遵循的是驼峰,而rust使用的snake case,两者是有区别的。 这里就需要注意如果是以Java为主的项目那么Rust的序列化和反序列化都应该使用驼峰的方式来进行。也就是上面代码的增加的 #[serde(rename_all="camelCase")] 而如果是Rust项目为主,很大可能序列后的JSON字符串使用的就是snake case 那么Java项目就需要进行相对应的处理。

2.2 Java代码有继承的结构

代码示例:

public static class Person {
        private String name;
        private String age;
		//ignore get set method
    }

    public static class Student extends Person {
        private String school;
		//ignore get set method
    }

在Java代码中继承是很常见的一种操作,但是在Rust中struct的继承并不存在。那么这种情况下应该如何解决。

2.2.1 将所有的代码扁平化

代码扁平化这个是最简单的方式。以上面代码为例。如果扁平化后我们后我们处理后的Rust代码:

#[derive(Clone,Debug,Serialize,Deserialize)]
#[serde(rename_all="camelCase")]
pub struct Person{
    name: String,
    age: String,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
#[serde(rename_all="camelCase")]
pub struct Person{
    name: String,
    age: String,
    school: String
}

所谓扁平化就是直接将继承代码的属性移到最底层的继承代码中。这样做就是简单,能够实现和Java相同的序列化的效果。

优点:

简单,快速解决问题

缺点:

需要实现的重复代码量大

2.2.2 抽象出来trait

将公共的方法操作方法抽象出来trait然后,使用trait继承的方式来实现。同样已上面的代码为例:

pub trait PersonTrait{
    fn get_name(&self)->String;
    fn get_age(&self)->String;
}

然后所有的struct进行实现。这个优缺点也很明显。

优点:

  • 简单,相比第一种方式多了一个抽象trait的步骤,其他的和第一种差不多
  • 可以使用Trait作为方法的参数或者struct的属性。提供了类似Java的多态(这个对于无需要进行序列化的比较好)

缺点:

需要实现的重复代码量大

2.2.3 使用struct聚合配合serde的扁平化(重点)

使用struct聚合配合serde的扁平化来解决Java项目和Rust项目的JSON数据的序列化和反序列交互比较优的解。通用用上面的代码为例子。如果使用这种方式来处理,转换成Rust代码后的代码:

#[derive(Clone,Debug,Serialize,Deserialize)]
#[serde(rename_all="camelCase")]
pub struct Person{
    name: String,
    age: String,
}

#[derive(Clone,Debug,Serialize,Deserialize)]
#[serde(rename_all="camelCase")]
pub struct Person{
    #[serde(flatten)]  // 这个是扁平化关键
    person: Persion
    school: String
}

同样定义跟Java相同的代码,然后通过聚合的方式来模拟Rust中的继承关系。 将需要扁平化的代码进行扁平化使用 #[serde(flatten)] 来实现。

优点:

  • 能够和其他语言相同的JSON序列化方式(需要serde的扁平化支持)
  • 整体的序列化相对较灵活

缺点:

需要Rust JSON序列化工具的支持。如果工具不支持没办法实现。只能手动序列化

说明:使用struct聚合配合serde的扁平化来解决JSON序列化的方式也是 Rocketmq-rust 项目中的解决方式。因为rocketmq-rust需要支持和Java版本进行互通。

3.总结

对于Java JSON序列化和Rust JSON序列化主要差异由以下两种原因引起:

  • 属性的命名规范,Java使用的是驼峰 而Rust使用的是snake case。这就导致在序列化的情况下两者之间的序列化会存在属性的命名差异。
  • Java有继承关系,继承的最底层的类进行序列化会将父类的属性进行扁平化序列化。而Rust中不存在所以导致Rust中的序列化的差异性,为了解决这种差异性就有了上面的三种方式。

就单纯解决JSON序列化使用 使用struct聚合配合serde的扁平化 是一种比较忧的解决方式。但是不是唯一的方式。

到此这篇关于Java和Rust实现JSON序列化互转的解决方案详解的文章就介绍到这了,更多相关Java Rust实现JSON序列化互转内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • springboot执行延时任务之DelayQueue的使用详解

    springboot执行延时任务之DelayQueue的使用详解

    DelayQueue是一个无界阻塞队列,只有在延迟期满时,才能从中提取元素。这篇文章主要介绍了springboot执行延时任务-DelayQueue的使用,需要的朋友可以参考下
    2019-12-12
  • 基于Java开发一个Markdown到Word文档转换工具

    基于Java开发一个Markdown到Word文档转换工具

    本文介绍了一个用Java开发的Markdown到Word文档转换工具,该工具通过MarkdownToWordConverter类实现,利用flexmark库将Markdown内容转换为HTML,借助jsoup库规范化HTML,再通过docx4j库将处理后的HTML导入并保存为Word文档,需要的朋友可以参考下
    2025-07-07
  • Java中BigDecimal与0比较的一个坑实战记录

    Java中BigDecimal与0比较的一个坑实战记录

    BigDecimal属于大数据,精度极高,不属于基本数据类型,属于java对象,下面这篇文章主要给大家介绍了关于Java中BigDecimal与0比较的一个坑的相关资料,需要的朋友可以参考下
    2022-12-12
  • Spring Security配置多个数据源并添加登录验证码的实例代码

    Spring Security配置多个数据源并添加登录验证码的实例代码

    这篇文章主要介绍了Spring Security配置多个数据源并添加登录验证码,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-08-08
  • Java 的可变参数方法详述

    Java 的可变参数方法详述

    这篇文章主要介绍了Java 的可变参数方法,可变参数只能作为函数的最后一个参数,在其前面可以有也可以没有任何其他参数,由于可变参数必须是最后一个参数,所以一个函数最多只能有一个可变参数,下面我们一起进入文章了解更多关于可变参数的内容吧
    2022-02-02
  • Java实现整合文件上传到FastDFS的方法详细

    Java实现整合文件上传到FastDFS的方法详细

    FastDFS是一个开源的轻量级分布式文件系统,对文件进行管理,功能包括:文件存储、文件同步、文件上传、文件下载等,解决了大容量存储和负载均衡的问题。本文将提供Java将文件上传至FastDFS的示例代码,需要的参考一下
    2022-02-02
  • 关于Spring中@Lazy注解的使用

    关于Spring中@Lazy注解的使用

    这篇文章主要介绍了关于Spring中@Lazy注解的使用,@Lazy注解用于标识bean是否需要延迟加载,没加注解之前主要容器启动就会实例化bean,本文提供了部分实现代码,需要的朋友可以参考下
    2023-08-08
  • 关于ZooKeeper的会话机制Session解读

    关于ZooKeeper的会话机制Session解读

    这篇文章主要介绍了关于ZooKeeper的会话机制Session解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-02-02
  • SpringBoot+URule实现可视化规则引擎的方法示例

    SpringBoot+URule实现可视化规则引擎的方法示例

    规则引擎其实是一种组件,它可以嵌入到程序当中,将程序复杂的判断规则从业务代码中剥离出来,使得程序只需要关心自己的业务,而不需要去进行复杂的逻辑判断,本文给大家介绍了SpringBoot+URule实现可视化规则引擎的方法示例,需要的朋友可以参考下
    2024-12-12
  • Springboot项目的搭建教程(分离出common父依赖)

    Springboot项目的搭建教程(分离出common父依赖)

    这篇文章主要介绍了Springboot项目的搭建教程(分离出common父依赖),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-01-01

最新评论