从Android中使用GSON Retrofit排除动态嵌套JSON中的空值

huangapple go评论85阅读模式
英文:

Exclude null values from dynamic nested json using GSON Retrofit in Android

问题

I'm parsing dynamic nested JSON using Gson and Retrofit in Android. I want to exclude null/empty values before adding them to the list.

I've tried the following methods but none of them seem to work:

// retMap.values().removeIf(Objects::isNull);
// Collection<POJOContent> values = retMap.values();
// while (values.remove(null)) {}

// list.removeAll(Arrays.asList(""));

CustomDeserializer.java:

public class CustomDeserializer implements JsonDeserializer<MyContentWrapper> {
    private final String abc_key = "abc";

    @Override
    public MyContentWrapper deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {

        MyContentWrapper abc = new MyContentWrapper();
        JsonObject object = json.getAsJsonObject().getAsJsonObject(abc_key);
        List<POJOContent> list = new ArrayList<POJOContent>();
        System.out.println("New Data: " + object);

        for (Map.Entry<String, JsonElement> set : object.entrySet()) {
            System.out.println("LIST " + set);

            JsonObject nextObject = object.getAsJsonObject().getAsJsonObject(set.getKey());

            Map<String, POJOContent> retMap = new Gson().fromJson(nextObject, new TypeToken<LinkedHashMap<String, POJOContent>>() {}.getType());

            // retMap.values().removeIf(Objects::isNull);
            // Collection<POJOContent> values = retMap.values();
            // while (values.remove(null)) {}

            list.addAll(retMap.values());
            // list.removeAll(Arrays.asList(""));
        }
        abc.abc = list;
        return abc;
    }
}

POJOContent.java:

public class POJOContent {

    @SerializedName("ab")
    public String content;

    @SerializedName("id")
    public String id;

    @SerializedName("key")
    public String key;

    @Override
    public String toString() {
        return content;
    }

    // getters and setters
}

MyContentWrapper.java:

public class MyContentWrapper {
    public List<POJOContent> abc;
}

JSON:

{
    "abc": {
        "1": {
            "1": {
                "ab": "some content",
                "id": "240",
                "key": "value"
            },
            "2": {
                "ab": "some content",
                "id": "240",
                "key": "value"
            },
            "3": {
                "ab": "some content",
                "id": "240",
                "key": "value"
            }
        },
        "2": {
            "1": {
                "ab": "",
                "id": "241",
                "key": "value"
            },
            "2": {
                "ab": "",
                "id": "241",
                "key": "value"
            },
            "3": {
                "ab": "",
                "id": "241",
                "key": "value"
            }
        }
    }
}

Basically, you want to skip objects whose "ab" value is empty and not add them to the list. If the parent object has any child object with an empty "ab" value, the child object should be excluded. If the parent object has all children with empty "ab" values, it should exclude the parent object.

Am I missing something? Would appreciate some help.

EDIT: Expected JSON:

{
    "abc": {
        "1": {
            "1": {
                "ab": "some content",
                "id": "240",
                "key": "value"
            },
            "2": {
                "ab": "some content",
                "id": "240",
                "key": "value"
            },
            "3": {
                "ab": "some content",
                "id": "240",
                "key": "value"
            }
        },
        "2": {
            "1": {
                "ab": "",
                "id": "241",
                "key": "value"
            },
            "2": {
                "ab": "",
                "id": "241",
                "key": "value"
            },
            "3": {
                "ab": "",
                "id": "241",
                "key": "value"
            }
        },
        "3": {
            "2": {
                "ab": "some content",
                "id": "252",
                "key": "value"
            }
        }
    }
}

UPDATE 2:

You mentioned that you are still getting empty brackets when logging the values in the callback response. It appears that the empty brackets represent empty objects in the JSON response. You may need to modify your deserialization logic to exclude these empty objects from the final list.

英文:

I'm parsing dynamic nested json using gson and Retrofit in Android. I want to exclude null/empty values before I add it to the list.

I've tried the following methods but none of them seem to work:

 // retMap.values().removeIf(Objects::isNull);
 //  Collection&lt;POJOContent&gt; values = retMap.values();
//  while (values.remove(null)) {}

//list.removeAll(Arrays.asList(&quot;&quot;));

CustomDeserialiser.java

public class CustomDeserializer implements JsonDeserializer&lt;MyContentWrapper&gt; {
    private final String abc_key = &quot;abc&quot;;

