I want to remove attributes that have empty collections or null values using 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:
{"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!
You can ignore null fields at the class level by using @JsonInclude(Include. NON_NULL) to only include non-null fields, thus excluding any attribute whose value is null. You can also use the same annotation at the field level to instruct Jackson to ignore that field while converting Java object to json if it's null.
First, you should deserialize json to a Map<String, Object> . Second, loop the map entry to find out what key has null value or what key has value is instance of ArrayList but empty and remove from the Map . Last, serialize the Map to json . Type, TypeToken, GsonBuilder, Gson..
By default, the Gson object does not serialize the fields with null values to JSON. If a field in a Java object is null, Gson excludes it. We can force Gson to serialize null values via the GsonBuilder class.
Gson is the main actor class of Google Gson library. It provides functionalities to convert Java objects to matching JSON constructs and vice versa. Gson is first constructed using GsonBuilder and then toJson(Object) or fromJson(String, Class) methods are used to read/write JSON constructs.
Map<String,Object>
using Gson#fromJson()
null
or empty ArrayList
or Map
.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 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. 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.
Object
is not recognized as int
).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 complex JSONs.
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.
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
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With