简体   繁体   English

使用 Gson 从 JSON 中删除空集合

[英]Remove empty collections from a JSON with Gson

I want to remove attributes that have empty collections or null values using gson.我想使用 gson 删除具有空集合或空值的属性。

Aiperiodo periodo = periodoService();
//periodo comes from a service method with a lot of values
Gson gson = new Gson();
String json = gson.toJson(periodo);

I print json and I have this:我打印json,我有这个:

{"idPeriodo":121,"codigo":"2014II",
"activo":false,"tipoPeriodo":1,
"fechaInicioPreMatricula":"may 1, 2014",
"fechaFinPreMatricula":"jul 1, 2014",
"fechaInicioMatricula":"jul 15, 2014",
"fechaFinMatricula":"ago 3, 2014",
"fechaInicioClase":"ago 9, 2014",
"fechaFinClase":"dic 14, 2014",
"fechaActa":"ene 15, 2015",
"fechaUltModificacion":"May 28, 2014 12:28:26 PM",
"usuarioModificacion":1,"aiAvisos":[],
"aiAlumnoCarreraConvalidacionCursos":[],
"aiAlumnoMatriculas":[],"aiMallaCurriculars":[],
"aiAlumnoCarreraEstados":[],"aiAdmisionGrupos":[],
"aiMatriculaCronogramaCabeceras":[],
"aiAlumnoCarreraConvalidacions":[],
"aiHorarioHorases":[],"aiAsistencias":[],
"aiAlumnoPreMatriculas":[],
"aiAlumnoMatriculaCursoNotaDetalles":[],
"aiOfertaAcademicas":[],"aiTarifarios":[]}

For example for that json I don't want to have the collection aiAvisos, there is a way to delete this from the json.例如,对于那个 json,我不想拥有 aiAvisos 集合,有一种方法可以从 json 中删除它。 I'm working with a lot of collections actually here I show one, I really need remove these from the json.我实际上正在处理很多集合,我在这里展示了一个,我真的需要从 json 中删除这些集合。

I need something like this:我需要这样的东西:

{"idPeriodo":121,"codigo":"2014II",
"activo":false,"tipoPeriodo":1,
"fechaInicioPreMatricula":"may 1, 2014",
"fechaFinPreMatricula":"jul 1, 2014",
"fechaInicioMatricula":"jul 15, 2014",
"fechaFinMatricula":"ago 3, 2014",
"fechaInicioClase":"ago 9, 2014",
"fechaFinClase":"dic 14, 2014",
"fechaActa":"ene 15, 2015",
"fechaUltModificacion":"May 28, 2014 12:28:26 PM",
"usuarioModificacion":1}

I tried setting the collections to null, I check the documentation and there's no method there neither...我尝试将集合设置为空,我检查了文档,但那里没有任何方法......

Please any suggestions.请任何建议。

Thanks a lot who read this!非常感谢阅读本文的人!

Steps to follow:要遵循的步骤:

  • Convert the JSON String into Map<String,Object> using Gson#fromJson()使用Gson#fromJson()将 JSON 字符串转换为Map<String,Object>
  • Iterate the map and remove the entry from the map which are null or empty ArrayList or Map .迭代地图并从地图中删除null或空的ArrayListMap条目。
  • Form the JSON String back from the final map using Gson#toJson() .使用Gson#toJson()从最终地图返回 JSON 字符串。

Note : Use GsonBuilder#setPrettyPrinting() that configures Gson to output Json that fits in a page for pretty printing.注意:使用GsonBuilder#setPrettyPrinting()配置 Gson 以输出适合页面的 Json 以进行漂亮的打印。

Sample code:示例代码:

import java.lang.reflect.Type;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
...  
 
Type type = new TypeToken<Map<String, Object>>() {}.getType();
Map<String, Object> data = new Gson().fromJson(jsonString, type);

for (Iterator<Map.Entry<String, Object>> it = data.entrySet().iterator(); it.hasNext();) {
    Map.Entry<String, Object> entry = it.next();
    if (entry.getValue() == null) {
        it.remove();
    } else if (entry.getValue().getClass().equals(ArrayList.class)) {
        if (((ArrayList<?>) entry.getValue()).size() == 0) {
            it.remove();
        }
    } else if (entry.getValue() instanceof Map){ //removes empty json objects {}
        Map<?, ?> m = (Map<?, ?>)entry.getValue();
        if(m.isEmpty()) {
           it.remove();
        }
    }
}

