700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > Gson转换错误导致Int变为Double类型

Gson转换错误导致Int变为Double类型

时间:2022-06-01 05:26:03

相关推荐

Gson转换错误导致Int变为Double类型

情况说明

需要解析的json

{"status": 200,"msg": "OK","data": [{"id": 1,"username": "eric","password": "123456","age": 29,"sex": 0,"permission": 0,"isDel": 0}]}

类的定义

@Datapublic class ResponseData implements Serializable {// 响应业务状态private Integer status;// 响应消息private String msg;// 响应中的数据private Object data;}

解析后

ResponseData(status=200, msg=OK, data=[{id=1.0, username=eric, password=123456, age=29.0, sex=0.0, permission=0.0, isDel=0.0}])

进行处理后,变为

{"status": 200,"msg": "OK","data": [{"id": 1.0,"username": "eric","password": "123456","age": 29.0,"sex": 0.0,"permission": 0.0,"isDel": 0.0}]}

问题分析

Object最后默认的TypeAdapter使用的是com.google.gson.internal.bind包下的ObjectTypeAdapter,处理如下

/*** Adapts types whose static type is only 'Object'. Uses getClass() on* serialization and a primitive/Map/List on deserialization.*/public final class ObjectTypeAdapter extends TypeAdapter<Object> {public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {@SuppressWarnings("unchecked")@Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {if (type.getRawType() == Object.class) {return (TypeAdapter<T>) new ObjectTypeAdapter(gson);}return null;}};private final Gson gson;ObjectTypeAdapter(Gson gson) {this.gson = gson;}@Override public Object read(JsonReader in) throws IOException {JsonToken token = in.peek();switch (token) {case BEGIN_ARRAY:List<Object> list = new ArrayList<Object>();in.beginArray();while (in.hasNext()) {list.add(read(in));}in.endArray();return list;case BEGIN_OBJECT:Map<String, Object> map = new LinkedTreeMap<String, Object>();in.beginObject();while (in.hasNext()) {map.put(in.nextName(), read(in));}in.endObject();return map;case STRING:return in.nextString();case NUMBER:return in.nextDouble();case BOOLEAN:return in.nextBoolean();case NULL:in.nextNull();return null;default:throw new IllegalStateException();}}@SuppressWarnings("unchecked")@Override public void write(JsonWriter out, Object value) throws IOException {if (value == null) {out.nullValue();return;}TypeAdapter<Object> typeAdapter = (TypeAdapter<Object>) gson.getAdapter(value.getClass());if (typeAdapter instanceof ObjectTypeAdapter) {out.beginObject();out.endObject();return;}typeAdapter.write(out, value);}}

查看read方法发现所有的Number类型都被转成了double类型,想要修改掉这个问题,需要自己实现一个TypeAdapter,处理Number类型的问题,自己重写TypeAdapter

解决

上面我们分析后,是需要去重写TypeAdapter方法,在重写的这个方法里面,我们需要将其写出为对应的方法

第一步:重写TypeAdapter方法

public class ResponseDataTypeAdaptor extends TypeAdapter<ResponseData> {public static final TypeAdapterFactory FACTORY = new TypeAdapterFactory() {@SuppressWarnings("unchecked")@Overridepublic <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) {if (type.getRawType() == ResponseData.class) {return (TypeAdapter<T>) new ResponseDataTypeAdaptor(gson);}return null;}};private final Gson gson;ResponseDataTypeAdaptor(Gson gson) {this.gson = gson;}@Overridepublic void write(JsonWriter out, ResponseData value) throws IOException {if (value == null) {out.nullValue();return;}out.beginObject();out.name("status");gson.getAdapter(Integer.class).write(out, value.getStatus());out.name("msg");gson.getAdapter(String.class).write(out, value.getMsg());out.name("data");gson.getAdapter(Object.class).write(out, value.getData());out.endObject();}@Overridepublic ResponseData read(JsonReader in) throws IOException {ResponseData data = new ResponseData();Map<String, Object> dataMap = (Map<String, Object>) readInternal(in);data.setStatus((Integer) dataMap.get("status"));data.setMsg((String) dataMap.get("msg"));data.setData(dataMap.get("data"));return data;}private Object readInternal(JsonReader in) throws IOException {JsonToken token = in.peek();switch (token) {case BEGIN_ARRAY:List<Object> list = new ArrayList<Object>();in.beginArray();while (in.hasNext()) {list.add(readInternal(in));}in.endArray();return list;case BEGIN_OBJECT:Map<String, Object> map = new LinkedTreeMap<String, Object>();in.beginObject();while (in.hasNext()) {map.put(in.nextName(), readInternal(in));}in.endObject();return map;case STRING:return in.nextString();case NUMBER:String numberStr = in.nextString();if (numberStr.contains(".") || numberStr.contains("e") || numberStr.contains("E")) {return Double.parseDouble(numberStr);}if (Long.parseLong(numberStr) <= Integer.MAX_VALUE) {return Integer.parseInt(numberStr);}return Long.parseLong(numberStr);case BOOLEAN:return in.nextBoolean();case NULL:in.nextNull();return null;default:throw new IllegalStateException();}}}

第二步:注册gson

将自己重写的TypeAdapter注册一下

private static Gson buildGson() {GsonBuilder gsonBuilder = new GsonBuilder();gsonBuilder.registerTypeAdapterFactory(DataTypeAdaptor.FACTORY);return gsonBuilder.create();}

第三步:测试

public class GsonTest {public static void main(String[] args) {String dataJson = "{\"status\":200,\"msg\":\"OK\",\"data\":[{\"id\":1,\"username\":\"eric\",\"password\":\"123456\",\"age\":29,\"sex\":0,\"permission\":0,\"isDel\":0}]}";Gson gson = buildGson();ResponseData data = gson.fromJson(dataJson, ResponseData.class);System.out.println(data.toString());}}

其他问题

解析过程中,还会出现转换问题,如:

com.google.gson.internal.LinkedTreeMap cannot be cast to XXX

问题1:LinkedTreeMap cannot be cast to XXX

这种情况出现的原因是:

进行到对list进行操作的那步,报错了(java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to xx)。原来list中的数据是LinkedTreeMap 格式的,并没有转换成对应的实体类。

那么现在就需要自己去改写一下之前所重写的TypeAdapter方法

问题1:解决

去遍历这个LinkedTreeMap 这个Map

LinkedTreeMap,可通过key来获取value的map

如下去一步一步遍历,将遍历的结果设置到对应的实体类中

LinkedTreeMap tm = (LinkedTreeMap)fromJson2;Iterator it = tm.keySet().iterator(); while (it.hasNext()) {String key = (String) it.next();String value = (String)tm.get(key);}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。