国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

gson-plugin基礎源碼分析(二)

beanlam / 458人閱讀

摘要:對于如果以修改源碼的方式,也可以通過判斷當前的數據類型是否與預期的數據類型一致的方式進行。但由于每種數據類型都是一個匿名內部類,很難通過判斷預期的數據類型是啥,所以可以通過添加捕獲異常,在發生異常后,跳過解析。

一、項目地址

項目地址:github-gson-plugin

二、Gson解析核心類

1.ArrayTypeAdapter.JAVA 用于解析數組類型的數據

  public Object read(JsonReader in) throws IOException {
    if(in.peek() == JsonToken.NULL) {
      in.nextNull();
      return null;
    } else {
      List list = new ArrayList();
      in.beginArray();

      Object array;
      while(in.hasNext()) {
        array = this.componentTypeAdapter.read(in);
        list.add(array);
      }

      in.endArray();
      array = Array.newInstance(this.componentType, list.size());

      for(int i = 0; i < list.size(); ++i) {
        Array.set(array, i, list.get(i));
      }

      return array;
    }
  }

2.CollectionTypeAdapterFactory.JAVA 用于解析集合類型的數據

    @Override public Collection read(JsonReader in) throws IOException {
      if (in.peek() == JsonToken.NULL) {
        in.nextNull();
        return null;
      }

      Collection collection = constructor.construct();
      in.beginArray();
      while (in.hasNext()) {
        E instance = elementTypeAdapter.read(in);
        collection.add(instance);
      }
      in.endArray();
      return collection;
    }

3.MapTypeAdapterFactory.JAVA 用于解析map類型的數據

    @Override public Map read(JsonReader in) throws IOException {
      JsonToken peek = in.peek();
      if (peek == JsonToken.NULL) {
        in.nextNull();
        return null;
      }

      Map map = constructor.construct();

      if (peek == JsonToken.BEGIN_ARRAY) {
        in.beginArray();
        while (in.hasNext()) {
          in.beginArray(); // entry array
          K key = keyTypeAdapter.read(in);
          V value = valueTypeAdapter.read(in);
          V replaced = map.put(key, value);
          if (replaced != null) {
            throw new JsonSyntaxException("duplicate key: " + key);
          }
          in.endArray();
        }
        in.endArray();
      } else {
        in.beginObject();
        while (in.hasNext()) {
          JsonReaderInternalAccess.INSTANCE.promoteNameToValue(in);
          K key = keyTypeAdapter.read(in);
          V value = valueTypeAdapter.read(in);
          V replaced = map.put(key, value);
          if (replaced != null) {
            throw new JsonSyntaxException("duplicate key: " + key);
          }
        }
        in.endObject();
      }
      return map;
    }

4.ReflectiveTypeAdapterFactory.JAVA 用于解析Object類型

   @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();
          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;
    }

5.TypeAdapters.JAVA 用于解析基本數據類型
里邊每種基本數據類型,都對應一個匿名內部類,只列出boolean類型的解析,其它省略

  public static final TypeAdapter BOOLEAN = new TypeAdapter() {
    @Override
    public Boolean read(JsonReader in) throws IOException {
      JsonToken peek = in.peek();
      if (peek == JsonToken.NULL) {
        in.nextNull();
        return null;
      } else if (peek == JsonToken.STRING) {
        // support strings for compatibility with GSON 1.7
        return Boolean.parseBoolean(in.nextString());
      }
      return in.nextBoolean();
    }
    @Override
    public void write(JsonWriter out, Boolean value) throws IOException {
      out.value(value);
    }
  };
三、跳過異常字段

1.對于ArrayTypeAdapter.JAVA,CollectionTypeAdapterFactory.JAVA,MapTypeAdapterFactory.JAVA,ReflectiveTypeAdapterFactory.JAVA 我們很清楚的知道預期的數據類型是啥,所以可以判斷當前的數據類型是否與預期的數據類型一致,如果不一致則跳過解析。
2.對于TypeAdapters.JAVA 如果以修改源碼的方式,也可以通過判斷當前的數據類型是否與預期的數據類型一致的方式進行。但由于每種數據類型都是一個匿名內部類,很難通過javassist判斷預期的數據類型是啥,所以可以通過添加try-catch捕獲異常,在發生異常后,跳過解析。
3.判斷數據類型是否與預期的數據類型一致,如果不一致則跳過解析。

  /**
   * used for array、collection、map、object
   * skipValue when expected token error
   *
   * @param in input json reader
   * @param expectedToken expected token
   */
  public static boolean checkJsonToken(JsonReader in, JsonToken expectedToken) {
    if (in == null || expectedToken == null) {
      return false;
    }
    JsonToken inToken = null;
    try {
      inToken = in.peek();
    } catch (IOException e) {
      e.printStackTrace();
    }
    if (inToken == expectedToken) {
      return true;
    }
    if (inToken != JsonToken.NULL) {
      String exception = "expected " + expectedToken + " but was " + inToken + " path " + in.getPath();
      notifyJsonSyntaxError(exception);
    }
    skipValue(in);
    return false;
  }

