欢迎访问悦橙教程(wld5.com),关注java教程。悦橙教程  java问答|  每日更新
页面导航 : > > 文章正文

FastJSON 对 `Integer` 类型的编解码(序列化和反序列化),FastJSON在初

来源: javaer 分享于  点击 36917 次 点评:9

FastJSON 对 `Integer` 类型的编解码(序列化和反序列化),FastJSON在初


FastJSON 对 Integer 类型的编解码(序列化和反序列化)是通过内置的 IntegerCodec 类实现的。FastJSON 在初始化时,会通过 ParserConfig 和 SerializeConfig 自动默认注册该编解码器。

FastJSON 对 Integer 类型的编解码(序列化和反序列化)是通过内置的 IntegerCodec 类实现的。本文基于 fastjson-1.2.83 讲解其核心实现逻辑和源码分析。


1. 源码定位

FastJSON 的 Integer 编解码逻辑位于 com.alibaba.fastjson.serializer.IntegerCodec 类中。该类实现了 ObjectSerializerObjectDeserializer 接口,分别负责序列化和反序列化。

package com.alibaba.fastjson.serializer;

public class IntegerCodec implements ObjectSerializer, ObjectDeserializer {

    public static IntegerCodec instance = new IntegerCodec();

    public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features)
        throws IOException {
        ...
    }
    
    public <T> T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) {
        ...
    }

    public int getFastMatchToken() {
        return JSONToken.LITERAL_INT; // 整数字面量
    }
}

2. 序列化源码(Integer → JSON)

入口方法: IntegerCodec#write

public void write(JSONSerializer serializer, Object object, Object fieldName, Type fieldType, int features) throws IOException {
    SerializeWriter out = serializer.out;
    Number value = (Number) object;

    if (value == null) {
        out.writeNull(); // 处理 null 值
        return;
    }

    // 直接输出整数
    if (object instanceof Long) {
        out.writeLong(value.longValue());
    } else {
        out.writeInt(value.intValue());
    }
}

关键点:

  1. 直接写入整数值:将 Integer(或Long) 转换为 基本类型int(或long) 后直接输出,避免装箱/拆箱。
  2. 处理 null 值:如果输入为 null,输出 JSON 的 null

3. 反序列化源码(JSON → Integer

入口方法: IntegerCodec#deserialze

// 输入:parser-语法解析器(即 JSON 解析器),包含词法分析器 (lexer)
        clazz-目标类型(如 Integer.class 或 AtomicInteger.class)
        fieldName-当前字段名(用于错误提示)
// 输出:反序列化后的对象(Integer 或 AtomicInteger)
public <T> T deserialze(DefaultJSONParser parser, Type clazz, Object fieldName) {
    final JSONLexer lexer = parser.lexer; // lexer-词法分析器

    final int token = lexer.token(); // token-词法单元

    // 处理 JSON 空值 。当检测到 null 值时,跳过当前 token 并返回 null
    if (token == JSONToken.NULL) {
        lexer.nextToken(JSONToken.COMMA);
        return null;
    }


    Integer intObj;
    try {
        if (token == JSONToken.LITERAL_INT) { // 整数字面量
            int val = lexer.intValue();
            lexer.nextToken(JSONToken.COMMA);
            intObj = Integer.valueOf(val);
        } else if (token == JSONToken.LITERAL_FLOAT) { // 浮点数字面量
            BigDecimal number = lexer.decimalValue();
            intObj = TypeUtils.intValue(number); // 浮点转整数,截断小数(非四舍五入,可能丢失精度)
            lexer.nextToken(JSONToken.COMMA);
        } else {
            if (token == JSONToken.LBRACE) { // 当 JSON 值为对象(如 {"$value": 123})时,解析整个对象并通过 TypeUtils 转换
                JSONObject jsonObject = new JSONObject(true);
                parser.parseObject(jsonObject);
                intObj = TypeUtils.castToInt(jsonObject);
            } else { // 兜底处理。处理非基础类型(如字符串 "123"、布尔值等)的转换
                Object value = parser.parse();
                intObj = TypeUtils.castToInt(value);
            }
        }
    } catch (Exception ex) { // 异常封装:统一抛出 JSONException 避免底层异常泄露
        String message = "parseInt error";
        if (fieldName != null) {
            message += (", field : " + fieldName);
        }
        throw new JSONException(message, ex); // 带字段名的错误提示(附加字段信息便于调试)
    }

    // 通过 clazz 参数确保返回类型正确性(Integer或 AtomicInteger)
    if (clazz == AtomicInteger.class) {
        return (T) new AtomicInteger(intObj.intValue());
    }
    return (T) intObj;
}

关键点:

  1. 支持多种输入格式
    • JSON 整数(123)直接解析为 Integer
    • JSON 字符串("123")转换为 Integer
    • JSON null 解析为 null
    • 其他类型(如浮点数 123.0 123.5)通过 Number 类型转换,可能会丢失精度哦。
  2. 严格的类型检查:非法格式(如非数字字符串)会抛出JSONException异常。

4. 编解码器注册

FastJSON 在初始化时,会通过 ParserConfigSerializeConfig 自动注册默认编解码器。IntegerCodec 的注册逻辑如下:

源码片段(ParserConfig#initDeserializers

// 反序列化器注册
deserializers.put(Integer.class, IntegerCodec.instance);
deserializers.put(int.class, IntegerCodec.instance);

源码片段(SerializeConfig#initSerializers

// 序列化器注册
put(Integer.class, IntegerCodec.instance);
put(int.class, IntegerCodec.instance);

5. 性能优化

FastJSON 对 Integer 的编解码做了以下优化:

  1. 避免对象创建:直接操作原始类型 int,减少装箱/拆箱。
  2. 快速路径(Fast Path):针对常见的整数输入格式(如 JSONToken.LITERAL_INT)直接解析。
  3. 缓存常用值:JVM 对 Integer 的缓存(-128~127)被隐式利用,减少对象创建。

6. 示例:序列化与反序列化过程

序列化过程(Integer → JSON)

Integer num = 100;
String json = JSON.toJSONString(num); // 输出: 100

反序列化过程(JSON → Integer

String json = "200";
Integer num = JSON.parseObject(json, Integer.class); // 结果: 200

7. 扩展应用场景

1. 自定义类型处理器

可继承 IntegerCodec 覆盖 deserialze 方法,实现如:

// 处理十六进制字符串 "0xFF" → 255
if (token == JSONToken.LITERAL_STRING) {
    String hex = lexer.stringVal();
    return Integer.parseInt(hex.substring(2), 16);
}

2. 结合注解使用

通过 @JSONField(deserializeUsing = CustomIntegerCodec.class) 指定自定义解析器


总结

FastJSON 通过 IntegerCodec 实现了 Integer 的高效编解码,核心逻辑包括:

  1. 直接操作原始类型(int等基础类型,primitive type)避免性能损耗。
  2. 支持多种输入格式(整数、字符串、其他数字类型)。
  3. 严格校验非法输入,保证数据安全。

这种设计模式可以完全复用到自定义类型(如 Money)的编解码实现中。


当看到一些不好的代码时,会发现我还算优秀;当看到优秀的代码时,也才意识到持续学习的重要!--buguge
本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/buguge/p/18838633


相关栏目:

用户点评