GSON «вложенные» десериализаторы - PullRequest
0 голосов
/ 17 марта 2020

У меня проблемы с «вложенными» десериализаторами gson для следующего json образца. Я застрял на несколько дней.

Здесь я использую 3 десериализатора для dept, contact, role. dept и role находятся на одном уровне иерархии. contact находится внутри dept. Проблема в том, что я не могу извлечь содержимое внутреннего 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

Результаты:

Для целей анализа предоставленный исходный код имеет возможность включать / отключать использование десериализаторов с помощью комментариев / комментариев. Здесь NG означает «ничего хорошего», я не могу извлечь contact содержимое.

Для этих комбинаций ниже мои результаты: NG:

  1. Все dept , role, contact десериализаторы активны.

  2. Активны только dept, contact десериализаторы.

Для этих комбинации ниже, мои результаты в порядке:

Только десериализаторы role, contact активны, десериализатор dept отключен.

Только десериализаторы role, dept активны, с contact десериализатор отключен.

Анализ результатов:

5.1. Десериализатор contact равен NG, если десериализатор dept включен. См. (1), (2).

5.2. Десериализатор contact работает, когда десериализатор dept отключен. См. (3).

5.3. Несколько десериализаторов на одном уровне иерархии в порядке. См. (4).

Вопросы:

6.1. Почему содержимое contact недоступно, если включен десериализатор dept?

6.2. Какие модификации необходимы для работы всех трех десериализаторов?

Спасибо.

Решение:

Большое спасибо Гургену Гевондову за решение. Проблема заключается в неправильном размещении внутреннего десериализатора contact. Найдите fixme обновленный код. Добавили дополнительные тестовые случаи. Теперь можно анализировать dept, contact, являются ли они 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);
    }
  }

1 Ответ

1 голос
/ 17 марта 2020

Проблема в том, что вы каждый раз создаете новый объект Gson для анализа массива D_dept с ключом dept в классе D_depts.D_deptsDeserializer, и этот новый созданный объект 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...