序列化方式二——JSON之Gson

news2024/9/22 18:55:36

Gson

1、什么是Gson?

Gson是Google提供的一个用于Java编程语言的JSON(JavaScript Object Notation)序列化和反序列化库。它允许开发者在Java对象和JSON数据之间进行高效的映射和转换。

官网地址:https://github.com/google/gson

官网文档:https://google.github.io/gson/UserGuide.html

2、为什么选择Gson?

  1. 快速、高效:Gson采用了一些优化策略,确保在处理大量数据时能够保持高效率。

  2. 代码量少、简洁:Gson的设计简洁,使用起来非常方便,开发者可以以较少的代码实现复杂的JSON处理功能。

  3. 面向对象:Gson支持Java对象的序列化,能够将复杂的Java对象(包括嵌套对象和集合)转换为JSON字符串,同时也支持将JSON字符串反序列化为Java对象。

  4. 数据传递和解析方便:Gson提供了灵活的数据传递和解析方式,使得在前后端之间传递数据时变得非常方便。

  5. 自定义序列化和反序列化:Gson允许开发者通过实现JsonSerializer和JsonDeserializer接口来自定义对象的序列化和反序列化过程,以满足特定需求。

  6. 支持复杂对象:Gson能够处理复杂的Java对象,包括嵌套对象和集合,它会自动处理对象之间的关系,将它们转换为相应的JSON格式。

  7. 与Android兼容:Gson在Android开发中也被广泛使用,因为它与Android平台兼容,能够方便地处理Android应用中的JSON数据。

  8. 性能优化:对于大型数据集,Gson提供了性能优化的选项,如使用JsonReader和JsonWriter进行流式处理,以减少内存占用并提高处理速度。

  9. 版本控制:Gson支持使用@Since和@Until注解来指定字段的版本信息,以便在对象模型发生变化时保持向后和向前兼容性。

  10. 处理空值和异常:Gson能够处理Java对象中的null值,并将它们序列化为JSON字符串中的null。同时,Gson也提供了异常处理机制,以便在反序列化过程中捕获和处理可能出现的异常。

3、Gson常用的API

3.1. Gson对象的创建

  • 直接创建:通过new Gson()直接创建一个Gson对象,使用默认配置。

  • GsonBuilder:使用GsonBuilder类可以构建自定义配置的Gson对象,如设置日期格式、排除空值、自定义序列化器等。

3.2. 序列化

  • toJson()方法:将Java对象序列化为JSON字符串。Gson提供了多个重载的toJson()方法,支持将对象、对象数组、集合等转换为JSON字符串。

3.3. 反序列化

  • fromJson()方法:将JSON字符串反序列化为Java对象。Gson同样提供了多个重载的fromJson()方法,支持将JSON字符串解析为指定的Java对象、对象数组、集合等。

3.4. JsonElement、JsonObject和JsonArray

  • JsonElement:表示JSON树中的一个节点,可以是JsonObject、JsonArray、JsonPrimitive或JsonNull。

  • JsonObject:表示JSON对象,即键值对集合。可以通过get()方法获取特定键对应的值,使用put()方法添加或修改键值对。

  • JsonArray:表示JSON数组,即值的有序列表。可以使用get()方法按索引访问数组中的元素,使用add()方法添加元素。

3.5. TypeToken

  • 当需要将JSON字符串反序列化为泛型集合时,由于类型擦除,直接使用fromJson()方法会丢失泛型信息。此时,可以使用TypeToken类来捕获泛型信息。

3.6. 自定义序列化器与反序列化器

  • JsonSerializer和JsonDeserializer:Gson 1.x版本中提供的自定义序列化器和反序列化器接口,基于树型结构进行解析。

  • TypeAdapter:Gson 2.0版本中新增的自定义序列化器和反序列化器接口,基于流式结构进行解析,相比树型结构更节省内存。

3.7. 注解

Gson提供了一系列注解来支持复杂的序列化和反序列化场景,如:

  • @SerializedName:用于指定JSON属性名与Java字段名之间的映射关系。

  • @Expose:用于控制字段是否参与序列化和反序列化。

  • @JsonAdapter:用于指定字段或类使用自定义的序列化器或反序列化器。

  • @Since和@Until:用于控制字段的序列化版本。

