1、序列化之Java序列化工具详解

Java对象的序列化与反序列化工具对比
本文详细介绍了Java中常用的序列化和反序列化工具,包括Jackson、Gson和Fastjson。Jackson以其高性能和低内存占用成为SpringMVC的默认选择,Gson则因其对Java特性的良好支持受到青睐,而Fastjson则以其速度著称。对于小数据量,推荐使用Gson,大数据量场景下Jackson更优,但Fastjson在某些情况下可能存在安全问题。

Java的序列化与反序列化工具详解

1、序列化和反序列化定义

序列化:Java序列化是指把Java对象转换为可传输的字节序列的过程;

反序列化:而Java反序列化是指把传输的字节序列恢复为Java对象的过程。这两个过程使我们非常方便的存储和传输数据。

2、工具介绍

2.1、Jackson(即ObjectMapper)

2.1.1概述:
	Jackson 是当前用的比较广泛的,用来序列化和反序列化 json 的 Java 的开源框架。Jackson 社区相对比较活跃,更新速度也比较快, 从 Github 中的统计来看,Jackson 是最流行的 json 解析器之一 。 
2.1.2、优点:
	Spring MVC 的默认 json 解析器便是 Jackson。 
	Jackson 所依赖的 jar 包较少 ,简单易用。
	与其他 Java 的 json 的框架 Gson 等相比, Jackson 解析大的 json 文件速度比较快;
	Jackson 运行时占用内存比较低,性能比较好;
	Jackson 有灵活的 API,可以很容易进行扩展和定制。
2.1.3、使用方法:
jackson
//maven依赖
//该依赖同时会将如下库添加到项目路径中:
//jackson-annotations-2.9.8.jar
//jackson-core-2.9.8.jar
//jackson-databind-2.9.8.jar
<!-- json数据的解析包 -->
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.9.3</version>
  </dependency>
   
//导包: 
import com.fasterxml.jackson.databind.ObjectMapper;

//序列化
ObjectMapper mapper = new ObjectMapper();
String s = mapper.writeValueAsString(all);
//反序列化
ObjectMapper mapper = new ObjectMapper();
List list = mapper.readValue(categories, List.class);
2.1.4、工具类:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @author :
 * @date :Created in 19:30 2022/7/18
 * @description :
 * @version: 1.0
 */
public class ObjectMapperUtils {

    public static final ObjectMapper mapper = new ObjectMapper();

    private static final Logger logger = LoggerFactory.getLogger(JsonUtils.class);

    public static String toString(Object obj) {
        if (obj == null) {
            return null;
        }
        if (obj.getClass() == String.class) {
            return (String) obj;
        }
        try {
            return mapper.writeValueAsString(obj);
        } catch (JsonProcessingException e) {
            logger.error("json序列化出错:" + obj, e);
            return null;
        }
    }

    public static <T> T toBean(String json, Class<T> tClass) {
        try {
            return mapper.readValue(json, tClass);
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }

    public static <E> List<E> toList(String json, Class<E> eClass) {
        try {
            return mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, eClass));
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }

    public static <K, V> Map<K, V> toMap(String json, Class<K> kClass, Class<V> vClass) {
        try {
            return mapper.readValue(json, mapper.getTypeFactory().constructMapType(Map.class, kClass, vClass));
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }

    public static <T> T nativeRead(String json, TypeReference<T> type) {
        try {
            return mapper.readValue(json, type);
        } catch (IOException e) {
            logger.error("json解析出错:" + json, e);
            return null;
        }
    }
}

2.2、Gson

2.2.1、概述:
	Gson是一个Java库,可用于将Java对象转换为JSON表示,它也可以用来将JSON字符串转换为等效的Java对象。使用的主要类是Gson,可以通过调用创建new Gson(),Gson实例在调用Json操作时不保持任何状态,所以,你可以自由地重复使用同一个对象来进行多个Json序列化和反序列化操作。
2.2.2、优点:
1.gson默认支持LocalData;
2.如果字段被标记为transient,(默认情况下)它会被忽略并且不包含在 JSON 序列化或反序列化中;
3.此实现正确处理空值,序列化时,从输出中跳过空字段反序列化时,JSON 中缺少条目导致将对象中的相应字段设置为 null;
4.如果字段是synthetic的,则它会被忽略并且不包括在 JSON 序列化或反序列化中。
2.2.3、使用方法:
//maven依赖
<dependency>
  <groupId>com.google.code.gson</groupId>
  <artifactId>gson</artifactId>
  <version>2.8.6</version>
</dependency>
       
//需要导包
import com.google.gson.Gson;

//序列化
String s = new Gson().toJson(setMealDetails);
//反序列化
Setmeal setmeal = new Gson().fromJson(json, Setmeal.class);
2.2.4、工具类:

import cn.hutool.core.date.DatePattern;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
import com.google.gson.reflect.TypeToken;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @author :
 * @date :Created in 20:12 2022/7/18
 * @description :Gson序列化工具类
 * @version: 1.0
 */
@Slf4j
public class GsonSerializeUtils {

