Reputation: 542
If I have a simple object as follows:
String name;
String email;
int age;
boolean isDeveloper;
Then let's say JSON object received have values:
{"name":null,"email":null,"age":26,"isDeveloper":true}
When deserializing this JSON using GSON as default I have:
{"age":26,"isDeveloper":true}
But email field missing will cause a failure afterwards on my application so I want to add
email = null;
Serialize back to JSON and have only this field value as null. Also not ignoring any non null fields.
Other null values should not be added to the resulting JSON.
I tried deserializing with a default GSON builder then serializing with a GSON that allows null values as:
Gson gson = new GsonBuilder().serializeNulls().create();
Problem is: this will look all null/empty values from the object class and set them all
{"name":null,"email":null,"age":26,"isDeveloper":true}
How can I set email property null then serialize back to a JSON containing only this field as null without ignoring any other non null values?
I'm using gson v2.2.4
Here is example code:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
public class App
{
private class UserSimple {
public String name;
public String email;
public int age;
public boolean isDeveloper;
UserSimple(String name, String email, int age, boolean isDeveloper) {
this.name = name;
this.email = email;
this.age = age;
this.isDeveloper = isDeveloper;
}
}
public static void main( String[] args )
{
String userJson = "{'age':26,'email':'[email protected]','isDeveloper':true,'name':null}";
Gson gson = new GsonBuilder()
.setPrettyPrinting()
.disableHtmlEscaping()
.create();
Gson gsonBuilder = new GsonBuilder().serializeNulls().create();
UserSimple deserializedObj = gson.fromJson(userJson, UserSimple.class);
System.out.println("\n"+gson.toJson(deserializedObj));
deserializedObj.email = null;
String serializedObj = gsonBuilder.toJson(deserializedObj, UserSimple.class);
System.out.println("\n"+serializedObj);
}
}
Upvotes: 4
Views: 2539
Reputation: 111
You could create your own custom adapter to resolve the issue at hand :
class MyCustomTypeAdapter extends TypeAdapter<UserSimple> {
@Override
public void write(JsonWriter writer, UserSimple userSimple) throws IOException {
writer.beginObject();
if(userSimple.getName() != null){
writer.name("name");
writer.value(userSimple.getName());
}
// you want to include email even if it's null
writer.name("email");
writer.value(userSimple.getEmail());
if(userSimple.getAge() != null){
writer.name("age");
writer.value(userSimple.getAge());
}
if(userSimple.getDeveloper() != null){
writer.name("isDeveloper");
writer.value(userSimple.getDeveloper());
}
writer.endObject();
}
public UserSimple read(JsonReader reader) throws IOException {
// you could create your own
return null;
}
}
Input :
String userJson = "{'age':null,'email':null,'isDeveloper':true,'name':'somename'}";
Output :
serializedObj :{"name":"somename","email":null,"isDeveloper":true}
Input :
String userJson = "{'age':20,'email':null,'isDeveloper':true,'name':'somename'}";
Output :
serializedObj :{"name":"somename","email":null,"age":20,"isDeveloper":true}
Have a look at https://google.github.io/gson/apidocs/com/google/gson/TypeAdapter.html
Upvotes: 4
Reputation: 2531
Have you considered using jackson? I think it's more powerful and faster than Gson. But that's just my opinion, I don't mean to offend anyone. I've also run into situations where jackson could do something that gson couldn't.
Here's the code that does the job for you:
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectWriter;
public class Main {
static class Person {
@JsonInclude(JsonInclude.Include.ALWAYS)
private String name;
@JsonInclude(JsonInclude.Include.NON_NULL)
private String email;
@JsonInclude(JsonInclude.Include.NON_NULL)
private Integer age;
public Person(String name, String email, Integer age) {
this.name = name;
this.email = email;
this.age = age;
}
public String getName() {
return name;
}
public String getEmail() {
return email;
}
public Integer getAge() {
return age;
}
}
public static void main(String[] args) throws Exception {
ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter(); // pretty printing only enabled for demonstration purposes
String test = ow.writeValueAsString(new Person(null, null, 2));
System.out.println(test);
}
}
output is:
{
"name" : null,
"age" : 2
}
name
is also output because the inclusion policy for it is JsonInclude.Include.ALWAYS
.
In maven dependencies include:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.9.6</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.6</version>
</dependency>
There's also this answer: Gson serialize null for specific class or field but it looks like it's not very good.
Upvotes: 1