    @Override
    public MyContentWrapper deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {


        MyContentWrapper abc = new MyContentWrapper();
        JsonObject object = json.getAsJsonObject().getAsJsonObject(abc_key);
        List&lt;POJOContent&gt; list = new ArrayList&lt;POJOContent&gt;();
        System.out.println(&quot;New Data: &quot;+object);

        for (Map.Entry&lt;String, JsonElement&gt; set : object.entrySet()) {
            System.out.println(&quot;LIST &quot; + set);

            JsonObject nextObject = object.getAsJsonObject().getAsJsonObject(set.getKey());


           Map&lt;String, POJOContent&gt; retMap = new Gson().fromJson(nextObject, new TypeToken&lt;LinkedHashMap&lt;String, POJOContent&gt;&gt;() {
            }.getType());

            // retMap.values().removeIf(Objects::isNull);
	          //  Collection&lt;POJOContent&gt; values = retMap.values();
	          //  while (values.remove(null)) {}

						 list.addAll(retMap.values());
  			  	//list.removeAll(Arrays.asList(&quot;&quot;));
        
          

        }
        abc.abc = list;
        return abc;
    }

POJOContent.java

		
public class POJOContent {

    @SerializedName(&quot;ab&quot;)
    public String content;

    @SerializedName(&quot;id&quot;)
    public String id;

    @SerializedName(&quot;key&quot;)
    public String key;

    @Override
    public String toString() {
        return content;
    }

    //getters and setters

}

MyContentWrapper.java

public class MyContentWrapper {

    public List&lt;POJOContent&gt; abc;
}

JSON:

{
	&quot;abc&quot;: {
		&quot;1&quot;: {
			&quot;1&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;240&quot;,
				&quot;key&quot;: &quot;value&quot;
			},
			&quot;2&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;240&quot;,
				&quot;key&quot;: &quot;value&quot;
			},
			&quot;3&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;240&quot;,
				&quot;key&quot;: &quot;value&quot;
			}
		},
		&quot;2&quot;: {
			&quot;1&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;241&quot;,
				&quot;key&quot;: &quot;value&quot;
			},
			&quot;2&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;241&quot;,
				&quot;key&quot;: &quot;value&quot;
			},
			&quot;3&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;241&quot;,
				&quot;key&quot;: &quot;value&quot;
			}
		},
		&quot;3&quot;: {
			&quot;1&quot;: {
				&quot;ab&quot;: &quot;&quot;,
				&quot;id&quot;: &quot;252&quot;,
				&quot;key&quot;: &quot;value&quot;
			},
			&quot;2&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;252&quot;,
				&quot;key&quot;: &quot;value&quot;
			},
			&quot;3&quot;: {
				&quot;ab&quot;: &quot;&quot;,
				&quot;id&quot;: &quot;252&quot;,
				&quot;key&quot;: &quot;value&quot;
			}
		}
	}
}

Basically, I want to skip the objects whose "ab" value is empty and NOT add them to the list (the other keys are irrelevant if the "ab" value is empty). To clarify, if the parent object has any child object with "ab" key empty value, the child object should be excluded. If the parent object has all children whose "ab" key has empty values, it should exclude the parent object.

Am I missing something? Would appreciate some help.

EDIT:: Expected JSON:

{
	&quot;abc&quot;: {
		&quot;1&quot;: {
			&quot;1&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;240&quot;,
				&quot;key&quot;: &quot;value&quot;
			},
			&quot;2&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;240&quot;,
				&quot;key&quot;: &quot;value&quot;
			},
			&quot;3&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;240&quot;,
				&quot;key&quot;: &quot;value&quot;
			}
		},
		&quot;2&quot;: {
			&quot;1&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;241&quot;,
				&quot;key&quot;: &quot;value&quot;
			},
			&quot;2&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;241&quot;,
				&quot;key&quot;: &quot;value&quot;
			},
			&quot;3&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;241&quot;,
				&quot;key&quot;: &quot;value&quot;
			}
		},
		&quot;3&quot;: {
			&quot;2&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;252&quot;,
				&quot;key&quot;: &quot;value&quot;
			}
		}
	}
}

UPDATE 2:

