java序列化之了解Jackson

海燕技术栈 发表于 2月以前  | 总阅读数:216 次

当涉及到在Java中进行JSON序列化和反序列化时,Jackson和Gson是两个最常用的库。它们都提供了强大的功能来处理JSON数据,但在某些方面有一些不同之处。

Jackson

Jackson 是一个功能强大且灵活的 JSON 处理库,由 FasterXML 维护。以下是 Jackson 的一些特点

强大的功能

Jackson 提供了广泛的功能,包括 JSON 到 Java 对象的转换,Java 对象到 JSON 的转换,以及 JSON 树模型的处理。

JSON 和 Java 对象互相转换的例子

import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) throws Exception {
        // 创建ObjectMapper实例
        ObjectMapper objectMapper = new ObjectMapper();

        // 将JSON字符串转换为Java对象
        String json = "{\"name\":\"John\",\"age\":30,\"email\":\"john@example.com\"}";
        User user = objectMapper.readValue(json, User.class);
        System.out.println("Java对象: " + user);

        // 将Java对象转换为JSON字符串
        User newUser = new User("Alice", 25, "alice@example.com");
        String jsonString = objectMapper.writeValueAsString(newUser);
        System.out.println("JSON字符串: " + jsonString);
    }
}

class User {
    private String name;
    private int age;
    private String email;

    // 省略构造函数、getter和setter

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", email='" + email + '\'' +
                '}';
    }
}

Json树模型

JSON树模型是指将 JSON 数据表示为树形结构的一种模型。在Java中,使用Jackson或者其他JSON处理库解析JSON数据时,通常会将JSON数据解析为一个树形结构,这个结构由节点组成,每个节点代表JSON数据的一个部分。JSON树模型中的每个节点可以是以下几种类型之一

对象节点(ObjectNode)

表示JSON对象,包含多个键值对。

数组节点(ArrayNode)

表示JSON数组,包含多个元素。

文本节点(TextNode)

表示JSON中的字符串。

数字节点(NumericNode)

表示JSON中的数值。

布尔节点(BooleanNode)

表示JSON中的布尔值。

空节点(NullNode)

表示JSON中的null值。

通过JSON树模型,我们可以轻松地遍历、访问和修改JSON数据。JSON树模型与JSONPath确实有些相似,它们都提供了一种方便的方式来处理JSON数据,但也有一些区别

  • JSON树模型是将JSON数据表示为树形结构,通过节点来表示JSON数据的层次结构,可以直接操作节点来处理JSON数据。
  • JSONPath是一种用于在JSON数据中定位和查询特定部分的查询语言,它是基于路径表达式的,通过指定路径来定位JSON数据的特定部分,类似于XPath用于XML。

虽然它们有些相似,但JSON树模型更注重于表示整个JSON数据的结构,而JSONPath更注重于定位和查询JSON数据的特定部分。

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) throws Exception {
        // 创建ObjectMapper实例
        ObjectMapper objectMapper = new ObjectMapper();

        // 创建JSON字符串
        String json = "{\"name\":\"John\",\"age\":30,\"email\":\"john@example.com\"}";

        // 解析JSON字符串为JsonNode对象(JSON树模型)
        JsonNode jsonNode = objectMapper.readTree(json);

        // 从JsonNode对象中获取值
        String name = jsonNode.get("name").asText();
        int age = jsonNode.get("age").asInt();
        String email = jsonNode.get("email").asText();

        System.out.println("Name: " + name);
        System.out.println("Age: " + age);
        System.out.println("Email: " + email);
    }
}

灵活性

Jackson 提供了多种不同的方式来定义和定制 JSON 序列化和反序列化的行为,包括使用注解、Mix-in Annotations、自定义序列化器和反序列化器等。

Mix-in Annotations是什么

Mix-in Annotations 是 Jackson 框架提供的一种高级定制技术,允许将注解绑定到 Java 类上,以指示 Jackson 在序列化或反序列化该类时应该应用这些注解。这个技术的主要优点是可以在无法修改源代码的情况下,对已有的 Java 类进行定制,以满足特定的序列化或反序列化需求。

具体来说,Mix-in Annotations 允许你创建一个独立的辅助类(通常是一个接口),在这个辅助类中定义你希望应用到目标类上的注解,然后通过 Jackson 的 ObjectMapper 将这些注解与目标类进行关联。

使用 Mix-in Annotations 的一般步骤如下:

  1. 创建一个辅助类,其中包含你希望应用到目标类上的注解。这个辅助类通常不会包含任何实现代码,只是用来存放注解。
  2. 使用 ObjectMapperaddMixInAnnotations() 方法,将目标类和辅助类进行关联。

下面是一个简单的示例,演示了如何使用 Mix-in Annotations 来定制 JSON 序列化和反序列化行为:

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) throws Exception {
        // 创建 ObjectMapper 实例
        ObjectMapper objectMapper = new ObjectMapper();

        // 创建 Mix-in Annotations 辅助类
        abstract class MixIn {
            @JsonInclude(JsonInclude.Include.NON_NULL)
            abstract String getEmail();
        }

        // 将 Mix-in Annotations 和目标类关联
        objectMapper.addMixIn(User.class, MixIn.class);

        // 将 Java 对象转换为 JSON 字符串
        User user = new User("John", 30, null);
        String jsonString = objectMapper.writeValueAsString(user);
        System.out.println(jsonString); // 输出: {"name":"John","age":30}
    }
}