3.8. 流式API

对于大量数据,Gson提供了流式API,即JsonReaderJsonWriter,可以有效地读写JSON数据,减少内存占用。

4、使用

4.1、引入依赖

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.10.1</version>
</dependency>

4.2、简单示例(json->对象,对象->json)

package com.zhz.test.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class GsonStudent {
    private String name;
    private String sex;
    private Integer age;
    private Date birthday;
}

@Test
public void test() {
    // 创建Java对象
    GsonStudent gsonStudent = GsonStudent
            .builder()
            .age(18)
            .sex("男")
            .birthday(new Date())
            .name("张三")
            .build();


    // 创建Gson对象
    Gson gson = new Gson();

    // 序列化:将Java对象转换为JSON字符串(对象->json)
    String json = gson.toJson(gsonStudent);
    System.out.println(json); // 输出: {"name":"Alice","age":30}

    // 反序列化:将JSON字符串转换为Java对象(json->对象)
    GsonStudent newPerson = gson.fromJson(json, GsonStudent.class);
    System.out.println(newPerson.getName()); // 输出: Alice
    System.out.println(newPerson.getAge()); // 输出: 30
}

image.png

4.3、 自定义序列化器与反序列化器

通过实现JsonSerializer和JsonDeserializer接口来自定义序列化和反序列化过程。这在你需要处理复杂对象或特殊格式时非常有用。

package com.zhz.test.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class GsonStudent {
    private String name;
    private String sex;
    private Integer age;
    private Date birthday;
}

序列化器

package com.zhz.test.json.gson;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.zhz.test.entity.GsonStudent;

import java.lang.reflect.Type;

public class GsonStudentSerializer implements JsonSerializer<GsonStudent> {
    @Override
    public JsonElement serialize(GsonStudent src, Type typeOfSrc, JsonSerializationContext context) {
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("name", src.getName());
        // 假设我们对年龄进行特殊处理,比如加10
        jsonObject.addProperty("age", src.getAge() + 10);
        // 可以添加更多自定义逻辑
        return jsonObject;
    }
}

反序列化器

package com.zhz.test.json.gson;

import com.google.gson.*;
import com.zhz.test.entity.GsonStudent;

import java.lang.reflect.Type;

public class GsonStudentDeserializer implements JsonDeserializer<GsonStudent> {
    @Override
    public GsonStudent deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonObject jsonObject = json.getAsJsonObject();
        String name = jsonObject.get("name").getAsString();
        // 假设我们从JSON中读取的年龄需要减10以还原原始值
        int age = jsonObject.get("age").getAsInt() - 10;
        // 创建并返回Person对象
        return GsonStudent.builder().name(name).age(age).build();
    }
}

测试代码

@Test
    public void testSerializable() {
        // 创建并注册自定义序列化器和反序列化器
        Gson gson = new GsonBuilder()
                .registerTypeAdapter(GsonStudent.class, new GsonStudentSerializer())
                .registerTypeAdapter(GsonStudent.class, new GsonStudentDeserializer())
                .create();

        // 序列化
        GsonStudent gsonStudent = GsonStudent
                .builder()
                .age(18)
                .sex("男")
                .birthday(new Date())
                .name("张三")
                .build();
        String json = gson.toJson(gsonStudent);
        System.out.println(json); // 输出: {"name":"John","age":40}

        // 反序列化
        GsonStudent deserializedPerson = gson.fromJson(json, GsonStudent.class);
        System.out.println(deserializedPerson); // 输出: Person{name='John', age=20}
    }

image.png