This is the response I'm getting after changing List to Maps:

		Callback&lt;MyContentWrapper&gt; myCallback = new Callback&lt;MyContentWrapper&gt;() {
        @Override
        public void onResponse(Call&lt;MyContentWrapper&gt; call, Response&lt;MyContentWrapper&gt; response) {
            if (response.isSuccessful()) {
                Log.d(&quot;Callback&quot;, &quot; Message: &quot; + response.raw());
                Log.d(&quot;Callback&quot;, &quot; Message: &quot; + response.body().abc.values());
				still showing empty brackets here ---&gt;	
//Log.d = 	  Message: [{1=1. some content, 1=2. some content, 1=3. some content}, {}]
            } else {
                Log.d(&quot;Callback&quot;, &quot;Code: &quot; + response.code() + &quot; Message: &quot; + response.message());
            }
        }
        @Override
        public void onFailure(Call&lt;MyContentWrapper&gt; call, Throwable t) {
            t.printStackTrace();
        }
    };

Just for context, this is the JSON response to above the callback:


{
	&quot;abc&quot;: {
		&quot;1&quot;: {
			&quot;1&quot;: {
				&quot;ab&quot;: &quot;some content&quot;,
				&quot;id&quot;: &quot;240&quot;,
				&quot;key&quot;: &quot;value&quot;
			},
			&quot;2&quot;: {
        &quot;ab&quot;: &quot;some content&quot;,
        &quot;id&quot;: &quot;240&quot;,
        &quot;key&quot;: &quot;value&quot;
			},
      &quot;3&quot;: {
        &quot;ab&quot;: &quot;some content&quot;,
        &quot;id&quot;: &quot;240&quot;,
        &quot;key&quot;: &quot;value&quot;
			}
		},
		&quot;2&quot;: {
			&quot;1&quot;: {
          &quot;ab&quot;: &quot;&quot;,
          &quot;id&quot;: &quot;241&quot;,
          &quot;key&quot;: &quot;value&quot;
			},
			&quot;2&quot;: {
          &quot;ab&quot;: &quot;&quot;,
          &quot;id&quot;: &quot;241&quot;,
          &quot;key&quot;: &quot;value&quot;
			},
      &quot;3&quot;: {
          &quot;ab&quot;: &quot;&quot;,
          &quot;id&quot;: &quot;241&quot;,
          &quot;key&quot;: &quot;value&quot;
      }
		}
	}
}

答案1

得分: 1

首先,你的 MyContentWrapper 是错误的。根据你的 JSON,它不是一个 List,而应该是一个嵌套的 Map 结构,像这样:

public class MyContentWrapper {
    public Map<Integer, Map<Integer, POJOContent>> abc;
}

现在,你可以编写一个复杂的反序列化器来处理这种结构,但也有另一种方法。你可以声明一个辅助的 Map 类,如下所示:

@SuppressWarnings("serial")
public class MyMap extends HashMap<Integer, POJOContent> {
    @Override
    public POJOContent put(Integer key, POJOContent value) {
        if (null == value.getContent() || value.getContent().isBlank()) {
            return null;
        }
        // 仅在内容不为空或不为空格时才添加。
        return super.put(key, value);
    }
}

然后修改调整后的 MyContentWrapper 如下:

public class MyContentWrapper {
    public Map<Integer, MyMap> abc;
}

这样你可以使用以下代码来进行反序列化:

MyContentWrapper mcw = new Gson().fromJson(JSON, MyContentWrapper.class);
英文:

First of all your MyContentWrapper is wrong. It is not a List according to your JSON. It should be map of maps so something like:

public class MyContentWrapper {
    public Map&lt;Integer, Map&lt;Integer, POJOContent&gt;&gt; abc;
}

Now, you could write some complex deserializer for this kind of structure but there is also an another way to do it. Namely, if you declare helper Map like:

@SuppressWarnings(&quot;serial&quot;)
public class MyMap extends HashMap&lt;Integer, POJOContent&gt; {
    @Override
    public POJOContent put(Integer key, POJOContent value) {
        if(null==value.getContent() || value.getContent().isBlank()) {
            return null;
        }
        // Added only if content = &quot;ab&quot; is not blank.
        return super.put(key, value);
    }
}

and then the tuned MyContentWrapper:

public class MyContentWrapper {
    public Map&lt;Integer, MyMap&gt; abc;
}

Then it is only:

MyContentWrapper mcw = new Gson().fromJson(JSON, MyContentWrapper.class);

huangapple
  • 本文由 发表于 2020年7月22日 04:14:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/63022383.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定