String json = new GsonBuilder().setPrettyPrinting().create().toJson(data);
System.out.println(json);

output;输出;

  {
    "idPeriodo": 121.0,
    "codigo": "2014II",
    "activo": false,
    "tipoPeriodo": 1.0,
    "fechaInicioPreMatricula": "may 1, 2014",
    "fechaFinPreMatricula": "jul 1, 2014",
    "fechaInicioMatricula": "jul 15, 2014",
    "fechaFinMatricula": "ago 3, 2014",
    "fechaInicioClase": "ago 9, 2014",
    "fechaFinClase": "dic 14, 2014",
    "fechaActa": "ene 15, 2015",
    "fechaUltModificacion": "May 28, 2014 12:28:26 PM",
    "usuarioModificacion": 1.0
  }

I tried a solution of @Braj in Kotlin.我在 Kotlin 中尝试了 @Braj 的解决方案。 The idea is to convert JSON to Map, remove nulls and empty arrays, then convert Map back to JSON string.这个想法是将 JSON 转换为 Map,删除空值和空数组,然后将 Map 转换回 JSON 字符串。

But it has several disadvantages.但它有几个缺点。

  1. It can only work with simple POJOs without nestings (no inner classes, lists of classes).它只能处理没有嵌套的简单 POJO(没有内部类、类列表)。
  2. It converts numbers to doubles (because Object is not recognized as int ).它将数字转换为双精度(因为Object不被识别为int )。
  3. It loses time to convert from String to String.从字符串转换为字符串会浪费时间。

Alternatively you can try to use Moshi instead of Gson , see Broken server response handling with Moshi .或者,您可以尝试使用Moshi而不是Gson ,请参阅使用Moshi 处理损坏的服务器响应

After couple of days I overcame a 1st problem for complex JSONs.几天后,我克服了复杂 JSON 的第一个问题。

import android.support.annotation.NonNull;

import com.google.gson.Gson;
import com.google.gson.internal.LinkedTreeMap;
import com.google.gson.reflect.TypeToken;

import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;


public class GsonConverter {

    private Type type;
    private Gson gson;


    public GsonConverter() {
        type = new TypeToken<Map<String, Object>>() {
        }.getType();
        gson = new Gson();
    }

    /**
     * Remove empty arrays from JSON.
     */
    public String cleanJson(String jsonString) {
        Map<String, Object> data = gson.fromJson(jsonString, type);
        if (data == null)
            return "";

        Iterator<Map.Entry<String, Object>> it = data.entrySet().iterator();
        traverse(it);

        return gson.toJson(data);
    }

    private void traverse(@NonNull Iterator<Map.Entry<String, Object>> iterator) {
        while (iterator.hasNext()) {
            Map.Entry<String, Object> entry = iterator.next();
            Object value = entry.getValue();
            if (value == null) {
                iterator.remove();
                continue;
            }

            Class<?> aClass = value.getClass();
            if (aClass.equals(ArrayList.class)) {
                if (((ArrayList) value).isEmpty()) {
                    iterator.remove();
                    continue;
                }
            }

            // Recoursively pass all tags for the next level.
            if (aClass.equals(ArrayList.class)) {
                Object firstItem = ((ArrayList) value).get(0);
                Class<?> firstItemClass = firstItem.getClass();

                // Check that we have an array of non-strings (maps).
                if (firstItemClass.equals(Map.class)) {
                    // Array of keys and values.
                    @SuppressWarnings("unchecked")
                    ArrayList<Map<String, Object>> items = (ArrayList<Map<String, Object>>) value;
                    for (Map<String, Object> item : items) {
                        traverse(item.entrySet().iterator());
                    }
                } else if (firstItemClass.equals(LinkedTreeMap.class)) {
                    // Array of complex objects.
                    @SuppressWarnings("unchecked")
                    ArrayList<LinkedTreeMap<String, Object>> items = (ArrayList<LinkedTreeMap<String, Object>>) value;
                    for (LinkedTreeMap<String, Object> item : items) {
                        traverse(item.entrySet().iterator());
                    }
                }
            } else if (aClass.equals(LinkedTreeMap.class)) {
                @SuppressWarnings("unchecked")
                LinkedTreeMap<String, Object> value2 = (LinkedTreeMap<String, Object>) value;
                traverse(value2.entrySet().iterator());
            }
        }
    }
}