class User {
    private String name;
    private int age;
    private String email;

    // 省略构造函数、getter和setter
}

在上面的示例中,我们创建了一个名为 MixIn 的辅助类,在其中定义了一个带有 @JsonInclude 注解的抽象方法。然后,通过调用 ObjectMapperaddMixInAnnotations() 方法,将 MixIn 类与 User 类进行关联,以告诉 Jackson 在序列化 User 类时应该应用 MixIn 类中定义的注解。

性能优化

Jackson 在性能上表现优异,通过使用流式 API、懒加载等技术来减少内存和CPU的开销,并提供了异步处理和基于缓存的优化。

异步处理和基于缓存的优化

在Jackson中,异步处理和基于缓存的优化是通过一些特定的设置和技术来实现的,主要是针对Jackson的ObjectMapper进行配置。

异步处理

异步处理在Jackson中主要是指在处理JSON数据时可以采用异步的方式,以提高性能和效率。异步处理通常涉及到IO操作,例如读取或写入JSON数据到文件、网络或其他数据源。在Jackson中实现异步处理的关键是使用异步的IO流和回调机制。对于读取JSON数据,我们可以使用JsonParser的异步API进行操作,而对于写入JSON数据,可以使用JsonGenerator的异步API进行操作。示例代码如下

ObjectMapper objectMapper = new ObjectMapper();
try (InputStream inputStream = new FileInputStream("data.json")) {
    // 创建JsonParser
    JsonParser jsonParser = objectMapper.getFactory().createNonBlockingByteArrayParser();
    // 设置JsonParser的输入流
    jsonParser.setNonBlockingInput(inputStream);
    // 通过回调处理JSON事件
    jsonParser.setNonBlockingParsing(true);
    jsonParser.nextToken();
    while (jsonParser.nextToken() != null) {
        // 处理JSON事件
    }
}

基于缓存的优化

基于缓存的优化主要是指将Jackson的一些中间结果缓存起来,以提高后续操作的性能和效率。这些中间结果可以是反序列化过程中的解析结果、序列化过程中的JSON片段等。在Jackson中实现基于缓存的优化通常是通过ObjectMapper的一些配置选项来实现的。例如,可以使用ObjectReaderObjectWriter来重用已经配置好的ObjectMapper实例,从而避免重复创建ObjectMapper实例。另外,Jackson还提供了一些缓存相关的配置选项,例如可以通过JsonFactory_createUTF8JsonGenerator方法来创建一个带有缓冲的JsonGenerator,以提高序列化性能。示例代码如下

ObjectMapper objectMapper = new ObjectMapper();
// 重用已经配置好的ObjectMapper实例
ObjectReader reader = objectMapper.reader();
ObjectWriter writer = objectMapper.writer();
// 创建带有缓冲的JsonGenerator
JsonFactory factory = objectMapper.getFactory();
factory._createUTF8JsonGenerator(System.out, JsonGenerator.Feature.AUTO_CLOSE_TARGET);

通过合理配置Jackson的ObjectMapper和相关组件,可以实现异步处理和基于缓存的优化,从而提高JSON数据的处理性能和效率。

流式 API

Jackson 提供了流式 API,用于在处理大型JSON文档时提供更高效和更灵活的方式。流式 API 允许我们以流的形式逐个处理JSON文档的各个部分,而不需要将整个文档加载到内存中。

以下是 Jackson 流式 API 的一些主要特点和用法

JsonParser 和 JsonGenerator

Jackson 的流式 API 主要围绕着 JsonParserJsonGenerator 这两个核心类展开。JsonParser 用于从 JSON 输入流中读取数据,而 JsonGenerator 用于将数据写入到 JSON 输出流中。

逐个读取和写入

使用 JsonParser 可以逐个读取 JSON 文档的各个部分(如对象、数组、字段),而使用 JsonGenerator 可以逐个写入 JSON 文档的各个部分。这种逐个处理的方式使得在处理大型JSON文档时可以更加高效和灵活。

事件模型

Jackson 的流式 API 采用了一种事件驱动的模型,即在读取或写入 JSON 文档时会产生各种事件(如开始对象、结束对象、开始数组、结束数组、字段等),开发者可以根据这些事件来决定如何处理 JSON 数据。

读取JSON文档:

ObjectMapper objectMapper = new ObjectMapper();
try (InputStream inputStream = new FileInputStream("data.json")) {
    JsonParser jsonParser = objectMapper.getFactory().createParser(inputStream);
    while (jsonParser.nextToken() != null) {
        // 处理JSON事件
    }
}

写入JSON文档:

ObjectMapper objectMapper = new ObjectMapper();
try (OutputStream outputStream = new FileOutputStream("output.json")) {
    JsonGenerator jsonGenerator = objectMapper.getFactory().createGenerator(outputStream);
    jsonGenerator.writeStartObject();
    jsonGenerator.writeStringField("name", "John");
    jsonGenerator.writeNumberField("age", 30);
    jsonGenerator.writeEndObject();
}

