英文:
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<POJOContent> values = retMap.values();
// while (values.remove(null)) {}
//list.removeAll(Arrays.asList(""));
CustomDeserialiser.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": "some content",
"id": "241",
"key": "value"
},
"2": {
"ab": "some content",
"id": "241",
"key": "value"
},
"3": {
"ab": "some content",
"id": "241",
"key": "value"
}
},
"3": {
"1": {
"ab": "",
"id": "252",
"key": "value"
},
"2": {
"ab": "some content",
"id": "252",
"key": "value"
},
"3": {
"ab": "",
"id": "252",
"key": "value"
}
}
}
}
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:
{
"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": "some content",
"id": "241",
"key": "value"
},
"2": {
"ab": "some content",
"id": "241",
"key": "value"
},
"3": {
"ab": "some content",
"id": "241",
"key": "value"
}
},
"3": {
"2": {
"ab": "some content",
"id": "252",
"key": "value"
}
}
}
}
UPDATE 2:
This is the response I'm getting after changing List to Maps:
Callback<MyContentWrapper> myCallback = new Callback<MyContentWrapper>() {
@Override
public void onResponse(Call<MyContentWrapper> call, Response<MyContentWrapper> response) {
if (response.isSuccessful()) {
Log.d("Callback", " Message: " + response.raw());
Log.d("Callback", " Message: " + response.body().abc.values());
still showing empty brackets here --->
//Log.d = Message: [{1=1. some content, 1=2. some content, 1=3. some content}, {}]
} else {
Log.d("Callback", "Code: " + response.code() + " Message: " + response.message());
}
}
@Override
public void onFailure(Call<MyContentWrapper> call, Throwable t) {
t.printStackTrace();
}
};
Just for context, this is the JSON response to above the callback:
{
"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"
}
}
}
}
答案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<Integer, Map<Integer, POJOContent>> 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("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;
}
// Added only if content = "ab" is not blank.
return super.put(key, value);
}
}
and then the tuned MyContentWrapper
:
public class MyContentWrapper {
public Map<Integer, MyMap> abc;
}
Then it is only:
MyContentWrapper mcw = new Gson().fromJson(JSON, MyContentWrapper.class);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论