4.4、排除字段

  • 使用@Expose注解来标记哪些字段应该被序列化或反序列化。未标记的字段将默认被排除。

  • 在Gson中,如果你想要排除某些字段,在序列化过程中不被包含到JSON字符串中,有几种方法可以实现这一点。然而,Gson本身并没有直接提供一个简单的注解来标记一个字段应该被排除。不过,你可以使用@Expose注解(虽然它主要用于Gson 2.x之前的版本,并且在新版本中可能不再推荐使用),或者更常见的是,使用GsonBuilder的excludeFieldsWithoutExposeAnnotation()方法结合@Expose注解(尽管这是标记哪些字段应该被包含,而不是排除),或者使用@SerializedName注解的变体(实际上不是用于排除,但可以用来避免生成JSON中的某些字段),或者通过自定义序列化器来完全控制序列化过程。

  • 不过,对于Gson 2.8及以上版本,简单地通过自定义序列化器来排除字段。以下是一个使用自定义序列化器来排除字段的示例:

package com.zhz.test.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class GsonStudent {
    private String name;
    private String sex;
    private Integer age;
    private Date birthday;
}

/**
 * 排除字段
 */
@Test
public void testExclusion(){
    // 创建一个Gson实例,使用自定义的排除策略
    Gson gson = new GsonBuilder()
            .setExclusionStrategies(new ExclusionStrategy() {
                @Override
                public boolean shouldSkipField(FieldAttributes f) {
                    // 这里可以根据字段名、类型等条件来排除字段
                    // 例如,排除所有名为"age"的字段
                    return "age".equals(f.getName());
                }

                @Override
                public boolean shouldSkipClass(Class<?> clazz) {
                    // 这里可以根据类来排除整个类的序列化,但通常不需要
                    return false;
                }
            })
            .create();

    // 序列化
    GsonStudent gsonStudent = GsonStudent
            .builder()
            .age(18)
            .sex("男")
            .birthday(new Date())
            .name("张三")
            .build();

    // 序列化Person对象,注意"age"字段被排除了
    String json = gson.toJson(gsonStudent);
    System.out.println(json); // 输出可能类似于: {"name":"John"}
}

image.png

4.5、格式化输出

使用GsonBuilder的setPrettyPrinting()方法可以使Gson以更易读的格式输出JSON字符串。

package com.zhz.test.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class GsonStudent {
    private String name;
    private String sex;
    private Integer age;
    private Date birthday;
}

@Test
public void testPrettyPrinting(){
    // 使用GsonBuilder设置格式化输出并创建Gson对象
    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    GsonStudent gsonStudent = GsonStudent
            .builder()
            .age(18)
            .sex("男")
            .birthday(new Date())
            .name("张三")
            .build();
    // 将Person对象序列化为格式化的JSON字符串
    String jsonString = gson.toJson(gsonStudent);

    // 输出结果
    System.out.println(jsonString);
}

image.png

4.6、处理泛型

对于泛型集合,Gson提供了TypeToken来捕获泛型信息,以便正确地进行反序列化。

基本对象

package com.zhz.test.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class GsonStudent {
    private String name;
    private String sex;
    private Integer age;
    private Date birthday;
}

处理List集合

   /**
     * 测试泛型
     */
    @Test
    public void testPansexual(){
        // 序列化
        GsonStudent gsonStudent = GsonStudent
                .builder()
                .age(18)
                .sex("男")
                .birthday(new Date())
                .name("张三")
                .build();
        // 创建一个包含Person对象的List
        List<GsonStudent> gsonStudents = new ArrayList<>();
        gsonStudents.add(gsonStudent);
        // 创建Gson实例
        Gson gson = new Gson();

        // 序列化List<Person>为JSON字符串
        String json = gson.toJson(gsonStudents);
        System.out.println(json);

        // 反序列化JSON字符串回List<Person>
        // 注意:由于类型擦除,我们需要使用TypeToken来捕获List<Person>的类型信息
        Type listType = new TypeToken<List<GsonStudent>>(){}.getType();
        List<GsonStudent> deserializedPersons = gson.fromJson(json, listType);

        // 输出反序列化后的List内容
        for (GsonStudent gsonStudent1 : deserializedPersons) {
            System.out.println(gsonStudent1);
        }
    }

image.png