通过使用 Jackson 的流式 API,我们可以有效地处理大型JSON文档,逐个读取或写入其各个部分,并在处理过程中灵活地控制和处理JSON数据。

广泛的支持

Jackson 支持标准的 JSON 规范,并且与许多其他第三方库和框架集成得很好,比如 Spring、JAX-RS、Hibernate 等。

使用注解的方式定制Json序列化和反序列化的行为

在Jackson中,可以使用各种注解来定制JSON序列化和反序列化的行为。以下是一些常用的注解及其用法

JSON序列化注解

@JsonProperty

用于指定JSON属性名称,可以将Java属性与JSON字段进行映射。


public class User {
    @JsonProperty("username")
    private String name;
    // 省略其他属性和方法
}

@JsonFormat

用于指定日期和时间的格式化方式。

public class Event {
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private Date timestamp;
    // 省略其他属性和方法
}

@JsonInclude

控制在序列化时是否包括某些属性。

@JsonInclude(JsonInclude.Include.NON_NULL)
public class User {
    // 省略其他属性和方法
}

@JsonRawValue

将属性的原始值直接包含在生成的JSON中,而不是将其序列化为JSON对象或数组。

public class Data {
    @JsonRawValue
    private String rawData;
    // 省略其他属性和方法
}

JSON反序列化注解

@JsonIgnore

忽略某个属性,使其在反序列化时不被处理。


public class User {
    @JsonIgnore
    private String password;
    // 省略其他属性和方法
}

@JsonCreator

用于指定一个静态工厂方法或构造函数,用于从JSON中创建对象。

public class User {
    private String name;
    @JsonCreator
    public User(@JsonProperty("username") String name) {
        this.name = name;
    }
    // 省略其他属性和方法
}

@JsonSetter

用于指定一个方法,用于在反序列化时设置属性值。

public class User {
    private String name;
    @JsonSetter("username")
    public void setName(String name) {
        this.name = name;
    }
    // 省略其他属性和方法
}

@JsonDeserialize

用于指定一个自定义的反序列化器。

public class User {
    @JsonDeserialize(using = CustomDateDeserializer.class)
    private Date birthday;
    // 省略其他属性和方法
}

通过使用这些注解,可以灵活地定制JSON序列化和反序列化的行为,以满足不同的需求和场景。

如何自定义序列化器和反序列化器

在Jackson中,可以通过自定义序列化器(Serializer)和反序列化器(Deserializer)来实现对特定类型的定制化序列化和反序列化行为。这种方式可以让我们完全控制JSON数据的生成和解析过程,以满足特定的需求和场景。

自定义序列化器

自定义序列化器是通过继承JsonSerializer<T>类并重写serialize()方法来实现的。在serialize()方法中,我们可以通过JsonGenerator将Java对象序列化为JSON数据。

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class CustomDateSerializer extends JsonSerializer<Date> {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Override
    public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        String formattedDate = dateFormat.format(value);
        gen.writeString(formattedDate);
    }
}

自定义反序列化器

自定义反序列化器是通过继承JsonDeserializer<T>类并重写deserialize()方法来实现的。在deserialize()方法中,我们可以通过JsonParser从JSON数据解析出Java对象。

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class CustomDateDeserializer extends JsonDeserializer<Date> {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    @Override
    public Date deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        String dateString = p.getText();
        try {
            return dateFormat.parse(dateString);
        } catch (ParseException e) {
            throw new IOException("Error parsing date", e);
        }
    }
}

注册自定义序列化器和反序列化器

完成自定义序列化器和反序列化器的编写后,我们需要将它们注册到ObjectMapper中,以便在序列化和反序列化过程中使用。示例代码

ObjectMapper objectMapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addSerializer(Date.class, new CustomDateSerializer());
module.addDeserializer(Date.class, new CustomDateDeserializer());
objectMapper.registerModule(module);

通过以上步骤,我们可以自定义序列化器和反序列化器,并将它们注册到Jackson的ObjectMapper中,从而实现对特定类型的定制化序列化和反序列化行为。

本文由微信公众号海燕技术栈原创,哈喽比特收录。
文章来源:https://mp.weixin.qq.com/s/agffLr6zyvJfBYqdN3QqrQ

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:7月以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:7月以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:7月以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:7月以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:7月以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:7月以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:7月以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:7月以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:7月以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:7月以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:7月以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:7月以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:7月以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:7月以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:7月以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:7月以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:7月以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:7月以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:7月以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:7月以前  |  398次阅读  |  详细内容 »
 相关文章
Java 中验证时间格式的 4 种方法 1年以前  |  3320次阅读
Java经典面试题答案解析(1-80题) 3年以前  |  2607次阅读
CentOS 配置java应用开机自动启动 3年以前  |  2437次阅读
IDEA依赖冲突分析神器—Maven Helper 4年以前  |  2428次阅读
SpringBoot 控制并发登录的人数教程 4年以前  |  2139次阅读
 目录