首页 > 编程语言 >Java序列化之Jackson详解

Java序列化之Jackson详解

时间:2024-03-24 18:33:42浏览次数:31  
标签:Java String Person Jackson 序列化 public ObjectMapper

目录

1 Jackson

1.1 Jackson简介

Jackson是一个用于处理JSON数据的开源Java库。JSON(JavaScript Object Notation)是一种轻量级的数据交换格式,易于阅读和编写,同时也易于计算机解析和生成。在Java领域,Jackson已经成为处理JSON数据的事实标准库。它提供了丰富的功能,包括将Java对象转换为JSON字符串(序列化)以及将JSON字符串转换为Java对象(反序列化

Jackson主要由三个核心包组成:

  • jackson-databind:提供了通用的数据绑定功能(将Java对象与JSON数据相互转换)
  • jackson-core:提供了核心的低级JSON处理API(例如JsonParser和JsonGenerator)
  • jackson-annotations:提供了用于配置数据绑定的注解

1.2 为什么选择Jackson

尽管Java生态系统中有其他处理JSON数据的库(如Gson和JSON-java),但Jackson仍然是许多开发者的首选,原因包括:

  • 性能:Jackson性能优越,对内存和CPU的使用都相对较低。许多性能基准测试表明,Jackson在序列化和反序列化方面都比其他库更快。
  • 功能丰富:Jackson提供了许多功能,包括注解、自定义序列化和反序列化、动态解析等,使其非常灵活和强大。
  • 易于使用:JacksonAPI简单易用,使得开发者可以轻松地在他们的应用程序中集成和使用。
  • 社区支持:Jackson拥有庞大的开发者社区,这意味着有更多的文档、教程和问题解答可供参考。
  • 模块化:Jackson支持通过模块扩展其功能,例如Java 8时间库、Joda-Time和Kotlin等。
  • 兼容性:Jackson可以很好地与其他流行的Java框架(如Spring)集成。

综上所述,Jackson是一个强大且易于使用的库,值得Java开发者在处理JSON数据时使用

1.3 Jackson的基本功能

Jackson库的核心功能是将Java对象转换为JSON字符串(序列化)以及将JSON字符串转换为Java对象(反序列化)

1.3.1 将Java对象转换为JSON字符串(序列化)

序列化:将Java对象转换为JSON字符串的过程。这在许多场景中非常有用,例如在将数据发送到Web客户端时,或者在将数据存储到文件或数据库时。Jackson通过ObjectMapper类来实现序列化。以下是一个简单的示例:

import com.fasterxml.jackson.databind.ObjectMapper;

public class Person {
    public String name;
    public int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper();
        Person person = new Person("Alice", 30);

        try {
            String jsonString = objectMapper.writeValueAsString(person);
            System.out.println(jsonString); // 输出:{"name":"Alice","age":30}
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

1.3.2 将JSON字符串转换为Java对象(反序列化)

反序列化:将JSON字符串转换回Java对象的过程。这在从Web客户端接收数据或从文件或数据库读取数据时非常有用。同样,Jackson使用ObjectMapper类来实现反序列化。以下是一个简单的示例:

import com.fasterxml.jackson.databind.ObjectMapper;

public class Person {
    public String name;
    public int age;
    public Person() {
    }
    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonString = "{\"name\":\"Alice\",\"age\":30}";

        try {
            Person person = objectMapper.readValue(jsonString, Person.class);
            System.out.println("Name: " + person.name + ", Age: " + person.age); // 输出:Name: Alice, Age: 30
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这些示例展示了Jackson库的基本功能。接下来的部分将介绍如何使用Jackson库,包括添加依赖、创建Java对象模型以及使用ObjectMapper进行序列化和反序列化。

1.4 Jackson库主要方法

以下是Jackson库的一些主要API和组件:

  • ObjectMapper:这是Jackson库的核心类,用于序列化和反序列化操作。主要方法有:
    writeValueAsString(Object):将Java对象序列化为JSON字符串
    readValue(String, Class):将JSON字符串反序列化为Java对象
  • JsonParser:用于从JSON数据源(如文件、输入流或字符串)解析JSON数据。主要方法有:
    nextToken():获取下一个JSON令牌(如START_OBJECT、FIELD_NAME等)。
    getValueAsString():将当前令牌作为字符串返回。
    getValueAsInt():将当前令牌作为整数返回。
  • JsonGenerator:用于将JSON数据写入数据源(如文件、输出流或字符串缓冲区)。主要方法有:
    writeStartObject():写入开始对象标记({)。
    writeFieldName(String):写入字段名称。
    writeString(String):写入字符串值。
    writeEndObject():写入结束对象标记(})。
  • JsonNode:用于表示JSON树模型中的节点,可以是对象、数组、字符串、数字等。主要方法有:
    get(String):获取指定字段的子节点。
    path(String):获取指定字段的子节点,如果不存在则返回一个“missing”节点。
    isObject():检查当前节点是否是一个对象。
    isArray():检查当前节点是否是一个数组。
  • 注解Jackson提供了一系列注解来配置序列化和反序列化过程。一些常用注解包括:
    @JsonProperty:指定字段在JSON数据中的名称。
    @JsonIgnore:指定字段在序列化和反序列化过程中被忽略。
    @JsonCreator:指定用于反序列化的构造函数或工厂方法。
    @JsonSerialize:指定用于序列化特定字段或类的自定义序列化器。
    @JsonDeserialize:指定用于反序列化特定字段或类的自定义反序列化器。

1.5 使用Jackson基本步骤

1.5.1 添加依赖(Maven或Gradle)

以下是添加Jackson库的方法:
Maven:将以下依赖添加到pom.xml文件中:

<dependencies>
  <!-- Jackson core -->
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.13.0</version>
  </dependency>
  <!-- Jackson databind -->
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.13.0</version>
  </dependency>
  <!-- Jackson annotations -->
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.13.0</version>
  </dependency>
</dependencies>

Gradle:将以下依赖添加到build.gradle文件中:

dependencies {
    implementation 'com.fasterxml.jackson.core:jackson-core:2.13.0'
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
    implementation 'com.fasterxml.jackson.core:jackson-annotations:2.13.0'
}

1.5.2 创建Java对象模型

在使用Jackson之前,需要创建一个Java对象模型,该模型表示要序列化和反序列化的JSON数据。例如,以下是一个表示Person的简单Java类:

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

1.5.3 使用ObjectMapper进行序列化和反序列化

使用ObjectMapper类,可以轻松地将Java对象序列化为JSON字符串以及将JSON字符串反序列化为Java对象。以下是一个简单的示例:

序列化:

import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper();
        Person person = new Person("Alice", 30);

        try {
            String jsonString = objectMapper.writeValueAsString(person);
            System.out.println(jsonString); // 输出:{"name":"Alice","age":30}
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

反序列化:

import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {
    public static void main(String[] args) {
        ObjectMapper objectMapper = new ObjectMapper();
        String jsonString = "{\"name\":\"Alice\",\"age\":30}";

        try {
            Person person = objectMapper.readValue(jsonString, Person.class);
            System.out.println("Name: " + person.getName() + ", Age: " + person.getAge()); // 输出:Name: Alice, Age: 30
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这些示例展示了如何使用Jackson库进行序列化和反序列化操作。在实际项目中,你可能需要根据需求对这些操作进行更多的配置和自定义,例如使用注解、自定义序列化器和反序列化器等。

1.6 注解讲解

Jackson库提供了一系列注解,可以在序列化和反序列化过程中对字段和类进行配置。以下是一些常用注解的示例:

1.6.1 @JsonProperty

该注解用于指定 Java 属性与 JSON 属性之间的映射关系,常用的参数有:

  • value:用于指定 JSON 属性的名称,当 Java 属性和 JSON 属性名称不一致时使用。
  • access:用于指定该属性的访问方式,常用的取值有 JsonAccess.READ_ONLY(只读),JsonAccess.WRITE_ONLY(只写)和 JsonAccess.READ_WRITE(可读可写)。
public class Person {
    @JsonProperty(value = "name")
    private String fullName;
    
    @JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
    private String password;
    
    // getters and setters
}

Person person = new Person();
person.setFullName("John Smith");
person.setPassword("123456");

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(person);
// {"name":"John Smith"}

Person person2 = mapper.readValue(json, Person.class);
System.out.println(person2.getFullName());
// John Smith
System.out.println(person2.getPassword());
// null

1.6.2 @JsonIgnore

用于禁用 Java 属性的序列化和反序列化。

public class Person {
    private String fullName;
    
    @JsonIgnore
    private String password;
    
    // getters and setters
}

Person person = new Person();
person.setFullName("John Smith");
person.setPassword("123456");

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(person);
// {"fullName":"John Smith"}

Person person2 = mapper.readValue("{\"fullName\":\"John Smith\",\"password\":\"123456\"}", Person.class);
System.out.println(person2.getFullName());
// John Smith
System.out.println(person2.getPassword());
// null

1.6.3 @JsonFormat

该注解用于指定 Java 属性的日期和时间格式,常用的参数有:

  • shape:用于指定日期和时间的格式,可选的取值有 JsonFormat.Shape.STRING(以字符串形式表示)和 JsonFormat.Shape.NUMBER(以时间戳形式表示)。
  • pattern:用于指定日期和时间的格式模板,例如 "yyyy-MM-dd HH:mm:ss"。
public class Person {
    private String fullName;
    
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
    private Date birthDate;
    
    // getters and setters
}

Person person = new Person();
person.setFullName("John Smith");
person.setBirthDate(new Date());

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(person);
// {"fullName":"John Smith","birthDate":"2022-05-16 10:38:30"}

Person person2 = mapper.readValue(json, Person.class);
System.out.println(person2.getFullName());
// John Smith
System.out.println(person2.getBirthDate());
// Mon May 16 10:38:30 CST 2022

1.6.4 @JsonInclude

该注解用于指定序列化 Java 对象时包含哪些属性,常用的参数有:

  • value:用于指定包含哪些属性,可选的取值有 JsonInclude.Include.ALWAYS(始终包含)、JsonInclude.Include.NON_NULL(值不为 null 时包含)、JsonInclude.Include.NON_DEFAULT(值不为默认值时包含)、JsonInclude.Include.NON_EMPTY(值不为空时包含)和 JsonInclude.Include.CUSTOM(自定义条件)。
  • content:用于指定自定义条件的实现类。
@JsonInclude(JsonInclude.Include.NON_NULL)
public class Person {
    private String fullName;
    
    private Integer age;
    
    // getters and setters
}

Person person = new Person();
person.setFullName("John Smith");
// person.setAge(null);

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(person);
// {"fullName":"John Smith"}

Person person2 = mapper.readValue("{\"fullName\":\"John Smith\",\"age\":null}", Person.class);
System.out.println(person2.getFullName());
// John Smith
System.out.println(person2.getAge());
// null

1.6.5 @JsonCreator

该注解用于指定反序列化时使用的构造方法或工厂方法。

public class Person {
    private String fullName;
    
    private Integer age;
    
    @JsonCreator
    public Person(@JsonProperty("fullName") String fullName, @JsonProperty("age") Integer age) {
        this.fullName = fullName;
        this.age = age;
    }
    
    // getters and setters
}

ObjectMapper mapper = new ObjectMapper();
Person person = mapper.readValue("{\"fullName\":\"John Smith\",\"age\":30}", Person.class);
System.out.println(person.getFullName());
// John Smith
System.out.println(person.getAge());
// 30

1.6.6 @JsonSetter

该注解用于指定反序列化时使用的方法,常用的参数有:

  • value:用于指定 JSON 属性的名称,当方法名和 JSON 属性名称不一致时使用
public class Person {
    private String fullName;
    
    private Integer age;
    
    @JsonSetter("name")
    public void setFullName(String fullName) {
        this.fullName = fullName;
    }
    
    // getters and setters
}

ObjectMapper mapper = new ObjectMapper();
Person person = mapper.readValue("{\"name\":\"John Smith\",\"age\":30}", Person.class);
System.out.println(person.getFullName());
// John Smith
System.out.println(person.getAge());
// 30

1.6.7 @JsonGetter

该注解用于指定序列化时使用的方法,常用的参数有:

  • value:用于指定 JSON 属性的名称,当方法名和 JSON 属性名称不一致时使用。
public class Person {
    private String fullName;
    
    private Integer age;
    
    @JsonGetter("name")
    public String getFullName() {
        return fullName;
    }
    
    // getters and setters
}

1.6.8 @JsonAnySetter

该注解用于指定反序列化时使用的方法,用于处理 JSON 中未知的属性。

public class Person {
    private String fullName;
    
    private Map<String, Object> otherProperties = new HashMap<>();
    
    @JsonAnySetter
    public void setOtherProperties(String key, Object value) {
        otherProperties.put(key, value);
    }
    
    // getters and setters
}

ObjectMapper mapper = new ObjectMapper();
Person person = mapper.readValue("{\"fullName\":\"John Smith\",\"age\":30}", Person.class);
System.out.println(person.getFullName());
// John Smith
System.out.println(person.getOtherProperties());
// {age=30}

1.6.9 @JsonAnyGetter

该注解用于指定序列化时使用的方法,用于处理 Java 对象中未知的属性

public class Person {
    private String fullName;
    
    private Map<String, Object> otherProperties = new HashMap<>();
    
    public void addOtherProperty(String key, Object value) {
        otherProperties.put(key, value);
    }
    
    @JsonAnyGetter
    public Map<String, Object> getOtherProperties() {
        return otherProperties;
    }
    
    // getters and setters
}

Person person = new Person();
person.setFullName("John Smith");
person.addOtherProperty("age", 30);

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(person);
// {"fullName":"John Smith","age":30}

1.6.10 @JsonTypeInfo

该注解用于指定 Java 对象在序列化和反序列化时的类型信息,常用的参数有:

  • use:用于指定类型信息的使用方式,可选的取值有 JsonTypeInfo.Id.CLASS(使用 Java 类的全限定名)、JsonTypeInfo.Id.NAME(使用名称)和 JsonTypeInfo.Id.NONE(不使用类型信息)。
  • include:用于指定类型信息的包含方式,可选的取值有 JsonTypeInfo.As.PROPERTY(作为 JSON 属性)和 JsonTypeInfo.As.EXTERNAL_PROPERTY(作为外部属性)。
  • property:用于指定包含类型信息的属性名,当 include 的值为 JsonTypeInfo.As.PROPERTY 时使用。
  • visible:用于指定类型信息是否可见。
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = Rectangle.class, name = "rectangle"),
    @JsonSubTypes.Type(value = Circle.class, name = "circle")
})
public abstract class Shape {
    // ...
}

public class Rectangle extends Shape {
    // ...
}

public class Circle extends Shape {
    // ...
}

Shape shape = new Rectangle();

ObjectMapper mapper = new ObjectMapper();
String json = mapper.writeValueAsString(shape);
// {"type":"rectangle"}

Shape shape2 = mapper.readValue(json, Shape.class);
System.out.println(shape2.getClass().getSimpleName());
// Rectangle

1.7 高级特性

1.7.1 自定义序列化和反序列化

创建自定义序列化器和反序列化器以自定义特定字段或类的序列化和反序列化行为。为此,创建一个实现JsonSerializerJsonDeserializer接口的类,并在需要自定义的字段或类上使用@JsonSerialize@JsonDeserialize注解。例如:

public class CustomDateSerializer extends JsonSerializer<Date> {
    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public void serialize(Date value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        gen.writeString(dateFormat.format(value));
    }
}
public class Person {
    private String name;

    @JsonSerialize(using = CustomDateSerializer.class)
    private Date birthdate;

    // ...其他代码...
}

1.7.2 使用JsonNode进行动态解析

可以使用JsonNode类来动态地解析和操作JSON数据。例如:

String jsonString = "{\"name\":\"Alice\",\"age\":30,\"address\":{\"street\":\"Main St\",\"city\":\"New York\"}}";

ObjectMapper objectMapper = new ObjectMapper();
JsonNode rootNode = objectMapper.readTree(jsonString);

String name = rootNode.get("name").asText(); // Alice
int age = rootNode.get("age").asInt(); // 30
String street = rootNode.get("address").get("street").asText(); // Main St

1.7.3 处理日期和时间类型

Jackson可以处理Java日期和时间类型,例如java.util.Date和Java 8时间库中的类型。可以通过配置ObjectMapper来指定日期和时间格式,例如:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd"));

1.7.4 处理泛型

Jackson可以处理泛型类型,例如List<T>Map<String, T>。在反序列化时,需要使用TypeReference来指定泛型类型。例如:

String jsonString = "[{\"name\":\"Alice\",\"age\":30},{\"name\":\"Bob\",\"age\":25}]";

ObjectMapper objectMapper = new ObjectMapper();
List<Person> persons = objectMapper.readValue(jsonString, new TypeReference<List<Person>>() {});

1.7.5 使用模块扩展Jackson(如Java 8时间支持)

Jackson可以通过模块来扩展其功能。例如,你可以使用jackson-datatype-jsr310模块为Jackson添加对Java 8时间库的支持。首先,将依赖添加到项目中:

Maven:

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.13.0</version>
</dependency>

Gradle:

dependencies {
    implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.0'
}

然后,需要注册模块到ObjectMapper

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());

现在,Jackson可以正确地处理Java 8时间库中的类型,例如LocalDate、LocalTime和Instant。

参考资料:
https://github.com/FasterXML/jackson-docs
https://github.com/google/gson
https://github.com/alibaba/fastjson
https://github.com/stleary/JSON-java
https://github.com/square/moshi
https://github.com/boonproject/boon

标签:Java,String,Person,Jackson,序列化,public,ObjectMapper
From: https://www.cnblogs.com/jingzh/p/18092787

相关文章

  • JAVAEE——多线程的设计模式,生产消费模型,阻塞队列
    文章目录多线程设计模式什么是设计模式单例模式饿汉模式懒汉模式线程安全问题懒汉模式就一定安全吗?锁引发的效率问题jvm的优化引起的安全问题阻塞队列阻塞队列是什么?生产消费者模型阻塞队列实现消费生产者模型可能遇到的异常多线程设计模式什么是设计模式首先我......
  • java入门基础掌握知识
    Java基础入门Java一门高级编程语言Java是sun公司研发的,现在属于oracle公司Java之父是詹姆斯.高斯林Java主要是来做企业级应用开发的Java的三大技术体系是:技术体系说明JavaSE(JavaStandardEdition):标准版Java技术的核心和基础JavaEE(JavaEnterpri......
  • 注解总结,Java中的注解,springboot中的注解
    注解总结1、Junit开始执行的方法:初始化资源,执行完之后的方法:释放资源测试方法,必须是:公有、非静态、无参无返回值的在一个类中,可以定义多个测试方法,每个测试方法可以单独运行,也可以整体运行(顺序:方法名升序)Junit4注解说明@Test测试方法@Before用来修饰实例方法,在每个@......
  • (毕设)基于Java+Vue+Mysql的WMS仓库管理系统
          前言: WMS(WarehouseManagementSystem)仓库管理系统是一个用于优化仓库操作、提高效率和准确性的软件解决方案。以下是针对列出的WMS仓库管理系统的各个部分的简要描述:1.订单管理订单管理是WMS的核心功能之一,涉及处理、跟踪和完成客户订单。这包括:订单录入:......
  • (毕设)基于Java+SpringBoot+Vue+Mysql的智慧园区管理系统
        前言:智慧园区管理系统是一个集成了园区管理、缴费服务、退款功能、缴费提醒、抄表功能、打印功能、统计报表和协同办公等多个模块的综合性系统。以下是对每个模块及其子功能的简要说明:园区管理:园区管理:对整个园区进行宏观管理,包括园区的基本信息、资源配置、设施维......
  • (毕设)基于Java+Vue+Mysql的门店管理系统
        前言:门店管理系统是一个综合性的软件解决方案,旨在帮助门店高效地管理日常运营、提升服务质量、优化资源配置和增强决策能力。以下是您提到的各个管理模块的简要概述:门店管理:门店信息管理:记录门店的基本信息,如门店名称、地址、联系方式、营业时间等。门店布局管理:定......
  • Javascript中的严格模式 “use strict“
    一、为什么使用严格模式?在普通的JavaScript中,写错变量名会创建新的全局变量,在严格模式中,写错变量名会抛出错误来提醒开发者二、声明严格模式通过在脚本或函数的开头添加“usestrict”;来声明严格模式。"usestrict"指令只能在脚本或函数的开头被识别在脚本开头进......
  • Java项目:332SSM校园网站设计与实现(含论文)
    作者主页:源码空间站2022  简介:Java领域优质创作者、Java项目、学习资料、技术互助文末获取源码项目介绍角色:管理员、学生,项目分为前后台学生登陆系统后,可以查看首页,学校介绍、领导架构、联系我们、留言板,新闻资讯信息、师资力量、校园风光、我的、后台管理等功能管理......
  • PhpStrom启动报错, java.net.BindException: Address already in use: bind
    问题描述:今天启动phpstromIDE时,突然报错,报错信息如下图:问题分析1.不正确关闭应用(强制关闭):可能是之前启动了一个本地web服务占了端口,在没有停掉服务,直接关闭IDE导致的(尝试了重启电脑也没解决)2.其他应用占用端口:安装了Hyper-V导致端口被占用?显然我的是第一种情况问题解决......
  • Shiro反序列化分析
    前言Shiro,一个流行的web框架,养活了一大批web狗,现在来对它分析分析。Shiro的gadget是CB链,其实是CC4改过来的,因为Shiro框架是自带Commoncollections的,除此之外还带了一个包叫做CommonBeanUtils,主要利用类就在这个包里环境搭建https://codeload.github.com/apache/shiro/zip/shiro......