处理Set


    /**
     * 测试Set泛型
     */
    @Test
    public void testPansexualSet(){
        // 序列化
        GsonStudent gsonStudent = GsonStudent
                .builder()
                .age(18)
                .sex("男")
                .birthday(new Date())
                .name("张三")
                .build();
        // 创建一个包含Person对象的List
        Set<GsonStudent> gsonStudents = new HashSet<>();
        gsonStudents.add(gsonStudent);
        // 创建Gson实例
        Gson gson = new Gson();

        // 序列化List<Person>为JSON字符串
        String json = gson.toJson(gsonStudents);
        System.out.println(json);

        // 反序列化JSON字符串回List<Person>
        // 注意:由于类型擦除,我们需要使用TypeToken来捕获List<Person>的类型信息
        Type setType = new TypeToken<Set<GsonStudent>>(){}.getType();
        Set<GsonStudent> deserializedPersons = gson.fromJson(json, setType);

        // 输出反序列化后的List内容
        for (GsonStudent gsonStudent1 : deserializedPersons) {
            System.out.println(gsonStudent1);
        }
    }

image.png

处理Map


    /**
     * 测试Map泛型
     */
    @Test
    public void testPansexualMap(){
        // 序列化
        GsonStudent gsonStudent = GsonStudent
                .builder()
                .age(18)
                .sex("男")
                .birthday(new Date())
                .name("张三")
                .build();
        // 创建一个包含Person对象的List
        Map<String,GsonStudent> gsonStudents = new HashMap<>();
        gsonStudents.put("111",gsonStudent);
        // 创建Gson实例
        Gson gson = new Gson();

        // 序列化List<Person>为JSON字符串
        String json = gson.toJson(gsonStudents);
        System.out.println(json);

        // 反序列化JSON字符串回List<Person>
        // 注意:由于类型擦除,我们需要使用TypeToken来捕获List<Person>的类型信息
        Type mapType = new TypeToken<Map<String,GsonStudent>>(){}.getType();
        Map<String,GsonStudent> deserializedPersons = gson.fromJson(json, mapType);

        // 输出反序列化后的Map内容
        for (Map.Entry<String, GsonStudent> entry : deserializedPersons.entrySet()) {
            System.out.println(entry.getKey()+"\t"+entry.getValue());
        }
    }

image.png

4.7、处理日期格式

Gson本身并不直接提供注解来指定日期格式,但你可以通过自定义序列化器(JsonSerializer)和反序列化器(JsonDeserializer)来解决这个问题。

以下是一个处理日期格式的示例,展示了如何为java.util.Date类型自定义序列化器和反序列化器,并设置特定的日期格式(例如,yyyy-MM-dd)。代码如下:

package com.zhz.test.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class GsonStudent {
    private String name;
    private String sex;
    private Integer age;
    private Date birthday;
}

自定义Date序列化

package com.zhz.test.json.gson;

import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateSerializer implements JsonSerializer<Date> {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
        return new JsonPrimitive(dateFormat.format(src));
    }
}

自定义Date反序列化器

package com.zhz.test.json.gson;

import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;

import java.lang.reflect.Type;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DateDeserializer implements JsonDeserializer<Date> {
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        try {
            return dateFormat.parse(json.getAsString());
        } catch (ParseException e) {
            throw new JsonParseException(e);
        }
    }
}

测试demo

@Test
public void testDate(){
    Gson gson = new GsonBuilder()
            .registerTypeAdapter(Date.class, new DateSerializer())
            .registerTypeAdapter(Date.class, new DateDeserializer())
            .create();

    // 序列化
    GsonStudent gsonStudent = GsonStudent
            .builder()
            .age(18)
            .sex("男")
            .birthday(new Date())
            .name("张三")
            .build();
    // 序列化对象
    String json = gson.toJson(gsonStudent);
    System.out.println(json); // 输出类似:{"date":"2023-04-01"}

    // 反序列化JSON字符串
    GsonStudent deserializedObj = gson.fromJson(json, GsonStudent.class);
    System.out.println(deserializedObj.getBirthday()); // 输出:对应的Date对象,但注意它只包含日期部分
}

image.png

4.8、处理异常

