关于Gson

解析列表数据时如遇到后台数据传值为 "" 解决方式

public class BookDeserializer implements JsonDeserializer<Book>{
  @Override
  public Book deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
    ...
    JsonElement jsonAuthors = jsonObject.get("authors");
    if(jsonAuthors.isJsonArray()){
      ...
      book.setAuthors(authors);
    }else{
      book.setAuthors(null);
    }
    ...
  }
}

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapter(Book.class, new BookDeserializer());
...
Gson gson = gsonBuilder.create();

TypeAdapter的工作原理分析

JsonParser final类,解析成JsonElement对象(可以解析String串、Reader输入流、JsonReader输入流)

Stream.parser(JsonReader reader){...}
TypeAdapter.JSON_ELEMENT.reader(reader){...}

// 递归调用read方法将json串封装成JsonElement对象供我们使用
public static final TypeAdapter<JsonElement> JSON_ELEMENT = new TypeAdapter<JsonElement>() {
      /****
      *该方法的主要作用就是让json串封装成你希望的对象,在这里是把json串
      */
    @Override public JsonElement read(JsonReader in) throws IOException {
   //调用peek()方法对json传进行读取和解析,并返回对应的JsonToke类型
      switch (in.peek()) {
      case STRING://如果是字符类型,封装并返回之
        return new JsonPrimitive(in.nextString());
      case NUMBER://数字类型,例如double,long,int
        String number = in.nextString();
        return new JsonPrimitive(new LazilyParsedNumber(number));
      case BOOLEAN://boolean 类型:true or false
        return new JsonPrimitive(in.nextBoolean());
      case NULL://null
        in.nextNull();
        return JsonNull.INSTANCE;
      case BEGIN_ARRAY://数组类型
         //解析此数组,并添加到array中去
        JsonArray array = new JsonArray();
        in.beginArray();
        //循环遍历数组,并调用read方法解析成JsonElement对象,添加到array中去
        while (in.hasNext()) {
          array.add(read(in));
        }
        in.endArray();
        return array;//返回之
      case BEGIN_OBJECT://如果只json对象,例如{"name":"value"}
        JsonObject object = new JsonObject();
        in.beginObject();
        //解析该json对象,并获取name 和value放入object中
        //注意value可能是JsonElement,所以要调用read(in)
        while (in.hasNext()) {
          object.add(in.nextName(), read(in));
        }
        in.endObject();
        return object;
      case END_DOCUMENT:
      case NAME:
      case END_OBJECT:
      case END_ARRAY:
      default:
        throw new IllegalArgumentException();
      }
    }
}

// TypeAdapter抽象类解析json串为指定对象
/***
*匿名内部类的完美应用
**/
 public final TypeAdapter<T> nullSafe() {
    return new TypeAdapter<T>() {
      @Override public void write(JsonWriter out, T value) throws IOException {
        if (value == null) {
          out.nullValue();
        } else {
          TypeAdapter.this.write(out, value);
        }
      }
      @Override public T read(JsonReader reader) throws IOException {
        if (reader.peek() == JsonToken.NULL) {
          reader.nextNull();
          return null;
        }
        return TypeAdapter.this.read(reader);
      }
    };
  }

Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class,
      new TypeAdapter<Foo>() {
        public Foo read(JsonReader in) throws IOException {
          // read a Foo from in and return it
       }
        public void write(JsonWriter out, Foo src) throws IOException {
          // write src as JSON to out
        }
      }.nullSafe()).create();

fromJson(String,Class)–>fromJson(String,Type) (Type包含了class的报名和类名 class package.className)–>fromJson(Reader,Type)–>fromJson(JsonReader,Type);最终调用了fromJson(Jsonreader,Type)

自定义Adapter要让Gson使用,registerTypeAdapter,注册

通过GsonBuilder注册TypeAdapter,并把TypeAdapter封装成TypeAdpterFactory对象;
将封装成的TypeAdapterFactory通过GsonBuilder的create传入Gson对象中并返回;
调用gson.fromJson方法,调用getTypeAdapter方法返回你自定义的Adapter,并调用其reader方法进行处理。

JsonDeserializer的工作方式

将JsonDesrializer封装成TypeAdapterFactory;
在Factory的create方法 返回TypeAdapter的时候,需要再次将JsonDesrializer封装成TypeAdapter;
然后在Gson的getTypeAdapter 方法,返回封装过后的TypeAdapter,并调用read方法;
JsonDesrializer在TypeAdapter起到代理的作用,在reader方法执行的时候实际上调用的是JsonDesrializer的deserializer方法;

Gson解析原理

如果是通过GsonBuilder创建的Gson对象,那么就用自定义的TyperAdapter来完成json的解析;
如果是通过new Gson()创建的Gson对象,那么就用Java反射机制来完成json的解析。

通过Gson的factories(List) 这个对象add TypeAdapterFactory的顺序来控制的!当是用第一种方式来创建Gson对象的时候,把自定一个TypeAdapter或者TypeAdapterFactory添加在factories靠前的位置,然后在getAdapter方法中遍历factories的每一个TypeAdapterFactory,如果当前循环中的TypeAdapterFactory.create 返回的TypeAdapter!=null,就返回该Adapter退出了factories的遍历.因为自定义的TypeAdapter位置在factories中靠前这样就优先与ReflectiveTypeAdapterFactory 遍历到,所以就避免了用Gson的反射机制来解析json了。

image.png

Gson的反射解析机制

Gson解析成Java对象:①注册TypeAdapter;②将TypeAdapter封装成TypeAdapterFactory,加至列表factories;③fromJson,getAdapter,factory的create方法创建TypeAdapter;④Typeadapter的read方法完成转换

对于每一个Java的基本类型或者集合类型,Gson都提供了与之相对应的TypeAdapter类型(如CHARACTER_FACTORY)

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容