最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

java - Remove empty collections from a JSON with Gson - Stack Overflow

programmeradmin4浏览0评论

I want to remove attributes that have empty collections or null values using gson.

Aiperiodo periodo = periodoService();
//periodo es 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:

{"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. I'm working with a lot of collections actually here I show one, I really need remove these from the 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!

I want to remove attributes that have empty collections or null values using gson.

Aiperiodo periodo = periodoService();
//periodo es 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:

{"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. I'm working with a lot of collections actually here I show one, I really need remove these from the 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!

Share Improve this question asked May 28, 2014 at 19:58 oshingcoshingc 3612 gold badges5 silver badges14 bronze badges 1
  • see: possible and working answer in other thread – cbit Commented May 11, 2017 at 9:12
Add a ment  | 

3 Answers 3

Reset to default 10

Steps to follow:

  • Convert the JSON String into Map<String,Object> using Gson#fromJson()
  • Iterate the map and remove the entry from the map which are null or empty ArrayList or Map.
  • Form the JSON String back from the final map using Gson#toJson().

Note : Use GsonBuilder#setPrettyPrinting() that configures Gson to output Json that fits in a page for pretty printing.

Sample code:

import java.lang.reflect.Type;
import .google.gson.Gson;
import .google.gson.GsonBuilder;
import .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. The idea is to convert JSON to Map, remove nulls and empty arrays, then convert Map back to JSON string.

But it has several disadvantages.

  1. It can only work with simple POJOs without nestings (no inner classes, lists of classes).
  2. It converts numbers to doubles (because Object is not recognized as 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.

After couple of days I overcame a 1st problem for plex JSONs.

import android.support.annotation.NonNull;

import .google.gson.Gson;
import .google.gson.internal.LinkedTreeMap;
import .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 plex 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.

import .google.gson.Gson
import .google.gson.GsonBuilder
import .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. If it's not critical, it can help you.

Your code will be:

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

...

import .google.gson.GsonBuilder;
import .google.gson.JsonElement;
import .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);
            }
        }
    }
}

}
发布评论

评论列表(0)

  1. 暂无评论