GSON 'nested' 个反序列化器

GSON 'nested' deserializers

我对以下 json 样本的 'nested' gson 反序列化器有问题。我卡了好几天了。

这里我为 deptcontactrole 使用了 3 个反序列化器。 deptrole 处于同一层级。 contactdept 里面。 问题是我无法提取内部 contact.

的内容
{
  "depts": {
    "dept": [
      {
        "name": "IT1",
        "contacts": {
          "contact": [
            {
              "name": "CCC11"
            },
            {
              "name": "CCC12"
            }
          ]
        }
      },
      {
        "name": "IT2",
        "contacts": {
          "contact": [
            {
              "name": "CCC21"
            }
          ]
        }
      }
    ]
  },
  "roles": {
    "role": [
      {
        "name": "ADMIN"
      },
      {
        "name": "MANAGER"
      }
    ]
  }
}
public class D_result {
  public D_depts depts;
  public D_roles roles;
}
public class D_depts {

  // fixme: choose either (A) or (B)

  // region - (A) not using deserializer
//
//  public D_dept[] dept;
//
  // endregion - (A) not using deserializer

  // region - (B) using deserializer

  private static final String TAG_dept = "dept";
  public D_dept mD_dept;
  public D_dept[] mD_deptList;

  public void setD_dept(D_dept d_dept) {
    mD_dept = d_dept;
  }

  public void setD_deptList(D_dept[] d_deptList) {
    mD_deptList = d_deptList;
  }

  public static class D_deptsDeserializer implements JsonDeserializer<D_depts> {
    @Override
    public D_depts deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

      D_depts depts = new Gson().fromJson(json, D_depts.class);

      JsonObject jsonObject = json.getAsJsonObject();

      if (jsonObject.has(TAG_dept)) {

        JsonElement jsonElement = jsonObject.get(TAG_dept);
        if (jsonElement.isJsonArray()) {

          JsonArray array = jsonElement.getAsJsonArray();
          D_dept[] values = new Gson().fromJson(array, D_dept[].class);
          depts.setD_deptList(values);

        } else if (jsonElement.isJsonObject()) {

          JsonObject object = jsonElement.getAsJsonObject();
          D_dept value = new Gson().fromJson(object, D_dept.class);
          depts.setD_dept(value);

        } else {

        }
      }
      return depts;
    }
  }

  // endregion - (B) using deserializer

}
public class D_dept {
  public String name;
  public D_contacts contacts;
}
public class D_contacts {

  // fixme: choose either (A) or (B)

//  // region - (A) not using deserializer
//
//  public D_contact[] contact;
//
//  // endregion - (A) not using deserializer

  // region - (B) using deserializer

  private static final String TAG_contact = "contact";
  public D_contact mD_contact;
  public D_contact[] mD_contactList;

  public void setD_contact(D_contact d_contact) {
    mD_contact = d_contact;
  }

  public void setD_contactList(D_contact[] d_contactList) {
    mD_contactList = d_contactList;
  }

  public static class D_contactsDeserializer implements JsonDeserializer<D_contacts> {
    @Override
    public D_contacts deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

      D_contacts contacts = new Gson().fromJson(json, D_contacts.class);

      JsonObject jsonObject = json.getAsJsonObject();

      if (jsonObject.has(TAG_contact)) {

        JsonElement jsonElement = jsonObject.get(TAG_contact);
        if (jsonElement.isJsonArray()) {

          JsonArray array = jsonElement.getAsJsonArray();
          D_contact[] values = new Gson().fromJson(array, D_contact[].class);
          contacts.setD_contactList(values);

        } else if (jsonElement.isJsonObject()) {

          JsonObject object = jsonElement.getAsJsonObject();
          D_contact value = new Gson().fromJson(object, D_contact.class);
          contacts.setD_contact(value);

        } else {

        }
      }
      return contacts;
    }
  }

  // endregion - (B) using deserializer

}
public class D_contact {
  public String name;
}
public class D_roles {

  // fixme: choose either (A) or (B)

//  // region - (A) not using deserializer
//
//  public D_role[] role;
//
//  // endregion - (A) not using deserializer

  // region - (B) using deserializer

  private static final String TAG_role = "role";
  public D_role mD_role;
  public D_role[] mD_roleList;

  public void setD_role(D_role d_role) {
    mD_role = d_role;
  }

  public void setD_roleList(D_role[] d_roleList) {
    mD_roleList = d_roleList;
  }

  public static class D_rolesDeserializer implements JsonDeserializer<D_roles> {
    @Override
    public D_roles deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

      D_roles roles = new Gson().fromJson(json, D_roles.class);

      JsonObject jsonObject = json.getAsJsonObject();

