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

如何配置Gson使继承类导出JSON时父类字段优先或自定义顺序?

解决Gson导出JSON时父类字段优先/自定义字段顺序的问题

你可以通过两种方式实现Gson序列化时父类字段优先,或者自定义字段输出顺序:

方案一:用@SerializedName指定序列化优先级

Gson的@SerializedName注解支持通过serialize参数设置字段的序列化顺序,数值越小,字段越先被序列化。给父类字段设置更小的数值,子类字段设置更大的数值即可。

代码示例:

父类Foo:

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public abstract class Foo {
    @Expose
    @SerializedName(value = "name", serialize = 1)
    private String name;

    // 构造器、getter/setter 自行补充
}

子类Bar:

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

public class Bar extends Foo {
    @Expose
    @SerializedName(value = "value", serialize = 2)
    private int value;

    // 构造器、getter/setter 自行补充
}

初始化Gson并序列化:

Gson gson = new GsonBuilder()
        .excludeFieldsWithoutExposeAnnotation() // 启用@Expose注解过滤
        .create();

Bar bar = new Bar();
bar.setName("test");
bar.setValue(123);
String json = gson.toJson(bar);
// 输出结果:{"name":"test","value":123}

方案二:自定义TypeAdapterFactory统一处理继承结构

如果需要批量处理大量继承类,不想逐个字段加注解,可以自定义TypeAdapterFactory,强制先序列化父类字段,再序列化子类字段。

代码示例:

自定义Factory:

import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

public class ParentFirstTypeAdapterFactory implements TypeAdapterFactory {
    @Override
    public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {
        Class<?> clazz = type.getRawType();
        // 仅处理非Object的子类
        if (clazz.getSuperclass() == Object.class) {
            return null;
        }

        final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
        final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);

        return new TypeAdapter<T>() {
            @Override
            public void write(JsonWriter out, T value) throws Exception {
                JsonObject jsonObject = delegate.toJsonTree(value).getAsJsonObject();
                JsonObject orderedObject = new JsonObject();

                // 先添加父类的@Expose字段
                List<Field> parentFields = getAllFields(clazz.getSuperclass());
                for (Field field : parentFields) {
                    String fieldName = getSerializedName(field);
                    if (jsonObject.has(fieldName)) {
                        orderedObject.add(fieldName, jsonObject.get(fieldName));
                        jsonObject.remove(fieldName);
                    }
                }

                // 再添加子类剩余的字段
                orderedObject.addAll(jsonObject);

                elementAdapter.write(out, orderedObject);
            }

            @Override
            public T read(JsonReader in) throws Exception {
                return delegate.read(in);
            }

            // 递归获取类的所有@Expose字段(包括私有)
            private List<Field> getAllFields(Class<?> clazz) {
                List<Field> fields = new ArrayList<>();
                while (clazz != Object.class) {
                    for (Field field : clazz.getDeclaredFields()) {
                        if (field.isAnnotationPresent(Expose.class)) {
                            fields.add(field);
                        }
                    }
                    clazz = clazz.getSuperclass();
                }
                return fields;
            }

            // 获取字段的序列化名称,优先用@SerializedName的值,没有则用字段名
            private String getSerializedName(Field field) {
                SerializedName annotation = field.getAnnotation(SerializedName.class);
                return annotation != null ? annotation.value() : field.getName();
            }
        };
    }
}

使用自定义Factory:

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

Bar bar = new Bar();
bar.setName("test");
bar.setValue(123);
String json = gson.toJson(bar);
// 输出结果:{"name":"test","value":123}

注意事项

  • 方案一简单直观,适合字段数量少、需要精准控制单个字段顺序的场景;方案二更适合批量处理多个继承类的情况。
  • Gson默认的字段顺序依赖JVM反射获取字段的顺序,不同环境可能有差异,显式指定顺序能保证输出稳定。

内容的提问来源于stack exchange,提问作者Dylan Trenti

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.25 22:45:33