背景:
Gson在使用gson.fromJson对json对象中带int类型的数据转换时候,会存在nt类型转换为double的情况,原因是Gson在解释数据过程中的number类型处理导致的;具体见ObjectTypeAdapter类 的read方法
@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();// 处理number类型数据,会自动转换为double类型case NUMBER:return in.nextDouble();case BOOLEAN:return in.nextBoolean();case NULL:in.nextNull();return null;default:throw new IllegalStateException();}}
代码中使用到的Gson版本为2.8.6版本,笔者本人也尝试过使用Gson的高版本2.9.1版本,Number类型的实现方式稍有出入,不过结果还是相同解析int类型数据依旧转换为double
<dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.6.4</version></dependency>
示例:
public static void main(String[] args) {String str = "{\"msg\":\"操作成功\",\"code\":200,\"data\":\"$f8ff483ee9d57d5ef5d1adf4385a24b\"}";BaseResult baseResult = new Gson().fromJson(str,BaseResult.class);System.out.println(111);}
解决方案:自定义TypeAdapter,复制ObjectTypeAdapter中的所有代码,只修改read方法中关于Number类型的处理
package com.yojofly.server.config;import com.google.gson.Gson;import com.google.gson.TypeAdapter;import com.google.gson.TypeAdapterFactory;import com.google.gson.internal.LinkedTreeMap;import com.google.gson.internal.bind.ObjectTypeAdapter;import com.google.gson.reflect.TypeToken;import com.google.gson.stream.JsonReader;import com.google.gson.stream.JsonToken;import com.google.gson.stream.JsonWriter;import org.ponent;import java.io.IOException;import java.util.*;@Componentpublic class GsonTypeAdaptor 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 GsonTypeAdaptor(gson);}return null;}};private Gson gson;GsonTypeAdaptor(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:// 自定义的number类型处理String s = in.nextString();if (s.contains(".")) {return Double.valueOf(s);} else {try {return Integer.valueOf(s);} catch (Exception e) {return Long.valueOf(s);}}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);}}
最后需要将自定义的GsonTypeAdaptor注册到GsonBuilder中
public static final Gson gson = getGson();public static Gson getGson() {Gson gson = new GsonBuilder().create();try {Field factories = Gson.class.getDeclaredField("factories");factories.setAccessible(true);Object o = factories.get(gson);Class<?>[] declaredClasses = Collections.class.getDeclaredClasses();for (Class c : declaredClasses) {if ("java.util.Collections$UnmodifiableList".equals(c.getName())) {Field listField = c.getDeclaredField("list");listField.setAccessible(true);List<TypeAdapterFactory> list = (List<TypeAdapterFactory>) listField.get(o);int i = list.indexOf(ObjectTypeAdapter.FACTORY);list.set(i, GsonTypeAdaptor.FACTORY);break;}}} catch (Exception e) {e.printStackTrace();}return gson;}
示例:
public static void main(String[] args) {String str = "{\"msg\":\"操作成功\",\"code\":200,\"data\":\"$f8ff483ee9d57d5ef5d1adf4385a24b\"}";BaseResult baseResult = gson.fromJson(str,BaseResult.class);System.out.println(111);}
最后解决该问题。
网上也有通过如下代码实现自定义typeAdapter注册,但笔者多次尝试如下代码并不生效
new GsonBuilder().registerTypeAdapter(new TypeToken<Map<String,Object>>(){}.getType(),new DataTypeAdapter()).create();