You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用GSON反序列化Reddit API中类型动态的edited字段?

解决Reddit API中edited字段的GSON反序列化问题

哈哈,这个坑我当初对接Reddit API的时候踩过!GSON默认的类型转换根本搞不定这种同一个字段既可能是布尔值(未编辑时为false)又可能是长整型时间戳(编辑过的情况)的场景,直接转Boolean肯定会炸。不过咱们可以通过自定义反序列化逻辑轻松解决,给你两种实用方案:

方案一:自定义JsonDeserializer(快速实现)

这种方法适合只需要反序列化的场景,逻辑直观好写。

步骤1:定义实体类

你可以把edited字段定义为Long类型——用null表示未编辑,有值则为编辑时间戳;或者封装成一个更清晰的自定义类,比如EditedInfo:

选项A:用Long直接存储

public class RedditPost {
    // 其他字段(比如id、title等)
    private Long edited; // null = 未编辑,非null = 编辑时间戳
}

选项B:封装成自定义类(更易读)

public class EditedInfo {
    private boolean isEdited;
    private Long editTimestamp;

    public EditedInfo(boolean isEdited, Long editTimestamp) {
        this.isEdited = isEdited;
        this.editTimestamp = editTimestamp;
    }

    // 省略getter、setter方法
}

// 实体类中使用
public class RedditPost {
    // 其他字段
    private EditedInfo edited;
}

步骤2:编写自定义反序列化器

对应选项A的反序列化器

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;

public class EditedLongDeserializer implements JsonDeserializer<Long> {
    @Override
    public Long deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json.isJsonPrimitive()) {
            var primitive = json.getAsJsonPrimitive();
            if (primitive.isBoolean()) {
                // 未编辑时返回null
                return primitive.getAsBoolean() ? null : null;
            } else if (primitive.isNumber()) {
                // 编辑过则返回时间戳
                return primitive.getAsLong();
            }
        }
        // 处理异常情况,返回null或抛出异常按需选择
        return null;
    }
}

对应选项B的反序列化器

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;

public class EditedInfoDeserializer implements JsonDeserializer<EditedInfo> {
    @Override
    public EditedInfo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json.isJsonPrimitive()) {
            var primitive = json.getAsJsonPrimitive();
            if (primitive.isBoolean()) {
                return new EditedInfo(false, null);
            } else if (primitive.isNumber()) {
                return new EditedInfo(true, primitive.getAsLong());
            }
        }
        // 未知类型返回默认未编辑状态
        return new EditedInfo(false, null);
    }
}

步骤3:注册反序列化器到GSON

// 对应选项A
Gson gson = new GsonBuilder()
        .registerTypeAdapter(Long.class, new EditedLongDeserializer())
        .create();

// 对应选项B
Gson gson = new GsonBuilder()
        .registerTypeAdapter(EditedInfo.class, new EditedInfoDeserializer())
        .create();

// 开始反序列化
RedditPost post = gson.fromJson(yourJsonString, RedditPost.class);

方案二:自定义TypeAdapter(性能更优,支持序列化)

如果之后需要把数据序列化回符合Reddit格式的JSON,用TypeAdapter更合适,它的读写逻辑都能自定义,性能也比JsonDeserializer好一点。

步骤1:复用方案一中的EditedInfo类

步骤2:编写TypeAdapter

import com.google.gson.TypeAdapter;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonToken;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;

public class EditedInfoTypeAdapter extends TypeAdapter<EditedInfo> {
    @Override
    public void write(JsonWriter out, EditedInfo value) throws IOException {
        // 序列化时:未编辑写false,编辑过写时间戳
        if (value == null || !value.isEdited()) {
            out.value(false);
        } else {
            out.value(value.getEditTimestamp());
        }
    }

    @Override
    public EditedInfo read(JsonReader in) throws IOException {
        JsonToken token = in.peek();
        if (token == JsonToken.BOOLEAN) {
            return new EditedInfo(false, null);
        } else if (token == JsonToken.NUMBER) {
            return new EditedInfo(true, in.nextLong());
        } else {
            // 跳过未知类型,返回默认状态
            in.skipValue();
            return new EditedInfo(false, null);
        }
    }
}

步骤3:注册TypeAdapter

Gson gson = new GsonBuilder()
        .registerTypeAdapter(EditedInfo.class, new EditedInfoTypeAdapter())
        .create();

// 反序列化和序列化都能用
RedditPost post = gson.fromJson(yourJsonString, RedditPost.class);
String serializedJson = gson.toJson(post);

注意事项

  • Reddit的edited字段一般只有两种情况:false(未编辑)或长整型时间戳(已编辑),很少出现true的情况,所以上面的逻辑完全覆盖主流场景。
  • 如果需要处理极端异常情况(比如字段是字符串),可以在反序列化器里加额外判断,避免抛出解析异常。

内容的提问来源于stack exchange,提问作者Charlie Niekirk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 10:05:37