      if (jsonObject.has(TAG_role)) {

        JsonElement jsonElement = jsonObject.get(TAG_role);
        if (jsonElement.isJsonArray()) {

          JsonArray array = jsonElement.getAsJsonArray();
          D_role[] values = new Gson().fromJson(array, D_role[].class);
          roles.setD_roleList(values);

        } else if (jsonElement.isJsonObject()) {

          JsonObject object = jsonElement.getAsJsonObject();
          D_role value = new Gson().fromJson(object, D_role.class);
          roles.setD_role(value);

        } else {

        }
      }
      return roles;
    }
  }

  // endregion - (B) using deserializer

}
public class D_role {
  public String name;
}
  private static String sJsonString = "{\"depts\":{\"dept\":[{\"name\":\"IT1\",\"contacts\":{\"contact\":[{\"name\":\"CCC11\"},{\"name\":\"CCC12\"}]}},{\"name\":\"IT2\",\"contacts\":{\"contact\":[{\"name\":\"CCC21\"}]}}]},\"roles\":{\"role\":[{\"name\":\"ADMIN\"},{\"name\":\"MANAGER\"}]}}";

  private void vTest() {

    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(D_depts.class, new D_depts.D_deptsDeserializer());
    gsonBuilder.registerTypeAdapter(D_roles.class, new D_roles.D_rolesDeserializer());
    gsonBuilder.registerTypeAdapter(D_contacts.class, new D_contacts.D_contactsDeserializer());

    Gson gson = gsonBuilder.create();

    D_result result = gson.fromJson(sJsonString, D_result.class);

//    D_dept[] dDepts = result.depts.dept;  // not using deserializer
    D_dept[] dDepts = result.depts.mD_deptList;  // using deserializer
    if (dDepts != null) {
      for (D_dept dept : dDepts) {
        Log.d(TAG, dept.name);

        D_contacts dContacts = dept.contacts;
//        if (dContacts != null && dContacts.contact != null) {  // not using deserializer
        if (dContacts != null && dContacts.mD_contactList != null) {  // using deserializer
//          for (D_contact contact : dContacts.contact) {  // not using deserializer
          for (D_contact contact : dContacts.mD_contactList) {  // using deserializer
            Log.d(TAG+"dbg", dept.name + " " + contact.name);
          }
        }
        else {
          Log.d(TAG+"dbg", "Contacts unavailable");
        }
      }
    }
//    D_role[] dRoles = result.roles.role;  // not using deserializer
    D_role[] dRoles = result.roles.mD_roleList;  // using deserializer
    if (dRoles != null) {
      for (D_role role : dRoles) {
        Log.d(TAG, role.name);
      }
    }
  }

Logcat of NG result:
--------------------
D/DBG: IT1
D/DBGdbg: Contacts unavailable
D/DBG: IT2
D/DBGdbg: Contacts unavailable
D/DBG: ADMIN
D/DBG: MANAGER

Logcat of OK result:
--------------------
D/DBG: IT1
D/DBGdbg: IT1 CCC11
D/DBGdbg: IT1 CCC12
D/DBG: IT2
D/DBGdbg: IT2 CCC21
D/DBG: ADMIN
D/DBG: MANAGER

结果:

出于分析目的,提供的源代码能够 enable/disable comment/uncomment 使用反序列化器。此处NG表示'no good',无法提取contact内容。

对于以下这些组合,我的结果是 NG:

  1. 所有 deptrolecontact 反序列化器都处于活动状态。

  2. 只有 deptcontact 反序列化器处于活动状态。

对于以下这些组合,我的结果还可以:

  1. 只有 rolecontact 反序列化器处于活动状态,禁用 dept 反序列化器。

  2. 只有 roledept 反序列化器处于活动状态,contact 反序列化器已禁用。

结果分析:

5.1。 contact 解串器在启用 dept 解串器时出现错误。参见 (1),(2)。

5.2。当 dept 反序列化器被禁用时,contact 反序列化器正常。见(3).

5.3。同一层次结构级别的多个反序列化器是可以的。见(4).

问题:

6.1。为什么 contact 内容在启用 dept 解串器时不可用?

6.2。需要进行哪些修改才能使所有 3 个反序列化器正常工作?

谢谢。

解决方案:

非常感谢 Gurgen Gevondov 提供的解决方案。 问题是内部反序列化器 contact 的错误放置。 搜索 fixme 以获取更新的代码。 添加了额外的测试用例。现在能够解析 deptcontact 它们是 JsonArray 还是 JsonObject。

public class D_depts {

  // fixme: choose either (A) or (B)

  // region - (A) not using deserializer
//
//  public D_dept[] dept;
//
  // endregion - (A) not using deserializer

  // region - (B) using deserializer

  private static final String TAG_dept = "dept";
  public D_dept mD_dept;
  public D_dept[] mD_deptList;

  public void setD_dept(D_dept d_dept) {
    mD_dept = d_dept;
  }

  public void setD_deptList(D_dept[] d_deptList) {
    mD_deptList = d_deptList;
  }

  public static class D_deptsDeserializer implements JsonDeserializer<D_depts> {
    @Override
    public D_depts deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

      D_depts depts = new Gson().fromJson(json, D_depts.class);

      //fixme-add
      Gson gson = new GsonBuilder()
          .registerTypeAdapter(D_contacts.class, new D_contacts.D_contactsDeserializer())
          .create();

      JsonObject jsonObject = json.getAsJsonObject();

