27

I am trying to convert JSON to Java object. When a certain value of a pair is null, it should be set with some default value.

Here is my POJO:

public class Student {      
    String rollNo;
    String name;
    String contact;
    String school;

    public String getRollNo() {
        return rollNo;
    }
    public void setRollNo(String rollNo) {
        this.rollNo = rollNo;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getSchool() {
        return school;
    }
    public void setSchool(String school) {
        this.school = school;
    }
}

Example JSON object:

{
  "rollNo":"123", "name":"Tony", "school":null
}

So if school is null, I should make this into a default value, such as "school":"XXX". How can I configure this with Gson while deserializing the objects?

durron597
  • 31,968
  • 17
  • 99
  • 158
Arun
  • 609
  • 2
  • 12
  • 33

4 Answers4

28

If the null is in the JSON, Gson is going to override any defaults you might set in the POJO. You could go to the trouble of creating a custom deserializer, but that might be overkill in this case.

I think the easiest (and, arguably best given your use case) thing to do is the equivalent of Lazy Loading. For example:

private static final String DEFAULT_SCHOOL = "ABC Elementary";
public String getSchool() {
    if (school == null) school == DEFAULT_SCHOOL;
    return school;
}
public void setSchool(String school) {
    if (school == null) this.school = DEFAULT_SCHOOL;
    else this.school = school;
}

Note: The big problem with this solution is that in order to change the Defaults, you have to change the code. If you want the default value to be customizable, you should go with the custom deserializer as linked above.

durron597
  • 31,968
  • 17
  • 99
  • 158
  • you can have defaults as a static variables and use them in multiples places. so when you need to change any default, you just change the value of the **final static ..** – Kostanos Mar 20 '19 at 21:30
  • great, smart way – nomadSK25 Jun 07 '19 at 09:34
  • 1
    @durron Is it possible considering gson does not use setter/getter for accessing and setting field property ? – Tarun Apr 01 '20 at 09:43
9

I think that the way to do this is to either write your no-args constructor to fill in default values, or use a custom instance creator. The deserializer should then replace the default values for all attributes in the JSON object being deserialized.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
0

I was having the same issue, until I found this great solution.

For reference, you can create a post-processing class:

 interface PostProcessable {
      fun gsonPostProcess()
  }

  class PostProcessingEnabler : TypeAdapterFactory {
      fun <T> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T> {
          val delegate = gson.getDelegateAdapter(this, type)

          return object : TypeAdapter<T>() {
              @Throws(IOException::class)
              fun write(out: JsonWriter, value: T) {
                  delegate.write(out, value)
              }

              @Throws(IOException::class)
              fun read(`in`: JsonReader): T {
                  val obj = delegate.read(`in`)
                  if (obj is PostProcessable) {
                      (obj as PostProcessable).gsonPostProcess()
                  }
                  return obj
              }
          }
      }
  }

Register it like this:

GsonBuilder().registerTypeAdapterFactory(PostProcessingEnabler())

Implement it on your model:

class MyClass : Serializable, PostProcessable {
    // All your variable data
    override fun gsonPostProcess() {
        // All your post processing logic you like on your object
        // set default value for example
    }
}

And finally use it when converting json string:

var myObject = myGson.fromJson(myObjectJson, MyClass::class)

Or using retrofit2:

val api = Retrofit.Builder()
                  .baseUrl(BASE_URL)
                  .addConverterFactory(
                       GsonConverterFactory.create(
                          GsonBuilder().registerTypeAdapterFactory(
                                 GsonPostProcessingEnabler()
                          ).create()
                       )
                   )
                  .client(OkHttpClient.Builder().build())
                  .build()
                  .create(AccountApi::class.java)
hiddeneyes02
  • 2,562
  • 1
  • 31
  • 58
-4

You can simply make a universal function that checks for null

model.SchoolName= stringNullChecker(model.SchoolName);

public static String stringNullChecker(String val) {
        if (null == val) val = "";
        return val;
}
Shivam Mathur
  • 111
  • 1
  • 3