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

使用Gson序列化时byte[]被转为ArrayList,如何避免类型转换?

解决Gson反序列化时byte[]转为ArrayList的问题(不修改Object字段类型)

当使用Gson序列化包含Object类型字段的实体类时,如果该字段存储的是byte[]数组,反序列化后会被转换为ArrayList,而非原有的byte[]类型。以下是具体场景:

实体类代码:

public class RequesterArgument implements Serializable {
    private Object data;
    
    public void setData(Object data) {
        this.data = data;
    }

    public Object getData() {
        return data;
    }
}

测试代码:

byte[] data = {74,97,118,97,73,110,85,115,101};
RequesterArgument request = new RequesterArgument();
request.setData(data);

// 序列化前输出类型:[B
System.out.println(request.getData().getClass().getName());

// 序列化与反序列化
String jsonString = new Gson().toJson(request);
RequesterArgument response = new Gson().fromJson(jsonString, RequesterArgument.class);

// 反序列化后输出类型:java.util.ArrayList
System.out.println(response.getData().getClass().getName());

原因分析

Gson默认将byte[]序列化为JSON数组,而反序列化到Object类型字段时,由于没有明确的类型提示,Gson会将JSON数组默认转换为ArrayList。

解决方案

无需修改Object类型字段,通过自定义TypeAdapter实现类型的正确还原,以下提供两种可行方案:

方案1:针对byte[]的极简适配器

适用于确定Object字段仅存储byte[]的场景:

import com.google.gson.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

public class ByteArrayObjectAdapter extends TypeAdapter<Object> {
    private final Gson defaultGson = new Gson();

    @Override
    public void write(JsonWriter out, Object value) throws IOException {
        if (value instanceof byte[]) {
            byte[] bytes = (byte[]) value;
            out.beginArray();
            for (byte b : bytes) {
                out.value(b);
            }
            out.endArray();
        } else {
            defaultGson.getAdapter(value.getClass()).write(out, value);
        }
    }

    @Override
    public Object read(JsonReader in) throws IOException {
        if (in.peek() == JsonToken.BEGIN_ARRAY) {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            in.beginArray();
            while (in.hasNext()) {
                baos.write(in.nextInt());
            }
            in.endArray();
            return baos.toByteArray();
        } else {
            return defaultGson.fromJson(in, Object.class);
        }
    }
}

使用方式:创建Gson实例时注册该适配器

Gson gson = new GsonBuilder()
        .registerTypeAdapter(Object.class, new ByteArrayObjectAdapter())
        .create();

// 后续序列化反序列化使用这个gson实例即可
String jsonString = gson.toJson(request);
RequesterArgument response = gson.fromJson(jsonString, RequesterArgument.class);
// 输出类型:[B
System.out.println(response.getData().getClass().getName());

方案2:带类型标记的通用适配器

适用于Object字段可能存储多种类型的场景,通过在JSON中保留类型信息实现精准还原:

import com.google.gson.*;
import com.google.gson.stream.JsonReader;
import com.google.gson.stream.JsonWriter;
import java.io.IOException;
import java.lang.reflect.Type;

public class TypedObjectAdapter implements TypeAdapter<Object> {
    private final Gson defaultGson = new Gson();

    @Override
    public void write(JsonWriter out, Object value) throws IOException {
        out.beginObject();
        // 写入类型全限定名
        out.name("type").value(value.getClass().getName());
        out.name("value");
        // 针对byte[]单独处理,其他类型用默认序列化
        if (value instanceof byte[]) {
            byte[] bytes = (byte[]) value;
            out.beginArray();
            for (byte b : bytes) {
                out.value(b);
            }
            out.endArray();
        } else {
            defaultGson.getAdapter(value.getClass()).write(out, value);
        }
        out.endObject();
    }

    @Override
    public Object read(JsonReader in) throws IOException {
        in.beginObject();
        String typeName = null;
        JsonElement valueElement = null;
        while (in.hasNext()) {
            switch (in.nextName()) {
                case "type":
                    typeName = in.nextString();
                    break;
                case "value":
                    valueElement = JsonParser.parseReader(in);
                    break;
                default:
                    in.skipValue();
            }
        }
        in.endObject();

        if (typeName == null || valueElement == null) {
            return null;
        }

        try {
            Class<?> targetClass = Class.forName(typeName);
            if (targetClass == byte[].class) {
                JsonArray array = valueElement.getAsJsonArray();
                byte[] bytes = new byte[array.size()];
                for (int i = 0; i < array.size(); i++) {
                    bytes[i] = array.get(i).getAsByte();
                }
                return bytes;
            } else {
                return defaultGson.fromJson(valueElement, targetClass);
            }
        } catch (ClassNotFoundException e) {
            throw new JsonParseException("无法识别类型:" + typeName, e);
        }
    }
}

使用方式同样是注册适配器:

Gson gson = new GsonBuilder()
        .registerTypeAdapter(Object.class, new TypedObjectAdapter())
        .create();

此时序列化后的JSON会包含类型信息,例如:

{"data":{"type":"[B","value":[74,97,118,97,73,110,85,115,101]}}

反序列化时即可准确还原原类型,同时支持Object字段存储其他类型的对象。


内容的提问来源于stack exchange,提问作者Ganesh Gudghe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 13:30:39