    public static final Gson gsonToJson = new GsonBuilder()
            .registerTypeAdapter(LocalDateTime.class, new JsonSerializer<LocalDateTime>() {
                @Override
                public JsonElement serialize(LocalDateTime localDateTime, Type type, JsonSerializationContext jsonSerializationContext) {
                    return new JsonPrimitive(localDateTime.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
                }
            })
            .registerTypeAdapter(LocalDate.class, new JsonSerializer<LocalDate>() {
                @Override
                public JsonElement serialize(LocalDate localDate, Type typeOfSrc, JsonSerializationContext context) {
                    return new JsonPrimitive(localDate.format(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
                }
            })
            .registerTypeAdapter(Date.class, new JsonSerializer<Date>() {
                @Override
                public JsonElement serialize(Date date, Type typeOfSrc, JsonSerializationContext context) {
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
                    String dateString = simpleDateFormat.format(date);
                    return new JsonPrimitive(dateString);
                }
            })
            .serializeNulls()
            .create();


    public static final  Gson gsonToBean = new GsonBuilder()
            .registerTypeAdapter(LocalDateTime.class, new JsonDeserializer() {
                @Override
                public LocalDateTime deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                    return LocalDateTime.parse(json.getAsJsonPrimitive().getAsString(), DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN));
                }
            })
            .registerTypeAdapter(LocalDate.class, new JsonDeserializer() {
                @Override
                public LocalDate deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                    return LocalDate.parse(json.getAsJsonPrimitive().getAsString(), DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN));
                }
            })
            .registerTypeAdapter(Date.class, new JsonDeserializer() {
                @SneakyThrows
                @Override
                public Date deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
                    SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DatePattern.NORM_DATETIME_PATTERN);
                    return simpleDateFormat.parse(json.getAsJsonPrimitive().getAsString());
                }
            })
            .create();

    public static String toString(Object obj) {
        if (obj.getClass() == String.class) {
            return (String) obj;
        }
        try {
            return gsonToJson.toJson(obj);
        } catch (Exception e) {
            log.error("json序列化出错:" + obj, e);
            return null;
        }
    }

    public static <T> T toBean(String json, Class<T> tClass) {
        if(json == null || json.equals("")){
            return null;
        }
        try {
            return gsonToBean.fromJson(json, tClass);
        } catch (Exception e) {
            log.error("json解析Bean出错:" + json, e);
            return null;
        }
    }

    public static <E> List<E> toList(String json, Class<E> eClass) {
        try {
            return gsonToBean.fromJson(json, new TypeToken<List<E>>(){}.getType());
        } catch (Exception e) {
            log.error("json解析List出错:" + json, e);
            return null;
        }
    }

    public static <K, V> Map<K, V> toMap(String json, Class<K> kClass, Class<V> vClass) {
        try {
            return gsonToBean.fromJson(json, new TypeToken<Map<K, V>>(){}.getType());
        } catch (Exception e) {
            log.error("json解析出错:" + json, e);
            return null;
        }
    }

    public static <T> T nativeRead(String json,  TypeToken typeToken) {
        try {
            return gsonToBean.fromJson(json, typeToken.getType());
        } catch (Exception e) {
            log.error("json解析出错:" + json, e);
            return null;
        }
    }

}

2.3、Fastjson

2.3.1、概述:
	JSON、JSONObject都是FastJson框架中的东西,JSON协议使用方便,越来越流行,JSON的处理器有很多,这里先介绍一下FastJson,FastJson是阿里的开源框架,被不少企业使用,是一个极其优秀的Json框架。
2.3.2、优点:

​ 1.FastJson数度快,无论序列化和反序列化,都是当之无愧的fast

​ 2.功能强大(支持普通JDK类包括任意Java Bean Class、Collection、Map、Date或enum)

​ 3.零依赖(没有依赖其它任何类库)

2.3.3、JSON、JSONObject、javabean关系的解析:

​ 首先JSON、JSONObject是属于FastJson框架的类,它们就是普通的类只不过在FastJson框架赋予了它们对json格式字符的处理能力。

JSON:fastJson的解析器,用于JSON格式字符串与JSON对象及javaBean之间的转换。

JSONObject:fastJson提供处理对象样子的json字符的类。

2.3.4、使用方法:
//maven依赖
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>fastjson</artifactId>
  <version>1.2.58</version>
</dependency>

//导包
import com.alibaba.fastjson.JSONObject;


//序列化
String jsonString = JSON.toJSONString(updateResponse)
//反序列化
Student student = JSON.parseObject("对象样子的json字符", new TypeReference<Student>() {});