在使用Gson库处理JSON数据时,可能会遇到各种异常情况,例如解析错误、类型转换错误等。Gson通过抛出异常来指示这些错误情况,因此你需要适当地捕获和处理这些异常。Gson主要会抛出以下几种类型的异常:

  1. JsonSyntaxException:当输入的JSON字符串不符合JSON规范时,Gson会抛出此异常。这通常发生在解析JSON数据时。

  2. JsonParseException:Gson在解析JSON时,如果遇到无法理解的格式或结构,也会抛出此异常。虽然Gson主要使用JsonSyntaxException,但在某些情况下(或旧版本中),你可能会遇到JsonParseException

  3. JsonIOException:当Gson在读取或写入JSON数据时遇到I/O错误时,会抛出此异常。这通常与文件或网络I/O操作相关。

  4. IllegalStateException:虽然这不是Gson特有的异常,但在Gson的使用中,如果Gson的状态不正确(比如,在反序列化过程中尝试修改JsonReader的状态),则可能会抛出此异常。

  5. TypeMismatchException(Gson 2.8.6及以后版本):这是一个自定义的异常,用于指示在反序列化过程中类型不匹配的情况。它可以帮助你更容易地识别和处理类型错误。

  6. IllegalArgumentException 和 NullPointerException:这些Java标准异常也可能在Gson的使用中出现,尤其是在处理无效输入或配置错误时。

解决方案,只需要在fromJson ,toJson的时候加个try/catch就好了

@Test
public void testTryCatch() {
    // 创建Java对象
    GsonStudent gsonStudent = GsonStudent
            .builder()
            .age(18)
            .sex("男")
            .birthday(new Date())
            .name("张三")
            .build();


    // 创建Gson对象
    Gson gson = new Gson();

    // 序列化:将Java对象转换为JSON字符串
    String json = gson.toJson(gsonStudent);
    System.out.println(json); // 输出: {"name":"Alice","age":30}

    try {
        // 反序列化:将JSON字符串转换为Java对象
        GsonStudent newPerson = gson.fromJson(json, GsonStudent.class);
        System.out.println(newPerson.getName()); // 输出: Alice
        System.out.println(newPerson.getAge()); // 输出: 30
    }catch (Exception e) {
        throw new RuntimeException(e);
    }
}

4.9、字段访问权限

Gson默认只能访问类中的公共字段(public fields)和方法。如果类变量的访问权限不是公共的(如private、protected或默认包级私有),Gson就无法直接访问到这些变量。为了解决这个问题,Gson提供了几种方法:

  • 使用@Expose注解:通过@Expose注解,可以将非公共字段标记为可序列化和反序列化的字段。但请注意,要使用这个注解,必须在创建Gson对象时通过GsonBuilder配置Gson实例,以包含@Expose注解的字段。

  • 自定义序列化器和反序列化器:通过实现JsonSerializer和JsonDeserializer接口,可以自定义序列化和反序列化的逻辑,从而控制对字段的访问。

  • 修改字段访问权限:虽然这不是最佳实践,但在某些情况下,将字段的访问权限修改为public可能是一个简单的解决方案。

4.10、循环引用

循环引用是指两个或多个对象之间相互引用的现象。在Java中,循环引用可能导致内存泄漏和程序崩溃等问题。Gson提供了处理循环引用的方法:

  • 自动处理:在大多数情况下,Gson能够自动处理循环引用,确保数据结构的稳定性。这通常是通过在序列化过程中检测并处理循环引用来实现的。

  • 自定义序列化器和反序列化器:对于复杂的循环引用情况,可以通过自定义序列化器和反序列化器来特别处理循环引用,如跳过循环引用对象的某些属性等。

  • 使用GsonBuilder的setExclusionStrategies:通过实现ExclusionStrategy接口,可以定义排除策略,从而在序列化或反序列化过程中排除特定的字段或类。

4.11、性能优化&TypeAdapter测试用例

