序列化反序列化

序列化反序列化

当你将一个抽象类序列化反序列化的时候,需要自动反序列化
JacksonPolymorphicDeserialization · FasterXML/jackson-docs Wiki · GitHub
注意,如果只是一个类中的一个属性包含了一个抽象类的话,上面的这个例子就可以解决问题,但是如果是泛型的话,例如 List<XXX>,光配置注解无效,序列化的时候不会自动填充 property 字段,那怎么办呢,我们可以手动设置 property 属性的值,注意要用实例属性,而不是静态属性,然后我们在代码块中 this.getClass().canonicalName() 获取类名赋值给 property 属性即可。
写点儿代码试试。
写代码描述一下这个问题

fastjson 如何解决复杂对象的序列化和反序列化问题

fastjson 中可以配置将序列化地所有数据的类型信息都放到 json 里面,这样什么类型信息都不会丢失,它可以在序列化时保留对象类型信息,然后在反序列化时根据 json 字符串中的类型信息自动生成对象,用法很简单,只需要 JSONWriter.Feature.WriteClassNameJSONReader.Feature.SupportAutoType 结合使用即可。
简单实践
首先得引入 fastjson2 的依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>2.0.21</version>
</dependency>

然后使用这两个特性

package xyz.xiashuo;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
/**
 * @author xiashuo.xyz
 * @date 2024/4/5 11:09
 */
public class FastJsonTest {
    String name = "xiasshuo";
    public static void main(String[] args) {
        // Hero hero = Hero.getList().get(0);
        FastJsonTest testObj = new FastJsonTest();
        String jsonString = JSONObject.toJSONString(testObj, JSONWriter.Feature.WriteClassName);
        FastJsonTest testObjCopy = JSONObject.parseObject(jsonString, FastJsonTest.class, JSONReader.Feature.SupportAutoType);
        System.out.println(testObjCopy.name);
    }
}

jackson 应该也有类似的配置,TODO

利用 Jackson 实现将方法的所有参数序列化成字符串,然后将字符串反序列化成对象,然后通过反射调用方法

重点是当我们获取参数的 Type 类型之后,如何通过 Jackson 将其反序列化成对象

在使用 Jackson 库时,如果你需要根据 ParameterizedType 动态反序列化泛型类型,可以通过以下步骤来实现。Jackson 提供了一些工具类和方法来处理泛型类型的反序列化。

1. 使用 TypeReference

TypeReference 是 Jackson 提供的一个工具类,可以用来指定泛型的具体类型。通过继承 TypeReference 并指定泛型的具体类型,可以在反序列化时保留类型信息。

示例代码

假设我们有一个泛型类 Response<T>,我们希望根据 ParameterizedType 动态反序列化具体的类型。

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

public class JacksonDynamicDeserializationExample {
    public static void main(String[] args) {
        // 假设这是你从JSON化对象中得到的JSON字符串
        String jsonString = "{\"data\":[{\"name\":\"John\", \"age\":30}, {\"name\":\"Jane\", \"age\":25}]}";

        // 创建ObjectMapper实例
        ObjectMapper objectMapper = new ObjectMapper();

        try {
            // 获取泛型类型
            Type genericType = new GenericType<Response<List<Person>>>(){}.getType();

            // 将JSON字符串转换为Response对象
            Response<?> response = objectMapper.readValue(jsonString, new TypeReference<Response<List<Person>>>() {});

            // 打印对象的属性
            for (Person person : (List<Person>) response.getData()) {
                System.out.println("Name: " + person.getName() + ", Age: " + person.getAge());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 定义一个泛型类来获取ParameterizedType
    static class GenericType<T> {
        private final Type type;

        protected GenericType() {
            Type superClass = getClass().getGenericSuperclass();
            if (superClass instanceof ParameterizedType) {
                this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
            } else {
                throw new IllegalArgumentException("Invalid type");
            }
        }

        public Type getType() {
            return type;
        }
    }
}

class Response<T> {
    private T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

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;
    }
}

2. 使用 JavaType

JavaType 是 Jackson 提供的另一个工具类,可以用来构建复杂的泛型类型。JavaType 可以通过 ObjectMappergetTypeFactory() 方法创建。

示例代码

假设我们有一个泛型类 Response<T>,我们希望根据 ParameterizedType 动态反序列化具体的类型。

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

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

public class JacksonDynamicJavaTypeExample {
    public static void main(String[] args) {
        // 假设这是你从JSON化对象中得到的JSON字符串
        String jsonString = "{\"data\":[{\"name\":\"John\", \"age\":30}, {\"name\":\"Jane\", \"age\":25}]}";

        // 创建ObjectMapper实例
        ObjectMapper objectMapper = new ObjectMapper();

        try {
            // 获取泛型类型
            Type genericType = new GenericType<Response<List<Person>>>(){}.getType();

            // 构建JavaType
            JavaType javaType = objectMapper.getTypeFactory().constructType(genericType);

            // 将JSON字符串转换为Response对象
            Response<?> response = objectMapper.readValue(jsonString, javaType);

            // 打印对象的属性
            for (Person person : (List<Person>) response.getData()) {
                System.out.println("Name: " + person.getName() + ", Age: " + person.getAge());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 定义一个泛型类来获取ParameterizedType
    static class GenericType<T> {
        private final Type type;

        protected GenericType() {
            Type superClass = getClass().getGenericSuperclass();
            if (superClass instanceof ParameterizedType) {
                this.type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
            } else {
                throw new IllegalArgumentException("Invalid type");
            }
        }

        public Type getType() {
            return type;
        }
    }
}

class Response<T> {
    private T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

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;
    }
}

总结

JavaType 除了 可以通过 constructType 构造之外,还可以通过 constructCollectionType 或者 constructParametricType 等其他方法构造

示例代码

假设我们有一个泛型类 Response<T>,我们希望将其反序列化为具体的类型。

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

import java.util.List;

public class JacksonJavaTypeExample {
    public static void main(String[] args) {
        // 假设这是你从 JSON 化对象中得到的 JSON 字符串
        String jsonString = "{\"data\":[{\"name\":\"John\", \"age\":30}, {\"name\":\"Jane\", \"age\":25}]}";

        // 创建ObjectMapper实例
        ObjectMapper objectMapper = new ObjectMapper();

        try {
            // 使用JavaType构建泛型的具体类型
            JavaType personListType = objectMapper.getTypeFactory().constructCollectionType(List.class, Person.class);
            JavaType responseType = objectMapper.getTypeFactory().constructParametricType(Response.class, personListType);

            // 将JSON字符串转换为Response对象
            Response<List<Person>> response = objectMapper.readValue(jsonString, responseType);

            // 打印对象的属性
            for (Person person : response.getData()) {
                System.out.println("Name: " + person.getName() + ", Age: " + person.getAge());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class Response<T> {
    private T data;

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }
}

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;
    }
}