gson 분석 형식 오류 해결 데이터 crash
9924 단어 android
오프라인 과 백 엔 드 를 연결 할 때 이상 이 없습니다. 데 이 터 는 모두 인터페이스 문서 에 따라 주기 때 문 입 니 다.그러나 때때로 온라인 에 도착 하면 데이터 형식 은 더러 운 데이터 때문에 백 엔 드 가 데 이 터 를 되 돌려 줄 때 인터페이스 형식 에 따라 주지 않 는 데이터 구 조 를 되 돌려 준다.우리 가 자주 만 나 는 것 은 {} 대상 을 정의 하고 [] 데 이 터 를 주 었 거나 반대로 숫자 형식 이 비 숫자 형식 으로 되 돌아 간 것 이다.gson 해석 타 임 스 이상 을 일 으 켰 습 니 다.
gson 해석 원리
public T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
boolean isEmpty = true;
boolean oldLenient = reader.isLenient();
reader.setLenient(true);
try {
reader.peek();
isEmpty = false;
TypeToken typeToken = (TypeToken) TypeToken.get(typeOfT);
TypeAdapter 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);
} finally {
reader.setLenient(oldLenient);
}
}
들 어 오 는 유형 을 type: Token 으로 바 꾸 고 통과 합 니 다. type: Token 이 유형 을 해석 할 수 있 는 TypeAdapter 를 찾 습 니 다. 방법 은 List 를 옮 겨 다 니 는 것 입 니 다. factories. public TypeAdapter getAdapter(TypeToken type) {
TypeAdapter> cached = typeTokenCache.get(type);
if (cached != null) {
return (TypeAdapter) cached;
}
Map, FutureTypeAdapter>> threadCalls = calls.get();
boolean requiresThreadLocalCleanup = false;
if (threadCalls == null) {
threadCalls = new HashMap, FutureTypeAdapter>>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true;
}
// the key and value type parameters always agree
FutureTypeAdapter ongoingCall = (FutureTypeAdapter) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
try {
FutureTypeAdapter call = new FutureTypeAdapter();
threadCalls.put(type, call);
for (TypeAdapterFactory factory : factories) {
TypeAdapter candidate = factory.create(this, type);
if (candidate != null) {
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
return candidate;
}
}
throw new IllegalArgumentException("GSON cannot handle " + type);
} finally {
threadCalls.remove(type);
if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
캐 시 에서 찾 으 면 바로 돌아 가 고 분석 할 수 있 는 adapter 를 찾 을 때 까지 다시 찾 지 않 았 습 니 다.사용자 정의 TypeAdapter
gson 기본 구 조 는 여러 종류의 TypeAdapter 를 초기 화 했 습 니 다.
// 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 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);
대상 유형 을 분석 하 는 어댑터 ReflectiveTypeAdapter Factory. gs on 라 이브 러 리 가 final 형식 으로 정의 되 어 있 기 때문에 계승 을 통 해 수정 할 수 없습니다. json 문자열 을 분석 하 는 방법 을 복사 할 수 밖 에 없습니다. 내부 에 TypeAdapter 내부 클래스 를 설명 하고 read 방법 을 수정 할 수 있 습 니 다. @Override
public T read(JsonReader in) throws IOException {
if (in.peek() == JsonToken.NULL) {
in.nextNull();
return constructor.construct();
}
// ARRAY ( object), in ,
if (in.peek() == JsonToken.BEGIN_ARRAY) {
GsonTools.readArray(in);
return constructor.construct();
}
// NUMBER ( object), in ,
if (in.peek() == JsonToken.NUMBER) {
in.nextDouble();
return constructor.construct();
}
// String ( object), in ,
if (in.peek() == JsonToken.STRING) {
in.nextString();
return constructor.construct();
}
// name ( object), in ,
if (in.peek() == JsonToken.NAME) {
in.nextName();
return constructor.construct();
}
// bookean ( object), in ,
if (in.peek() == JsonToken.BOOLEAN) {
in.nextBoolean();
return constructor.construct();
}
T instance = constructor.construct();
try {
in.beginObject();
while (in.hasNext()) {
String name = in.nextName();
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;
}
그리고 Gson Builder 의 register TypeAdapter Factory 를 통 해 수 정 된 Reflective TypeAdapter Factory 를 추가 하면 됩 니 다. GsonBuilder gsonBuilder = new GsonBuilder();
Class builder = (Class) gsonBuilder.getClass();
Field f = null;
try {
//
f = builder.getDeclaredField("instanceCreators");
f.setAccessible(true);
final Map> val = (Map>) f.get(gsonBuilder);//
// String
gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(String.class,GsonTools.stringTypeAdapter()));
// int.class, Integer.class
gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(int.class, Integer.class, GsonTools.longAdapter(0)));
// short.class, Short.class
gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(short.class, Short.class, GsonTools.longAdapter(1)));
// long.class, Long.class
gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(long.class, Long.class, GsonTools.longAdapter(2)));
// double.class, Double.class
gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(double.class, Double.class, GsonTools.longAdapter(3)));
// float.class, Float.class
gsonBuilder.registerTypeAdapterFactory(TypeAdapters.newFactory(float.class, Float.class, GsonTools.longAdapter(4)));
//
gsonBuilder.registerTypeAdapterFactory(new ReflectiveTypeAdapterFactory(new ConstructorConstructor(val), FieldNamingPolicy.IDENTITY, Excluder.DEFAULT));
//
gsonBuilder.registerTypeAdapterFactory(new CollectionTypeAdapterFactory(new ConstructorConstructor(val)));
} catch (Exception e) {
e.printStackTrace();
}
첨가 해서 gsonBuilder.registerTypeAdapterFactory(new ReflectiveTypeAdapterFactory(new ConstructorConstructor(val), FieldNamingPolicy.IDENTITY, Excluder.DEFAULT)); Gson Builder 류 의 개인 변수 가 필요 합 니 다. 우 리 는 반 사 를 통 해 이 인 자 를 얻 을 수 있 습 니 다.
자주 사용 하 는 형식의 adapter
자주 사용 하 는 형식의 adapter 는 빈 칸 을 판정 하고 데이터 형식 이 잘못된 검 사 를 했 습 니 다. github 에 전송 되 었 습 니 다. 공동 교 류 를 환영 합 니 다.
https://github.com/850125665/MGson
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Kotlin의 기초 - 2부지난 글에서는 Kotlin이 무엇인지, Kotlin의 특징, Kotlin에서 변수 및 데이터 유형을 선언하는 방법과 같은 Kotlin의 기본 개념에 대해 배웠습니다. 유형 변환은 데이터 변수의 한 유형을 다른 데이터...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.