Gson的性能优化可以从多个方面入手:

  • 全局Gson对象:在项目中提供一个全局的Gson对象,以避免频繁创建Gson实例带来的性能开销。

  • 避免不必要的序列化:只序列化需要的数据,避免序列化整个对象图,特别是包含大量不必要数据或复杂对象图的情况。

  • 自定义序列化器和反序列化器:通过自定义序列化器和反序列化器,可以优化序列化和反序列化的过程,减少不必要的计算或内存使用。

  • 使用流式API(TypeAdapter):Gson 2.0引入了TypeAdapter,这是一个基于流式结构的API,相比基于树型结构的JsonSerializer和JsonDeserializer,TypeAdapter更节省内存。\

下面给一个TypeAdapter的测试用例

package com.zhz.test.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class GsonStudent {
    private String name;
    private String sex;
    private Integer age;
    private Date birthday;
}

package com.zhz.test.json.gson;

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import com.zhz.test.entity.GsonStudent;

import java.io.IOException;

public class GsonStudentTypeAdapter extends TypeAdapter<GsonStudent> {

    @Override
    public void write(JsonWriter out, GsonStudent value) throws IOException {
        if (value == null) {
            out.nullValue();
            return;
        }
        out.beginObject();
        out.name("name").value(value.getName());
        out.name("age").value(value.getAge());
        out.endObject();
    }

    @Override
    public GsonStudent read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.NULL) {
            in.nextNull();
            return null;
        }

        in.beginObject();
        String name = null;
        int age = 0;

        while (in.hasNext()) {
            switch (in.nextName()) {
                case "name":
                    name = in.nextString();
                    break;
                case "age":
                    age = in.nextInt();
                    break;
                default:
                    in.skipValue(); // 忽略未知字段
            }
        }

        in.endObject();
        return GsonStudent.builder().age(age).name(name).build();
    }
}
@Test
public void testSerializationAndDeserialization() {
    // 序列化
    GsonStudent gsonStudent = GsonStudent
            .builder()
            .age(18)
            .sex("男")
            .birthday(new Date())
            .name("张三")
            .build();

    Gson gson = new GsonBuilder()
            .registerTypeAdapter(GsonStudent.class, new GsonStudentTypeAdapter())
            .create();

    // 序列化
    String json = gson.toJson(gsonStudent);
    System.out.println(json);

    // 反序列化
    GsonStudent deserializedUser = gson.fromJson(json, GsonStudent.class);
    System.out.println(deserializedUser);
}

4.12、版本控制

Gson的版本控制主要涉及到两个方面:

  • Gson库的版本:在使用Gson时,应关注Gson库的最新版本,以便利用新功能和性能改进。同时,也需要注意版本兼容性,避免升级后引入不兼容的变更。

  • 序列化数据的版本:在序列化数据时,有时需要控制数据的版本,以便在反序列化时能够处理不同版本的数据。Gson提供了@Since和@Until注解,用于声明字段的起始和终止序列化版本。这样,在反序列化时,只有满足版本条件的字段才会被包含在内。

5、注意事项

  1. 版本兼容性:Gson的不同版本之间可能存在一些差异,特别是API的变化。因此,在升级Gson版本时,请务必参考官方文档或更新日志。

  2. 性能优化:对于大型数据集,Gson提供了流式API(JsonReaderJsonWriter)来减少内存占用并提高性能。

  3. 安全性:在处理不受信任的JSON数据时,请确保你的应用程序能够正确处理潜在的安全问题,如JSON注入攻击。

打个广告

本人新搞的个人项目,有意者可到 DDD用户中台 这里购买

可以学习到的体系

  • 项目完全从0到1开始架构,包含前端,后端,架构,服务器,技术管理相关运维知识!

    • 最佳包名设计,项目分层
  • 破冰CRUD,手撕中间件!

    • 基于MybatisPlus封装属于自己的DDD ORM框架

    • 基于Easyexcel封装属于自己的导入导出组件

    • oss对象存储脚手架(阿里云,minio,腾讯云,七牛云等)

    • 邮件脚手架

    • completefuture脚手架

    • redis脚手架

    • xxl-job脚手架

    • 短信脚手架

    • 常用工具类等

  • 传统MVC代码架构弊端的解决方案

    • DDD+CQRS+ES最难架构
  • 结合实际代码的业务场景

    • 多租户单点登录中心

    • 用户中台

    • 消息中心

    • 配置中心

    • 监控设计

  • 程序员的职业规划,人生规划

    • 打工永远没有出路!

    • 打破程序员的35岁魔咒

    • 技术带给你的优势和竞争力【启发】

    • 万物互联网的淘金之路!

