拆解Gson内核,当JSON遇上设计模式

155 阅读2分钟

Gson:数据世界的翻译官

Gson就像个语言天才,能瞬间把JSON字符串变成对象(反序列化),也能把对象打包成JSON包裹(序列化)。举个栗子,当服务器扔给你这样一坨数据:

{
  "name": "小明",
  "age": 18,
  "hobbies": ["coding", "gaming"]
}

Gson能瞬间把它变成:

Coder coder = new Gson().formJson(json, Code.class):

核心机密:TypeAdapter联盟

适配器界的变形金刚

TypeAdapter就像是不同部门的专员,每个类型都有自己的专属处理员。比如遇到Date类型,就派Date专员;遇到自定义的User类,就派反射专员。

// 以Date类型为例的简化版适配器
public class DateTypeAdapter extends TypeAdapter<Date> {
    private final DateFormat format = new SimpleDateFormat("yyyy-MM-dd");

    @Override
    public void write(JsonWriter out, Date value) throws IOException {
        out.value(format.format(value)); // 把Date变成字符串
    }

    @Override
    public Date read(JsonReader in) throws IOException {
        try {
            return format.parse(in.nextString()); // 把字符串还原成Date
        } catch (ParseException e) {
            throw new JsonParseException(e);
        }
    }
}

反射处理的黑科技

当遇到自定义类时,反射适配器就开始骚操作了:

public class ReflectiveTypeAdapter<T> extends TypeAdapter<T> {
    // 构造器工厂
    private final ObjectConstructor<T> constructor;
    // 字段绑定表(像快递单号对照表)
    private final Map<String, BoundField> boundFields;

    @Override
    public T read(JsonReader in) throws IOException {
        T instance= constructor.construct(); // 像拆快递一样创建对象
        in.beginObject();
        while (in.hasNext()) {
            String fieldName = in.nextName(); // 读取字段名
            BoundField field = boundFields.get(fieldName);
            if (field != null) {
                field.read(in, instance); // 按字段赋值
            } else {
                in.skipValue(); // 不认识的就扔掉
            }
        }
        in.endObject();
        return instance;
    }
}

工厂流水线的魔法

Gson内部有个TypeAdapter生产流水线,用工厂模式高效制造适配器:

public class Gson {
    // 适配器工厂列表(生产车间集合)
    private final List<TypeAdapterFactory> factories;

    public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
        // 走流水线逐个车间问能不能生产
        for (TypeAdapterFactory factory : factories) {
            TypeAdapter<T> candidate = factory.create(this, type);
            if (candidate != null) {
                return candidate; // 找到能生产的车间
            }
        }
        throw new IllegalArgumentException("没有适配器能处理: " + type);
    }
}

自定义你的专属翻译

方案一:全能型选手(继承TypeAdapter)

适合需要精确控制序列化和反序列化的场景:

public class UserAdapter extends TypeAdapter<User> {
    @Override
    public void write(JsonWriter out, User user) throws IOException {
        out.beginObject();
        out.name("fullName").value(user.getName()); // 字段重命名
        out.name("age").value(user.getAge());
        out.endObject();
    }

    @Override
    public User read(JsonReader in) throws IOException {
        User user = new User();
        in.beginObject();
        while (in.hasNext()) {
            switch (in.nextName()) {
                case"fullName":
                    user.setName(in.nextString());
                    break;
                case"age":
                    user.setAge(in.nextInt());
                    break;
            }
        }
        in.endObject();
        return user;
    }
}

方案二:灵活派(实现接口)

适合只需要处理单方向的场景:

public class UserDeserializer implements JsonDeserializer<User> {
    @Override
    public User deserialize(JsonElement json, Type type, 
                            JsonDeserializationContext context) {
        JsonObject obj= json.getAsJsonObject();
        User user=new User();
        // 处理嵌套对象
        user.setAddress(context.deserialize(obj.get("address"), Address.class));
        // 转换日期格式
        user.setBirthday(new Date(obj.get("birthday").getAsLong()));
        return user;
    }
}

开发小贴士

日期处理的坑:建议统一注册日期适配器

Gson gson = new GsonBuilder()
    .setDateFormat("yyyy-MM-dd HH:mm:ss")
    .create();

忽略未知字段:避免解析报错

Gson gson = new GsonBuilder()
    .excludeFieldsWithoutExposeAnnotation()
    .create();

Gson像一支设计模式交响乐团:

  • • 适配器模式:解决接口兼容问题
  • • 工厂模式:灵活创建对象
  • • 反射机制:处理未知类型
  • • 建造者模式:优雅配置参数

调用gson.fromJson()时,不妨想象背后这支交响乐团正在为你演奏数据的魔法。好的库设计就像乐谱,每个模式都在恰到好处的位置奏响和谐的旋律。