      if (jsonObject.has(TAG_dept)) {

        JsonElement jsonElement = jsonObject.get(TAG_dept);
        if (jsonElement.isJsonArray()) {

          JsonArray array = jsonElement.getAsJsonArray();
//          D_dept[] values = new Gson().fromJson(array, D_dept[].class);  //fixme:del
          D_dept[] values = gson.fromJson(array, D_dept[].class);  //fixme:add
          depts.setD_deptList(values);

        } else if (jsonElement.isJsonObject()) {

          JsonObject object = jsonElement.getAsJsonObject();
//          D_dept value = new Gson().fromJson(object, D_dept.class);  //fixme:del
          D_dept value = gson.fromJson(object, D_dept.class);  //fixme:add
          depts.setD_dept(value);

        } else {

        }
      }
      return depts;
    }
  }

  // endregion - (B) using deserializer

}

  private static String sJsonString1 = "{\"depts\":{\"dept\":[{\"name\":\"IT1\",\"contacts\":{\"contact\":[{\"name\":\"CCC11\"},{\"name\":\"CCC12\"}]}},{\"name\":\"IT2\",\"contacts\":{\"contact\":[{\"name\":\"CCC21\"}]}}]},\"roles\":{\"role\":[{\"name\":\"ADMIN\"},{\"name\":\"MANAGER\"}]}}";
  private static String sJsonString2 = "{\"depts\":{\"dept\":[{\"name\":\"IT1\",\"contacts\":{\"contact\":[{\"name\":\"CCC11\"},{\"name\":\"CCC12\"}]}},{\"name\":\"IT2\",\"contacts\":{\"contact\":{\"name\":\"CCC21_obj\"}}}]},\"roles\":{\"role\":[{\"name\":\"ADMIN\"},{\"name\":\"MANAGER\"}]}}";
  private static String sJsonString3 = "{\"depts\":{\"dept\":{\"name\":\"IT3_obj\",\"contacts\":{\"contact\":[{\"name\":\"CCC31\"},{\"name\":\"CCC32\"}]}}},\"roles\":{\"role\":[{\"name\":\"ADMIN\"},{\"name\":\"MANAGER\"}]}}";
  private static String sJsonString4 = "{\"depts\":{\"dept\":{\"name\":\"IT4_obj\",\"contacts\":{\"contact\":{\"name\":\"CCC41_obj\"}}}},\"roles\":{\"role\":[{\"name\":\"ADMIN\"},{\"name\":\"MANAGER\"}]}}";

  private static final String[] sJsonStrings = new String[] {
      sJsonString1   // dept as array, contact as array
      ,sJsonString2  // dept as array, contact as object
      ,sJsonString3  // dept as object, contact as array
      ,sJsonString4  // dept as object, contact as object
  };

  private void vTests() {
    for (String s : sJsonStrings) {
      Log.d(TAG, "--------------------");
      vTest(s);
    }
    Log.d(TAG, "--------------------");
  }

  private void vTest(String jsonString) {

    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(D_depts.class, new D_depts.D_deptsDeserializer());
    gsonBuilder.registerTypeAdapter(D_roles.class, new D_roles.D_rolesDeserializer());
//    gsonBuilder.registerTypeAdapter(D_contacts.class, new D_contacts.D_contactsDeserializer());  //fixme:del

    Gson gson = gsonBuilder.create();

    D_result result = gson.fromJson(jsonString, D_result.class);

    if (result.depts.mD_deptList != null) {
      for (D_dept dept : result.depts.mD_deptList) {
        Log.d(TAG, dept.name);
        vShowContacts(dept.contacts, dept);
      }
    } else if (result.depts.mD_dept != null) {
      D_dept dept = result.depts.mD_dept;
      Log.d(TAG, dept.name);
      vShowContacts(dept.contacts, dept);
    }

    D_role[] dRoles = result.roles.mD_roleList;
    if (dRoles != null) {
      for (D_role role : dRoles) {
        Log.d(TAG, role.name);
      }
    }
  }

  private void vShowContacts(D_contacts contacts, D_dept dept) {
    if (contacts.mD_contactList != null) {
      for (D_contact contact : contacts.mD_contactList) {
        Log.d(TAG+"dbgL", dept.name + " " + contact.name);
      }
    } else if (contacts.mD_contact != null) {
      D_contact contact = contacts.mD_contact;
      Log.d(TAG+"dbg1", dept.name + " " + contact.name);
    }
  }

问题是您每次都在创建新的 Gson 对象来解析 D_dept 数组,键 dept in D_depts.D_deptsDeserializer class 和这个新的创建的 Gson 对象对 D_contacts.D_contactsDeserializer 一无所知。要解决此问题,您需要删除

gsonBuilder.registerTypeAdapter(D_contacts.class, new D_contacts.D_contactsDeserializer());

从您的 vTest 方法开始并创建 Gson 对象以使用此代码解析 D_dept

private Gson gson = new GsonBuilder()
        .registerTypeAdapter(D_contacts.class, new D_contacts.D_contactsDeserializer())
        .create();

并更改此行(在 D_depts.D_deptsDeserializer#deserialize 方法中)

D_dept[] values = new Gson().fromJson(array, D_dept[].class);

D_dept[] values = gson.fromJson(array, D_dept[].class);