gson 분석 형식 오류 해결 데이터 crash

9924 단어 android
문제.
오프라인 과 백 엔 드 를 연결 할 때 이상 이 없습니다. 데 이 터 는 모두 인터페이스 문서 에 따라 주기 때 문 입 니 다.그러나 때때로 온라인 에 도착 하면 데이터 형식 은 더러 운 데이터 때문에 백 엔 드 가 데 이 터 를 되 돌려 줄 때 인터페이스 형식 에 따라 주지 않 는 데이터 구 조 를 되 돌려 준다.우리 가 자주 만 나 는 것 은 {} 대상 을 정의 하고 [] 데 이 터 를 주 었 거나 반대로 숫자 형식 이 비 숫자 형식 으로 되 돌아 간 것 이다.gson 해석 타 임 스 이상 을 일 으 켰 습 니 다.
gson 해석 원리
  •   등록 정 의 된 TypeAdapter (gson 자체 정의 가 많이 되 었 습 니 다. 저 희 는 스스로 정의 할 수 있 습 니 다. (나중에 추 가 된 우선 사항 은 Gson Builder. registerTypeAdapter Factory 를 통 해 추가 (중점 방법)
  • TypeAdapter 를 TypeAdapter Factory 로 밀봉 한 후 Gson 의 factories (List) 에 넣 습 니 다
  • from JSon 방법 을 통 해 최종 적 으로 getAdapter 를 호출 하여 factories 를 옮 겨 다 니 며 from JSon 의 두 번 째 매개 변수 type 과 대응 하 는 TypeAdapter Factory 를 얻 고 이 Factory 의 create 방법 으로 TypeAdapter 를 만 듭 니 다. 
  • TypeAdapter 의 read 방법 을 호출 하여 json 에서 관련 유형 으로 전환 합 니 다. (주로 이 방법 을 바 꿉 니 다)
  •  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

    좋은 웹페이지 즐겨찾기