使用指定旧HTTP库时,Gson解析含字节数组的JSON出现「期望对象却得到数组」错误的原因及解决疑问
问题分析与解决方案
首先看你的报错信息Expected BEGIN_OBJECT but was BEGIN_ARRAY,这已经很明确了——你返回的JSON是一个数组(外层是[]),但你却试图把它解析成单个PDFResponse对象,这是导致错误的直接原因。先解决这个核心问题,再处理字节数组的适配。
第一步:修复数组解析的问题
你的接口返回的是包含单个PDFResponse对象的JSON数组,所以需要把解析代码改成解析数组类型,两种方式任选:
方式1:解析为List<PDFResponse>
@Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { Type listType = new TypeToken<List<PDFResponse>>() {}.getType(); List<PDFResponse> pdfResponseList = gson.fromJson(new String(responseBody), listType); // 取第一个元素使用(根据业务确认数组非空) if (!pdfResponseList.isEmpty()) { PDFResponse pdfResponse = pdfResponseList.get(0); Debug.i("pdf: success "); } }
方式2:解析为PDFResponse数组
@Override public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) { PDFResponse[] pdfResponses = gson.fromJson(new String(responseBody), PDFResponse[].class); // 取第一个元素使用(根据业务确认数组非空) if (pdfResponses.length > 0) { PDFResponse pdfResponse = pdfResponses[0]; Debug.i("pdf: success "); } }
第二步:处理byte[]字段的解析问题
解决数组问题后,你会发现imgBinaryData字段仍无法正确解析——因为JSON里的imgBinaryData是整数数组(比如[-1,40,-1]),而Gson默认不会自动把int[]转成byte[](两者取值范围不同:byte是-128到127,int范围更大)。这里提供两种解决方案:
方案A:修改POJO字段类型,手动转换
把POJO里的byte[] imgBinaryData改成int[]或List<Integer>,然后在需要使用时手动转成byte数组:
public class PDFResponse { private Integer pdfconfigid; @SerializedName("LocationName") // 匹配JSON里的大写键 private String locationName; @SerializedName("imgBinaryData") private int[] imgBinaryData; // 改成int数组 // 其他字段同理添加@SerializedName匹配JSON键 @SerializedName("LocationCode") private String locationCode; @SerializedName("ActiveStatus") private String activeStatus; // ...省略getter/setter // 手动转换为byte数组的方法 public byte[] getImgBinaryDataAsBytes() { if (imgBinaryData == null) return null; byte[] bytes = new byte[imgBinaryData.length]; for (int i = 0; i < imgBinaryData.length; i++) { // 注意:若JSON中的int值超出byte范围会自动截断,需根据业务确认是否允许 bytes[i] = (byte) imgBinaryData[i]; } return bytes; } }
方案B:自定义Gson TypeAdapter,自动转换
如果不想修改POJO字段类型,可以写一个自定义适配器处理int数组到byte数组的转换:
public class ByteArrayTypeAdapter extends TypeAdapter<byte[]> { @Override public void write(JsonWriter out, byte[] value) throws IOException { if (value == null) { out.nullValue(); return; } out.beginArray(); for (byte b : value) { out.value(b & 0xFF); // 转成无符号int输出,避免负数序列化问题 } out.endArray(); } @Override public byte[] read(JsonReader in) throws IOException { if (in.peek() == JsonToken.NULL) { in.nextNull(); return null; } in.beginArray(); List<Byte> byteList = new ArrayList<>(); while (in.hasNext()) { int intValue = in.nextInt(); // 可添加逻辑处理超出byte范围的int值,这里直接强制转换 byteList.add((byte) intValue); } in.endArray(); // 转为byte数组返回 byte[] result = new byte[byteList.size()]; for (int i = 0; i < result.length; i++) { result[i] = byteList.get(i); } return result; } }
然后创建Gson实例时注册这个适配器:
Gson gson = new GsonBuilder() .registerTypeAdapter(byte[].class, new ByteArrayTypeAdapter()) .create();
这样就能直接把JSON里的int数组解析为POJO中的byte[]了。
最后补充:你的JSON键是大写开头(如LocationName),POJO字段是小写开头,一定要给这些字段添加@SerializedName注解,否则Gson无法正确映射字段。
内容的提问来源于stack exchange,提问作者Pemba Tamang
相关产品推荐
相关产品推荐