技术以外的赚钱路子

可以一起沟通

具体的文章目录

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

购买链接

DDD用户中台

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

小程序隐私合规自查指南

一 背景&#xff1a;小程序作为一种轻量级应用&#xff0c;广泛应用于各大互联网平台。工信部通报2022年第5批侵害用户权益名单中首次出现8款违规小程序。各监管单位对“小程序”违规收集个人信息监控手段和监控力度不断加强。 工信部APP违法违规通报 上海市委网信办查处违规小…

Python_控制循环语句

if语句单分支结构的语法形式如下&#xff1a; 【操作】输入一个数字&#xff0c;小于10&#xff0c;则打印这个数字(if_test01.py)&#xff1a; num input("输入一个数字&#xff1a;") if int(num)<10: print("小于10的数&#xff1a;"num)条件表达式…

BOE(京东方)携多场景物联网创新应用亮相2024服贸会 “屏之物联”赋能数字经济

9 月 12 日&#xff0c;以“全球服务 互惠共享”为主题的2024中国国际服务贸易交易会&#xff08;以下简称“服贸会”&#xff09;在北京拉开帷幕。作为领先的物联网创新企业&#xff0c;BOE&#xff08;京东方&#xff09;携智慧办公、智慧商显、智能车载、智慧教育、智能工厂…

设计模式例题

答案&#xff1a;D C A D 知识点&#xff1a; 观察者模式的意图&#xff1a;定义对象间的一种一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖它的对象都得到通知并被自动更新&#xff0c;和自媒体很相似&#xff0c;自媒体更新内容&#xff0c…

C++--C++11(下)