Usage:用法:

YourJsonObject yourJsonObject = new Gson().fromJson(new GsonConverter().cleanJson(json), YourJsonObject.class);

For those who want to use @Braj solution, here is a code in Kotlin.对于那些想要使用 @Braj 解决方案的人,这里是 Kotlin 中的代码。

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import java.lang.reflect.Type


class GsonConverter {

    private val type: Type = object : TypeToken<Map<String, Any?>>() {}.type
    private val gson = Gson()
    private val gsonBuilder: GsonBuilder = GsonBuilder()//.setLongSerializationPolicy(LongSerializationPolicy.STRING)


    fun convert(jsonString: String): String {
        val data: Map<String, Any?> = gson.fromJson(jsonString, type)

        val obj = data.filter { it.value != null && ((it.value as? ArrayList<*>)?.size != 0) }

        val json = gsonBuilder/*.setPrettyPrinting()*/.create().toJson(obj)
        println(json)

        return json
    }
}

I have code that can process array or object with different structure and will remove "empty collections or null values" recursively.我有可以处理具有不同结构的数组或对象的代码,并将递归删除“空集合或空值”。 It works with String not with Gson directly.它与 String 一起工作,而不是直接与 Gson 一起工作。 If it's not critical, it can help you.如果它不是关键,它可以帮助你。

Your code will be:您的代码将是:

Aiperiodo periodo = periodoService();
//periodo comes from a service method with a lot of values
Gson gson = new Gson();
String json = gson.toJson(periodo);
json = removeNullAndEmptyElementsFromJson(json);

... ...

import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

import java.util.Iterator;
import java.util.Map;

public class IoJ {

public static void main(String[] args) {
    String j = "{\"query\":\"\",\"name\":null,\"result\":{\"searchResult\":[{\"id\":null,\"phone\":\"123456\",\"familyAdditionalDetails\":[],\"probability\":0.0,\"lastUpdated\":\"2019-05-18T12:03:34Z\",\"empty\":false,\"gender\":\"F\"}]},\"time\":1558181014060}";

    // {"query":"","name":null,"result":{"searchResult":[{"id":null,"phone":"123456","familyAdditionalDetails":[],"probability":0.0,"lastUpdated":"2019-05-18T12:03:34Z","empty":false,"gender":"F"}]},"time":1558181014060}
    System.out.println(j);
    // (additional spaces for easier check)
    // {"query":"",            "result":{"searchResult":[{          "phone":"123456",                             "probability":0.0,"lastUpdated":"2019-05-18T12:03:34Z","empty":false,"gender":"F"}]},"time":1558181014060}
    System.out.println(removeNullAndEmptyElementsFromJson(j));
}

public static String removeNullAndEmptyElementsFromJson(String jsonString) {
    if (jsonString == null) {
        return jsonString;
    }
    try {
        JsonParser parser = new JsonParser();
        JsonElement element = parser.parse(jsonString);
        cleanByTree(element);
        jsonString = new GsonBuilder().disableHtmlEscaping().create().toJson(element);
        return jsonString;
    } catch (Exception e) {
        return jsonString;
    }
}

private static void cleanByTree(JsonElement e1) {
    if (e1 == null || e1.isJsonNull()) {

    } else if (e1.isJsonArray()) {
        for (Iterator<JsonElement> it = e1.getAsJsonArray().iterator(); it.hasNext(); ) {
            JsonElement e2 = it.next();
            if (e2 == null || e2.isJsonNull()) {
                //it.remove();
            } else if (e2.isJsonArray()) {
                if (e2.getAsJsonArray().size() == 0) {
                    it.remove();
                } else {
                    cleanByTree(e2);
                }
            } else if (e2.isJsonObject()) {
                cleanByTree(e2);
            }
        }
    } else {
        for (Iterator<Map.Entry<String, JsonElement>> it = e1.getAsJsonObject().entrySet().iterator(); it.hasNext(); ) {
            Map.Entry<String, JsonElement> eIt = it.next();
            JsonElement e2 = eIt.getValue();
            if (e2 == null || e2.isJsonNull()) {
                //it.remove();
            } else if (e2.isJsonArray()) {
                if (e2.getAsJsonArray().size() == 0) {
                    it.remove();
                } else {
                    cleanByTree(e2);
                }
            } else if (e2.isJsonObject()) {
                cleanByTree(e2);
            }
        }
    }
}

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM