使用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
相关产品推荐
相关产品推荐

