Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gson serialize null for specific class or field

Tags:

java

json

gson

I want to serialize nulls for a specific field or class.

In GSON, the option serializeNulls() applies to the whole JSON.

Example:

class MainClass {     public String id;     public String name;     public Test test; }  class Test {     public String name;     public String value;     }   MainClass mainClass = new MainClass(); mainClass.id = "101" // mainClass has no name. Test test = new Test(); test.name = "testName"; test.value = null; mainClass.test = test;     

Creating JSON using GSON:

GsonBuilder builder = new GsonBuilder().serializeNulls(); Gson gson = builder.create(); System.out.println(gson.toJson(mainClass)); 

Current ouput:

{     "id": "101",     "name": null,     "test": {         "name": "testName",         "value": null     } } 

Desired output:

{     "id": "101",     "test": {         "name": "testName",         "value": null     } } 

How to achieve the desired output?

Preferred solution would have the following properties:

  • Do NOT serialize nulls by default,
  • Serialize nulls for fields with a specific annotation.
like image 973
Martin Avatar asked Feb 18 '16 09:02

Martin


People also ask

How do I put null values in Gson?

We can force Gson to serialize null values via the GsonBuilder class. We need to call the serializeNulls() method on the GsonBuilder instance before creating the Gson object. Once serializeNulls() has been called the Gson instance created by the GsonBuilder can include null fields in the serialized JSON.

Does Gson ignore unknown fields?

As you can see, Gson will ignore the unknown fields and simply match the fields that it's able to.

Does Gson serialize static fields?

Nested Classes (including Inner Classes)Gson can serialize static nested classes quite easily.


1 Answers

I have a solution similar to the one of Aleksey but that can be applied to one or more fields in any class (example in Kotlin):

Create a new annotation for fields that should be serialized as null:

@Retention(AnnotationRetention.RUNTIME) @Target(AnnotationTarget.FIELD) annotation class SerializeNull 

Create a TypeAdapterFactory that checks if a class has fields annotated with this annotation and removes the fields that are null and not annotated with the annotation from the JsonTree when writing the object:

class SerializableAsNullConverter : TypeAdapterFactory {      override fun <T : Any?> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {         fun Field.serializedName() = declaredAnnotations             .filterIsInstance<SerializedName>()             .firstOrNull()?.value ?: name         val declaredFields = type.rawType.declaredFields         val nullableFieldNames = declaredFields             .filter { it.declaredAnnotations.filterIsInstance<SerializeNull>().isNotEmpty() }             .map { it.serializedName() }         val nonNullableFields = declaredFields.map { it.serializedName() } - nullableFieldNames          return if (nullableFieldNames.isEmpty()) {             null         } else object : TypeAdapter<T>() {             private val delegateAdapter = gson.getDelegateAdapter(this@SerializableAsNullConverter, type)             private val elementAdapter = gson.getAdapter(JsonElement::class.java)              override fun write(writer: JsonWriter, value: T?) {                 val jsonObject = delegateAdapter.toJsonTree(value).asJsonObject                 nonNullableFields                     .filter { jsonObject.get(it) is JsonNull }                     .forEach { jsonObject.remove(it) }                 val originalSerializeNulls = writer.serializeNulls                 writer.serializeNulls = true                 elementAdapter.write(writer, jsonObject)                 writer.serializeNulls = originalSerializeNulls             }              override fun read(reader: JsonReader): T {                 return delegateAdapter.read(reader)             }         }     } } 

Register the adapter with your Gson instance:

val builder = GsonBuilder().registerTypeAdapterFactory(SerializableAsNullConverter()) 

And annotate the fields you would like to be nullable:

class MyClass(val id: String?, @SerializeNull val name: String?) 

Serialization result:

val myClass = MyClass(null, null) val gson = builder.create() val json = gson.toJson(myClass) 

json:

{     "name": null } 
like image 89
Joris Avatar answered Sep 21 '22 19:09

Joris