目录 7.5 完美转发 8 新的类功能 9 可变参数模板 10 lambda表达式 11 包装器 7.5 完美转发 模板中的 && 万能引用 void Fun(int &x){ cout << "左值引用" << endl; } void Fun(const int &x){ cout << "const 左值引用…

秒变 Vim 高手:必学的编辑技巧与隐藏功能大揭秘

文章目录 前言一、vi与vim二、Vim的三种模式1. 普通模式2. 插入模式3. 命令模式 三、Vim中的查找与替换1. 查找2. 替换 四、给Vim设置行号1. 临时显示行号2. 永久显示行号 总结 前言 在Linux系统中&#xff0c;文本编辑器是开发者和系统管理员日常工作中的重要工具之一。其中&…

DeepSeek 2.5本地部署的实战教程

大家好,我是herosunly。985院校硕士毕业,现担任算法研究员一职,热衷于大模型算法的研究与应用。曾担任百度千帆大模型比赛、BPAA算法大赛评委,编写微软OpenAI考试认证指导手册。曾获得阿里云天池比赛第一名,CCF比赛第二名,科大讯飞比赛第三名。授权多项发明专利。对机器学…

想学习下Python和深度学习,Python需要学习到什么程度呢?

想要学习Python和深度学习&#xff0c;Python的学习程度需要达到能够熟练运用这门语言进行编程&#xff0c;并能够理解和实现深度学习模型的基本构建和训练过程。以下是一些推荐的书籍&#xff0c;可以帮助你系统地学习Python和深度学习&#xff1a; Python学习推荐书籍 《Py…

kubectl 执行一条命令之后发生了什么?

kubectl 是与 Kubernetes 集群交互的命令行工具&#xff0c;用户通过它可以对集群资源进行操作和管理。你有没有想过&#xff0c;当我们执行一条 kubectl 命令之后&#xff0c;背后都发生了什么&#xff1f; 详细过程 kubectl -> kube-api-server 根据通信类型&#xff0…

【大模型】AutoDL部署AI绘图大模型Stable Diffusion使用详解

目录 一、前言 二、AI绘图大模型概述 2.1 AI绘图大模型介绍 2.2 AI绘图大模型特点 2.3 AI绘图大模型优势 三、主流的AI绘图大模型介绍 3.1 Midjourney 3.1.1 Midjourney介绍 3.1.2 Midjourney功能特点 3.1.3 Midjourney使用场景 3.2 Stable Diffusion 3.2.1 Stable …

zynq的PS端mac与RTL8211F的连接要点

目录 1 VCCO_MIO12 PS_MIO_VREF3 PS的引脚4 RXDLY TXDLY5 ZYNQ的MAC可以调整延时吗 1 VCCO_MIO1 接1.8V 2 PS_MIO_VREF 接0.9V&#xff0c;可通过电阻分压 可通过电阻分压 3 PS的引脚 4 RXDLY TXDLY RXDLY RXD[0] TXDLY RXD[1] 与XC7Z020的PS端MAC连接&#xff0c;必须…

python画正方形、平行四边形、六边形、五角星、风车(四个半圆)

画正方形、平行四边形、六边形、五角星、风车&#xff08;四个半圆&#xff09; import turtle def square(side_length):"""正方形"""for _ in range(4):turtle.forward(side_length)turtle.right(90)def parallelogram(base, height):"&q…

C++——模拟实现string

1.再谈string string为什么要被设计成模板&#xff1f;日常使用string好像都是char*&#xff0c;char*不够使用吗&#xff0c;为什么要设计成模板呢&#xff1f; 1.1 关于编码 //计算机的存储如何区分呢&#xff1f;int main() {//比如在C语言中&#xff0c;有整型//如果是有…

Linux网络——HTTP协议详解(2)

文章目录 HTTP方法GET方法POST方法 状态码与报头状态码报头 会话 HTTP方法 HTTP方法有这些 但是怎么说呢&#xff0c;这些方法只有GET和POST方法是99%情况用到的 剩下的几乎不太用&#xff0c;如果有兴趣可以找《图解HTTP》&#xff0c;是处于了解的范畴 大家肯定一看就明白…

Qt Creator项目模板介绍

在Qt Creator中创建项目时&#xff0c;用户可以从多个模板类别中进行选择&#xff0c;以满足不同的开发需求。 Application(Qt) 在Application(Qt)类别下&#xff0c;Qt Creator提供了多种用于创建不同类型Qt应用程序的模板。这些模板主要包括&#xff1a; Qt Widgets Applic…

专业解析:移动硬盘“要求格式化”背后的真相与数据救援策略

引言&#xff1a;格式化预警下的数据危机 在日常的数字生活中&#xff0c;移动硬盘作为数据存储与传输的重要工具&#xff0c;其稳定性与安全性直接关系到用户资料的安全。然而&#xff0c;不少用户遭遇过这样一个令人头疼的问题——移动硬盘在接入电脑后&#xff0c;系统突然…

Tcping:一款实用的端口存活检测工具

简介 tcping 是一个基于TCP协议的网络诊断工具,通过发送 TCP SYN/ACK包来检测目标主机的端口状态。 官网:tcping.exe - ping over a tcp connection 优点: (1)监听服务器端口状态:tcping 可以检测指定端口的状态,默认是80端口,也可以指定其他端口。 (2)显示ping返…

MATLAB系列08:输入/输入函数

MATLAB系列08&#xff1a;输入/输入函数 8. 输入/输入函数8.1 函数textread8.2 关于load和save命令的进一步说明8.3 MATLAB文件过程简介8.4 文件的打开和关闭8.4.1 fopen函数8.4.2 fclose函数 8.5 二进制 I/O 函数8.5.1 fwrite 函数8.5.2 fread函数 8.6 格式化 I/O 函数8.6.1 f…

【漏洞复现】金斗云 HKMP download 任意文件读取漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

[Meachines] [Medium] Sniper RFI包含远程SMB+ powershell用户横向+CHM武器化权限提升

信息收集 IP AddressOpening Ports10.10.10.151TCP:80,135,139,445,49667 $ nmap -p- 10.10.10.151 --min-rate 1000 -sC -sV -Pn PORT STATE SERVICE VERSION 80/tcp open http Microsoft IIS httpd 10.0 |_http-server-header: Microsoft-IIS/10.…