1.方法入參:輸入的json為JsonReader,期望的數據類型為JsonToken
2.期望的數據類型:在調用方法的時候傳入
3.當前的數據類型:通過in.peek()獲取
4.當前字段:通過in.getPath()獲取
5.異常信息拼接:

      String exception = "expected " + expectedToken + " but was " + inToken + " path " + in.getPath();

ReaderTools.JAVA源碼

四、GsonPlugin插件編寫
/**
 * Created by tangfuling on 2018/10/25.
 */

class GsonPlugin implements Plugin {

  @Override
  void apply(Project project) {
    //add dependencies
    project.dependencies.add("compile",
        "com.ke.gson.sdk:gson_sdk:1.3.0")
    //add transform
    project.android.registerTransform(new GsonJarTransform(project))
  }
}
五、Transform侵入編譯流程
/**
 * Created by tangfuling on 2018/10/25.
 */

class GsonJarTransform extends Transform {

  private Project mProject

  GsonJarTransform(Project project) {
    mProject = project
  }

  @Override
  String getName() {
    return "GsonJarTransform"
  }

  @Override
  Set getInputTypes() {
    return TransformManager.CONTENT_CLASS
  }

  @Override
  Set getScopes() {
    return TransformManager.SCOPE_FULL_PROJECT
  }

  @Override
  boolean isIncremental() {
    return false
  }

  @Override
  void transform(TransformInvocation transformInvocation)
      throws TransformException, InterruptedException, IOException {
    //初始化ClassPool
    MyClassPool.resetClassPool(mProject, transformInvocation)

    //處理jar和file
    TransformOutputProvider outputProvider = transformInvocation.getOutputProvider()
    for (TransformInput input : transformInvocation.getInputs()) {
      for (JarInput jarInput : input.getJarInputs()) {
        // name must be unique,or throw exception "multiple dex files define"
        def jarName = jarInput.name
        if (jarName.endsWith(".jar")) {
          jarName = jarName.substring(0, jarName.length() - 4)
        }
        def md5Name = DigestUtils.md5Hex(jarInput.file.getAbsolutePath())
        //source file
        File file = InjectGsonJar.inject(jarInput.file, transformInvocation.context, mProject)
        if (file == null) {
          file = jarInput.file
        }
        //dest file
        File dest = outputProvider.getContentLocation(jarName + md5Name,
            jarInput.contentTypes, jarInput.scopes, Format.JAR)
        FileUtils.copyFile(file, dest)
      }

      for (DirectoryInput directoryInput : input.getDirectoryInputs()) {
        File dest = outputProvider.getContentLocation(directoryInput.name,
          directoryInput.contentTypes, directoryInput.scopes, Format.DIRECTORY)
        FileUtils.copyDirectory(directoryInput.file, dest)
      }
    }
  }
}
六、javassist修改Gson字節碼

修改ArrayTypeAdapter.JAVA的read()方法

/**
 * Created by tangfuling on 2018/10/30.
 */

public class InjectArrayTypeAdapter {

  public static void inject(String dirPath) {

    ClassPool classPool = MyClassPool.getClassPool()

    File dir = new File(dirPath)
    if (dir.isDirectory()) {
      dir.eachFileRecurse { File file ->
        if ("ArrayTypeAdapter.class".equals(file.name)) {
          CtClass ctClass = classPool.getCtClass("com.google.gson.internal.bind.ArrayTypeAdapter")
          CtMethod ctMethod = ctClass.getDeclaredMethod("read")
          ctMethod.insertBefore("     if (!com.ke.gson.sdk.ReaderTools.checkJsonToken($1, com.google.gson.stream.JsonToken.BEGIN_ARRAY)) {
" +
              "        return null;
" +
              "      }")
          ctClass.writeFile(dirPath)
          ctClass.detach()
          println("GsonPlugin: inject ArrayTypeAdapter success")
        }
      }
    }
  }
}
七、目錄

1.gson-plugin告別Json數據類型不一致(一)
2.gson-plugin基礎源碼分析(二)
3.gson-plugin深入源碼分析(三)
4.gson-plugin如何在JitPack發布(四)

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72238.html

相關文章

  • gson-plugin如何在JitPack發布(四)

    摘要:一項目地址項目地址二與關系普通的庫可以通過源碼的方式直接引入并使用,是一個插件,無法通過源碼的方式使用,只能編譯并發布以后,才能被正常使用。是一個代碼倉庫,我們可以將源代碼托管在這個平臺上。 一、項目地址 項目地址:github-gson-plugin 二、github與JitPack關系 1.普通的java庫可以通過源碼的方式直接引入并使用,gson-plugin是一個插件,無法通過...

    StonePanda 評論0 收藏0
  • gson-plugin告別Json數據類型不一致(一)

    摘要:六原理說明侵入編譯流程,在編譯過程中,修改庫的字節碼,修改解析相關的方法,在數據類型不一致的時候,跳過當前字段的解析。 一、目錄 1.gson-plugin告別Json數據類型不一致(一)2.gson-plugin基礎源碼分析(二)3.gson-plugin深入源碼分析(三)4.gson-plugin如何在JitPack發布(四) 看完這4篇文章,對Gson解析會有更加深刻的認識,對A...

    canopus4u 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<