//反序列化 json格式数据(需要是最外层为{}包裹的)转换为Map集合
//如果最外层是[]包裹的,则需要使用parseArray()方法来处理转换为List集合
Map<String, String> spec = JSON.parseObject(sku.getSpec(), Map.class);

//将json格式字符串转换成List集合, 如果json字符串最外层是方括号[]使用这个方法
//JSON.parseArray();

2.4、性能对比及选择

当数据量较小的时候(1~100),建议使用 Gson;
当数据量较大的时候,建议使用Jackson;
在大数据量的时候,虽然FastJson优势上来了,但是因为有漏洞,不得不放弃。
<think>好的,我现在需要帮助用户了解如何追踪`drm_atomic_crtc_set_property`这个用户API函数的调用流程。首先,我得确认自己对这个问题有足够的理解。用户提到这是一个提供给用户的API函数,所以应该属于DRMDirect Rendering Manager)子系统的一部分,用于设置CRTC(阴极射线管控制器,在现代GPU中通常指显示控制器)的原子属性。 首先,我应该回忆一下DRM框架的基本结构。DRM在内核中负责处理图形渲染和显示输出,支持原子更新,允许用户空间程序通过ioctl调用来修改显示相关的属性,比如分辨率、色彩模式等。原子更新意味着所有的更改在一次操作中提交,避免中间状态导致的闪烁或不一致。 接下来,`drm_atomic_crtc_set_property`这个函数的作用可能是在原子提交过程中设置CRTC的属性。用户想知道如何追踪这个函数的调用流程,也就是从用户空间发起调用,经过内核的各个层次,直到这个函数被执行的过程。 为了追踪这个调用流程,我需要考虑以下几个方面: 1. **用户空间的API**:用户程序如何调用这个函数。通常DRM的用户空间接口是通过libdrm库提供的,而libdrm会通过ioctl系统调用与内核交互。因此,可能需要检查libdrm中相关的函数,比如`drmModeObjectSetProperty`。 2. **内核中的ioctl处理**:DRM驱动会注册一系列的ioctl处理函数,对应的命令可能是`DRM_IOCTL_MODE_ATOMIC`。当用户空间发起ioctl调用时,内核的DRM子系统会解析请求,并调用相应的处理函数。 3. **原子提交流程**:在原子模式下,用户空间会准备一个原子请求(drm_mode_atomic),其中包含多个属性的更改。内核会遍历这些属性,并针对每个对象(如CRTC、Plane、Connector)调用对应的set_property函数,这里就是`drm_atomic_crtc_set_property`。 4. **属性定义和操作**:每个CRTC属性在驱动中应该有对应的定义,包括属性ID、类型以及如何设置的回调函数。`drm_atomic_crtc_set_property`可能需要根据属性ID来调用不同的处理逻辑,或者将值传递给底层的硬件驱动。 现在,我需要将这些步骤具体化,并给出用户可以用来追踪调用的方法。可能需要使用调试工具,如ftrace、printk,或者动态调试(dynamic_debug)来在内核代码中添加日志,观察函数调用的路径。另外,查看内核源码中相关函数的调用关系也是必要的。 可能的步骤包括: - **查找用户空间调用路径**:确定用户程序如何通过libdrm发起设置属性的请求,比如使用`drmModeAtomicAddProperty`函数,然后提交原子请求。 - **分析内核ioctl处理**:在内核中,`drm_mode_atomic_ioctl`函数处理用户空间的原子提交请求。该函数会解析用户传递的drm_mode_atomic结构,逐个处理每个属性更新。 - **跟踪属性处理流程**:在原子提交过程中,对于每个CRTC的属性,内核会调用`drm_atomic_crtc_set_property`函数。这个函数可能进一步调用驱动特定的回调函数,比如`atomic_set_property`。 - **使用调试工具**:在关键函数中添加printk语句,或者启用DRM的调试输出(如启用动态调试开关`CONFIG_DRM_DEBUG_SELFTEST`),或者使用ftrace来跟踪函数调用图。 另外,需要考虑到不同内核版本之间的差异,函数名或流程可能有所变化。因此,用户需要根据自己使用的内核版本来调整追踪的方法。 可能遇到的问题包括: - 如何确定用户空间的调用对应到内核的哪个ioctl? 这需要了解libdrm和内核之间的接口定义,通常libdrm的`xf86drmMode.h`中定义了相关的函数和结构体,而内核的`drm/drm_mode.h`定义了对应的ioctl命令和数据结构。 - 如何确认`drm_atomic_crtc_set_property`是否被正确调用? 在函数内部添加调试输出,或者使用kprobes来动态跟踪函数的执行。 - 如果驱动没有正确实现该函数,或者属性未正确注册,应该如何排查? 需要检查驱动代码中CRTC的初始化部分,确认属性是否通过`drm_object_attach_property`或类似函数注册,并且确认`atomic_set_property`回调是否被正确设置。 总结来说,追踪`drm_atomic_crtc_set_property`的调用流程需要结合用户空间的库函数、内核的ioctl处理、原子提交逻辑以及驱动中的具体实现。通过代码分析、调试工具和日志输出,可以逐步理清整个调用链。</think>要追踪`drm_atomic_crtc_set_property`函数的调用流程,可以按照以下步骤逐步分析: --- ### **1. 用户空间调用路径** 用户程序通过 **libdrm** 提供的接口发起属性修改请求: - **关键函数**:`drmModeAtomicAddProperty`(添加属性到原子请求)和`drmModeAtomicCommit`(提交请求)。 - **触发流程**: ```c drmModeAtomicAddProperty(atomic_req, crtc_id, property_id, value); drmModeAtomicCommit(fd, atomic_req, flags, NULL); ``` 提交后会触发`DRM_IOCTL_MODE_ATOMIC`的ioctl调用。 --- ### **2. 内核ioctl处理** 内核中处理原子提交的入口是`drm_mode_atomic_ioctl`函数- **代码路径**:`drivers/gpu/drm/drm_atomic_uapi.c` - **关键操作**: - 解析用户传递的`drm_mode_atomic`结构。 - 遍历每个属性对象(CRTC、Plane、Connector等),调用对应的`set_property`函数- 对于CRTC属性,最终调用`drm_atomic_crtc_set_property`。 --- ### **3. 属性设置流程** 在`drm_atomic_crtc_set_property`中: - **代码路径**:`drivers/gpu/drm/drm_atomic.c` - **关键逻辑**: - 根据`property_id`匹配CRTC的属性列表。 - 将用户空间传递的`value`写入CRTC的原子状态(`drm_crtc_state`)。 - 可能触发驱动实现的回调(如`.atomic_set_property`)。 --- ### **4. 调试与追踪方法** #### **(1) 内核日志(printk)** 在关键函数中添加调试输出: ```c // 在drm_atomic_crtc_set_property中添加printk int drm_atomic_crtc_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val) { printk(KERN_DEBUG "Setting CRTC%d property %s to %llu\n", crtc->base.id, property->name, val); // ...原有逻辑... } ``` 重新编译内核并查看`dmesg`输出。 #### **(2) 动态调试(Dynamic Debug)** 启用DRM子系统的动态调试: ```bash echo 'file drm_atomic* +p' > /sys/kernel/debug/dynamic_debug/control ``` 这会打印`drm_atomic`相关函数的调用信息。 #### **(3) Ftrace函数追踪** 使用ftrace追踪调用链: ```bash # 启用函数追踪 echo function > /sys/kernel/debug/tracing/current_tracer # 过滤DRM相关函数 echo "drm_atomic_*" > /sys/kernel/debug/tracing/set_ftrace_filter # 开始追踪 echo 1 > /sys/kernel/debug/tracing/tracing_on # 执行用户程序触发调用 cat /sys/kernel/debug/tracing/trace ``` #### **(4) 代码分析工具** 使用`cscope`或`ctags`在Linux内核源码中查找调用关系: ```bash # 在源码根目录生成索引 make cscope # 搜索drm_atomic_crtc_set_property的调用者 cscope -d -L3 drm_atomic_crtc_set_property ``` --- ### **5. 驱动实现示例** 检查驱动中CRTC属性的注册和回调: ```c // 驱动初始化时注册CRTC属性 static const struct drm_prop_enum_list prop_list[] = { {DRM_MODE_PROP_CRTC_MODE_ID, "MODE_ID"}, // ...其他属性... }; void my_crtc_init(struct drm_device *dev, struct drm_crtc *crtc) { // 创建属性 struct drm_property *prop = drm_property_create_range(dev, 0, "my_prop", 0, 100); // 将属性附加到CRTC drm_object_attach_property(&crtc->base, prop, 0); } // 实现atomic_set_property回调 static int my_crtc_atomic_set_property(struct drm_crtc *crtc, struct drm_crtc_state *state, struct drm_property *property, uint64_t val) { if (property == my_prop) { state->custom_value = val; // 保存到状态 return 0; } return -EINVAL; } ``` --- ### **常见问题排查** - **属性未生效**:检查驱动是否注册了对应属性,且`drm_atomic_crtc_set_property`是否正确处理了`property_id`。 - **内核崩溃**:确认传递的`value`范围合法,驱动回调未访问无效内存。 - **无调试输出**:检查内核配置是否启用`CONFIG_DRM_DEBUG`或动态调试未正确启用。 通过以上步骤,可以系统性地追踪`drm_atomic_crtc_set_property`的调用流程,定位问题根源。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白de成长之路

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值