问:
- 为什么解析的时候int会自动转成double
- float数据为什么会丢失
解析流程
graph TD
开始解析fromJson --> 获取解析的类型TypeToken --> 通过类型获取对应的Adapter --> 通过read方法获取对应的字段 --> 反射的方式获取字段的值 --> 每个字段都会对应一个Adapter --> 调用JsonReader的next系列方法截取对应的值-->调用系统方法直接将截取的值转化成对应的类型-->返回对应的字段值每个字段的解析类似
//下面一段代码解析流程是怎样的呢
var gsonStr = "{"code":"0","message":"","data":{"format":"#########0.###","format2":3.111110498093283782,"format3":3.045124912412,"format4":3.99992753112},"success":true}"
var gson = Gson().newBuilder().also {
//it.serializeSpecialFloatingPointValues()
}.create()
val model: Model = gson.fromJson<Model>(gsonStr,
Model::class.java
)
//数据类
data class Model(var code: String, var result: String?,var message:String?,var msg:String?, var data: Data)
data class Data(var format: String, var accuracy: Float?,var comma:Float?,var zero:Float?)
fromJson方法:通过传入string,初始化对应TypeToken,然后在找到对应Adapter,通过Adapter进行解析
//Gson.java文件
public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
Object object = fromJson(json, (Type) classOfT);
return Primitives.wrap(classOfT).cast(object);
}
/****中间省略若干代码****/
public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
if (json == null) {
return null;
}
//创建StringReader,只是string的包装类
StringReader reader = new StringReader(json);
T target = (T) fromJson(reader, typeOfT);
return target;
}
/****中间省略若干代码****/
public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
//创建JsonReader
JsonReader jsonReader = newJsonReader(json);
T object = (T) fromJson(jsonReader, typeOfT);
assertFullConsumption(object, jsonReader);
return object;
}
/****中间省略若干代码****/
public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
boolean isEmpty = true;
boolean oldLenient = reader.isLenient();
reader.setLenient(true);
try {
//检测类型
reader.peek();
isEmpty = false;
//获取当前类型对应的token,说白了只是简单包装一下
TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
//获取解析的Adapter
TypeAdapter<T> typeAdapter = getAdapter(typeToken);
//解析成对应得数据类型
T object = typeAdapter.read(reader);
return object;
} catch (EOFException e) {
/*
* For compatibility with JSON 1.5 and earlier, we return null for empty
* documents instead of throwing.
*/
if (isEmpty) {
return null;
}
throw new JsonSyntaxException(e);
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IOException e) {
// TODO(inder): Figure out whether it is indeed right to rethrow this as JsonSyntaxException
throw new JsonSyntaxException(e);
} catch (AssertionError e) {
AssertionError error = new AssertionError("AssertionError (GSON " + GsonBuildConfig.VERSION + "): " + e.getMessage());
error.initCause(e);
throw error;
} finally {
reader.setLenient(oldLenient);
}
}
TypeToken.get(typeOfT)方法:获取对应的TypeToken,通过对应的解析类型方便后续获得想要的Adapter
这里主要理解TypeToken这个类:
public class TypeToken<T> {
final Class<? super T> rawType;
final Type type;
final int hashCode;
TypeToken(Type type) {
//获取对应的Type,实际上就是Class
this.type = $Gson$Types.canonicalize($Gson$Preconditions.checkNotNull(type));
//真实的Class带泛型类型的
this.rawType = (Class<? super T>) $Gson$Types.getRawType(this.type);
//注意这里,重新定义了hashcode,用来在Map里面比对两个TypeToken是不是同一个对象,外界一般传递的是
//class,所以只需要是一样的class,那hashcode就是一样得,那最后在Gson的typeTokenCache或者calls这个Map结构存的
//key是同一个,也就保障了后边取值的时候取得是同一个
this.hashCode = this.type.hashCode();
}
//这里比较的是两个对象是否相等
@Override public final boolean equals(Object o) {
return o instanceof TypeToken<?>
&& $Gson$Types.equals(type, ((TypeToken<?>) o).type);
}
}
/*******$Gson$Types.equals方法******/
public static boolean equals(Type a, Type b) {
if (a == b) {
// also handles (a == null && b == null)
return true;
} else if (a instanceof Class) {
// Class already specifies equals().
//这里调用的是Object的方法,这里应该明白判定两个TypeToken对象是否相等逻辑了吧
//就是判定其T泛型是否相等,也就是你传入的解析class类型是否一致,如果一致就是一样的Adapter
return a.equals(b);
}
/*******省略其他代码******/
}
/*******截取代码*******/
//传过来的Type一般是解析目标对象的class类型
public static Type canonicalize(Type type) {
if (type instanceof Class) {
Class<?> c = (Class<?>) type;
return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;
}
/*******省略其他代码******/
}
/*******截取代码*******/
//传过来的Type一般是解析目标对象的class类型
public static Class<?> getRawType(Type type) {
if (type instanceof Class<?>) {
// type is a normal class.
return (Class<?>) type;
}
/*******省略其他代码******/
}
getAdapter方法:从factories中获取对应得Adapter,并缓存在当前线程中
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
//缓存中获取adapter
TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
if (cached != null) {
return (TypeAdapter<T>) cached;
}
//当前线程中得adapter集合
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
boolean requiresThreadLocalCleanup = false;
//当前线程没有Adapter集合就创建一个
if (threadCalls == null) {
threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true;
}
// the key and value type parameters always agree
//缓存中获取Adapter
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
try {
//新建Adapter代理工厂类,只是代理了Adapter得处理逻辑
FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
threadCalls.put(type, call);
for (TypeAdapterFactory factory : factories) {
//此方法很关键,factories是Gson初始化得时候构建
TypeAdapter<T> candidate = factory.create(this, type);
if (candidate != null) {
//设置具体得代理类,方便方法回调
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
//找到对应得Adapter并返回
return candidate;
}
}
throw new IllegalArgumentException("GSON (" + GsonBuildConfig.VERSION + ") cannot handle " + type);
} finally {
threadCalls.remove(type);
if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
factories:添加默认得解析工厂,比如Object、Long、Double等类型,根据需要解析的数据类型,返回对应的Adapter
List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
// built-in type adapters that cannot be overridden
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);
// the excluder must precede all adapters that handle user-defined types
factories.add(excluder);
// users' type adapters
factories.addAll(factoriesToBeAdded);
// type adapters for basic platform types
factories.add(TypeAdapters.STRING_FACTORY);
factories.add(TypeAdapters.INTEGER_FACTORY);
factories.add(TypeAdapters.BOOLEAN_FACTORY);
factories.add(TypeAdapters.BYTE_FACTORY);
factories.add(TypeAdapters.SHORT_FACTORY);
TypeAdapter<Number> longAdapter = longAdapter(longSerializationPolicy);
factories.add(TypeAdapters.newFactory(long.class, Long.class, longAdapter));
factories.add(TypeAdapters.newFactory(double.class, Double.class,
doubleAdapter(serializeSpecialFloatingPointValues)));
factories.add(TypeAdapters.newFactory(float.class, Float.class,
floatAdapter(serializeSpecialFloatingPointValues)));
factories.add(TypeAdapters.NUMBER_FACTORY);
factories.add(TypeAdapters.ATOMIC_INTEGER_FACTORY);
factories.add(TypeAdapters.ATOMIC_BOOLEAN_FACTORY);
factories.add(TypeAdapters.newFactory(AtomicLong.class, atomicLongAdapter(longAdapter)));
factories.add(TypeAdapters.newFactory(AtomicLongArray.class, atomicLongArrayAdapter(longAdapter)));
factories.add(TypeAdapters.ATOMIC_INTEGER_ARRAY_FACTORY);
factories.add(TypeAdapters.CHARACTER_FACTORY);
factories.add(TypeAdapters.STRING_BUILDER_FACTORY);
factories.add(TypeAdapters.STRING_BUFFER_FACTORY);
factories.add(TypeAdapters.newFactory(BigDecimal.class, TypeAdapters.BIG_DECIMAL));
factories.add(TypeAdapters.newFactory(BigInteger.class, TypeAdapters.BIG_INTEGER));
factories.add(TypeAdapters.URL_FACTORY);
factories.add(TypeAdapters.URI_FACTORY);
factories.add(TypeAdapters.UUID_FACTORY);
factories.add(TypeAdapters.CURRENCY_FACTORY);
factories.add(TypeAdapters.LOCALE_FACTORY);
factories.add(TypeAdapters.INET_ADDRESS_FACTORY);
factories.add(TypeAdapters.BIT_SET_FACTORY);
factories.add(DateTypeAdapter.FACTORY);
factories.add(TypeAdapters.CALENDAR_FACTORY);
factories.add(TimeTypeAdapter.FACTORY);
factories.add(SqlDateTypeAdapter.FACTORY);
factories.add(TypeAdapters.TIMESTAMP_FACTORY);
factories.add(ArrayTypeAdapter.FACTORY);
factories.add(TypeAdapters.CLASS_FACTORY);
// type adapters for composite and user-defined types
factories.add(new CollectionTypeAdapterFactory(constructorConstructor));
factories.add(new MapTypeAdapterFactory(constructorConstructor, complexMapKeySerialization));
this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
factories.add(jsonAdapterFactory);
factories.add(TypeAdapters.ENUM_FACTORY);
factories.add(new ReflectiveTypeAdapterFactory(
constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
this.factories = Collections.unmodifiableList(factories);
注:如果在解析得时候有传入具体得类型,走的是反射方式获取该类型的字段并调用对应的Adapter进行字段解析;
ReflectiveTypeAdapterFactory创建对应的反射Adapter
@Override public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
Class<? super T> raw = type.getRawType();
if (!Object.class.isAssignableFrom(raw)) {
return null; // it's a primitive!
}
ObjectConstructor<T> constructor = constructorConstructor.get(type);
return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
}
private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
if (raw.isInterface()) {
return result;
}
Type declaredType = type.getType();
while (raw != Object.class) {
//获取反射字段
Field[] fields = raw.getDeclaredFields();
//遍历所有字段
for (Field field : fields) {
boolean serialize = excludeField(field, true);
boolean deserialize = excludeField(field, false);
if (!serialize && !deserialize) {
continue;
}
accessor.makeAccessible(field);
Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
List<String> fieldNames = getFieldNames(field);
BoundField previous = null;
for (int i = 0, size = fieldNames.size(); i < size; ++i) {
String name = fieldNames.get(i);
if (i != 0) serialize = false; // only serialize the default name
//创建对应的BoundField并存入集合返回
BoundField boundField = createBoundField(context, field, name,
TypeToken.get(fieldType), serialize, deserialize);
BoundField replaced = result.put(name, boundField);
if (previous == null) previous = replaced;
}
if (previous != null) {
throw new IllegalArgumentException(declaredType
+ " declares multiple JSON fields named " + previous.name);
}
}
type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
raw = type.getRawType();
}
return result;
}
//
private ReflectiveTypeAdapterFactory.BoundField createBoundField(
final Gson context, final Field field, final String name,
final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
// special casing primitives here saves ~5% on Android...
JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
TypeAdapter<?> mapped = null;
if (annotation != null) {
mapped = jsonAdapterFactory.getTypeAdapter(
constructorConstructor, context, fieldType, annotation);
}
final boolean jsonAdapterPresent = mapped != null;
if (mapped == null) mapped = context.getAdapter(fieldType);
final TypeAdapter<?> typeAdapter = mapped;
return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
@SuppressWarnings({"unchecked", "rawtypes"}) // the type adapter and field type always agree
@Override void write(JsonWriter writer, Object value)
throws IOException, IllegalAccessException {
Object fieldValue = field.get(value);
TypeAdapter t = jsonAdapterPresent ? typeAdapter
: new TypeAdapterRuntimeTypeWrapper(context, typeAdapter, fieldType.getType());
t.write(writer, fieldValue);
}
//主要是read返回在Adapter中回调
@Override void read(JsonReader reader, Object value)
throws IOException, IllegalAccessException {
Object fieldValue = typeAdapter.read(reader);
if (fieldValue != null || !isPrimitive) {
//此处是通过Adapter读取到值之后进行赋值
field.set(value, fieldValue);
}
}
@Override public boolean writeField(Object value) throws IOException, IllegalAccessException {
if (!serialized) return false;
Object fieldValue = field.get(value);
return fieldValue != value; // avoid recursion for example for Throwable.cause
}
};
}
public static final class Adapter<T> extends TypeAdapter<T> {
private final ObjectConstructor<T> constructor;
private final Map<String, BoundField> boundFields;
Adapter(ObjectConstructor<T> constructor, Map<String, BoundField> boundFields) {
this.constructor = constructor;
this.boundFields = boundFields;
}
@Override public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
T instance = constructor.construct();
try {
in.beginObject();
while (in.hasNext()) {
String name = in.nextName();
//通过字段名获取对应的字段,并赋值给对应的实例instance
BoundField field = boundFields.get(name);
if (field == null || !field.deserialized) {
in.skipValue();
} else {
field.read(in, instance);
}
}
} catch (IllegalStateException e) {
throw new JsonSyntaxException(e);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
in.endObject();
return instance;
}
}
next方法获取对应的值
public double nextDouble() throws IOException {
int p = peeked;
if (p == PEEKED_NONE) {
p = doPeek();
}
if (p == PEEKED_LONG) {
peeked = PEEKED_NONE;
pathIndices[stackSize - 1]++;
return (double) peekedLong;
}
if (p == PEEKED_NUMBER) {
//直接截取对应的长度,其中peekedNumberLength的值是在doPeek()方法中确认的
peekedString = new String(buffer, pos, peekedNumberLength);
pos += peekedNumberLength;
} else if (p == PEEKED_SINGLE_QUOTED || p == PEEKED_DOUBLE_QUOTED) {
peekedString = nextQuotedValue(p == PEEKED_SINGLE_QUOTED ? ''' : '"');
} else if (p == PEEKED_UNQUOTED) {
peekedString = nextUnquotedValue();
} else if (p != PEEKED_BUFFERED) {
throw new IllegalStateException("Expected a double but was " + peek() + locationString());
}
peeked = PEEKED_BUFFERED;
//解析成对应的数据类型
double result = Double.parseDouble(peekedString); // don't catch this NumberFormatException.
if (!lenient && (Double.isNaN(result) || Double.isInfinite(result))) {
throw new MalformedJsonException(
"JSON forbids NaN and infinities: " + result + locationString());
}
peekedString = null;
peeked = PEEKED_NONE;
pathIndices[stackSize - 1]++;
return result;
}
解决问题1
//通过:Gson.fromJson<Any>(gsonStr, Any::class.java),这种方式解析的数据,如果数据中返回的是Int型数据,
//会自动转化成Double类型
public Object read(JsonReader in) throws IOException {
JsonToken token = in.peek();
switch(token) {
case BEGIN_ARRAY:
List<Object> list = new ArrayList();
in.beginArray();
while(in.hasNext()) {
list.add(this.read(in));
}
in.endArray();
return list;
case BEGIN_OBJECT:
Map<String, Object> map = new LinkedTreeMap();
in.beginObject();
while(in.hasNext()) {
map.put(in.nextName(), this.read(in));
}
in.endObject();
return map;
case STRING:
return in.nextString();
case NUMBER:
//数字类型,直接转化成double,保障了精度不丢失
return in.nextDouble();
case BOOLEAN:
return in.nextBoolean();
case NULL:
in.nextNull();
return null;
default:
throw new IllegalStateException();
}
}
解决方案可以参考:juejin.cn/post/695394… 原理就是重写其read方法,自定义解析规则,但有个缺点就是如果返回的是3.0会自动转成3,这种场景建议双方约定好解析类型,不用ObjectAdapter去解析
解决问题2
问题原因分析:
//比如3.312230498093283782会转成3.3122306
//但是3.000000498093283782会转成3.0000005
//3.111110498093283782会转成3.1111104
//这里是系统double强转float,至于为什么会出现这样情形。。。。。。母鸡!
public static final TypeAdapter<Number> FLOAT = new TypeAdapter<Number>() {
@Override
public Number read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return null;
}
//这里强转会丢失精度
return (float) in.nextDouble();
}
@Override
public void write(JsonWriter out, Number value) throws IOException {
out.value(value);
}
};
方案:直接使用double去解析