【发布时间】:2020-03-17 10:31:47
【问题描述】:
以下 json 示例的“嵌套”gson 反序列化程序存在问题。我被困了好几天。
这里我为dept、contact、role 使用了 3 个反序列化器。
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:
所有
dept,role,contact解串器都处于活动状态。只有
dept,contact反序列化器处于活动状态。
对于下面这些组合,我的结果还可以:
只有
role,contact解串器处于活动状态,dept解串器被禁用。只有
role,dept解串器处于活动状态,contact解串器被禁用。
结果分析:
5.1。 contact 解串器在启用dept 解串器时为 NG。见(1),(2)。
5.2。当dept 解串器被禁用时,contact 解串器正常。见(3)。
5.3。同一层次结构级别的多个反序列化器是可以的。见(4)。
问题:
6.1。为什么dept解串器开启后contact内容不可用?
6.2。需要进行哪些修改才能使所有 3 个反序列化器正常工作?
谢谢。
解决方案:
非常感谢 Gurgen Gevondov 提供的解决方案。
问题是内部解串器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);
}
}
【问题讨论】:
-
尝试使用 Pojo.. 生成 Pojo:jsonschema2pojo.org
-
感谢您的反馈。为了简单起见,我使用了公共变量,只是为了说明我遇到的问题,这不是一个好习惯。无论如何,我尝试了 POJO 方法,它有点起作用了,但是当我尝试将
contact从数组更改为对象时出现了另一个问题。 (首先使用反序列化器的原因是因为使用的数据集具有动态属性,其中dept和contact可以是数组或对象。)将进一步检查。