This post gives basic idea of below points.
1. How to serialize map to json using Gson.
2. How to serialize null values.
3. How to implement custom serialization logic with build-in class.
4. How to implement custom serialization logic with custom class.
5. Inline custom serialization.
6. Common utility class for json related custom conversion.
Conversion of Map into JSON String:
final Map<String, String> map = new HashMap<String, String>();
map.put("Name", "KK");
map.put("Age", "27");
map.put("Sex", "Male");
map.put("Address1", "India");
map.put("Address2", null);
final String jsonString = new Gson().toJson(map);
System.out.println("JSON Serialization default behaviour:" + jsonString);
Result:
{"Name":"KK","Age":"27","Address1":"India","Sex":"Male"}
By default Gson is ignoring null values with keys. In the above output "Address2" is missing. We can serialize that using serializeNulls() method.
Below is the complete example.
final Map<String, String> map = new HashMap<String, String>();
map.put("Name", "KK");
map.put("Age", "27");
map.put("Sex", "Male");
map.put("Address1", "India");
map.put("Address2", null);
final String jsonString = new Gson().toJson(map);
final String jsonStringWithNull = new GsonBuilder().serializeNulls().create().toJson(map);
System.out.println("JSON Serialization default behaviour:" + jsonString);
System.out.println("JSON Serialization with null values:" + jsonStringWithNull);
Result:JSON Serialization default behaviour:{"Name":"KK","Age":"27","Address1":"India","Sex":"Male"}
JSON Serialization with null values:{"Name":"KK","Age":"27","Address2":null,"Address1":"India","Sex":"Male"}
While deserialise Map<String,Object> throws ClassCastException
public class StudentFormBean {
private String registerNumber;
private String name;
private int age;
/*getter/setters and constructors removed from here. get it from attachment*/
}
Serialization of Map<String,StudentFormBean> gives correct json output but the reverse gives ClassCastException.
Conversion Map of objects to json
final Map<String, StudentFormBean> map = new HashMap<String, StudentFormBean>();
map.put("Student1", new StudentFormBean("ECE2014001","Jon",24));
map.put("Student2", new StudentFormBean("ECE2014002","James",23));
map.put("Student3", new StudentFormBean("ECE2014003","Hari",24));
map.put("Student4", new StudentFormBean("ECE2014004","Sam",23));
final String json = new Gson().toJson(map);
System.out.println(json);
Output
{"Student4":{"registerNumber":"ECE2014004","name":"Sam","age":23},"Student3":{"registerNumber":"ECE2014003","name":"Hari","age":24},"Student2":{"registerNumber":"ECE2014002","name":"James","age":23},"Student1":{"registerNumber":"ECE2014001","name":"Jon","age":24}}
JSON string to Map of object (Deserialization)
When we try to convert the JSON string to map of object as below then it throws ClassCastException.
Map<String,StudentFormBean> convertedMap = new Gson().fromJson(json, map.getClass());
for(Entry<String,StudentFormBean> studentEntry : convertedMap.entrySet()){
StudentFormBean bean = studentEntry.getValue();
System.out.println(bean);
}
Output
Exception in thread "main" java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to org.jsonconversion.model.StudentFormBean
at org.jsonconversion.JsonConversion.main(JsonConversion.java:29)
In the above map.getClass() gives the reverse conversion type, but it failes to convert to the particular object. Instead of it got converted to com.google.gson.internal.LinkedTreeMap.
for(Entry<String,StudentFormBean> studentEntry : convertedMap.entrySet()){
System.out.println(studentEntry.getValue());
}
Output
{registerNumber=ECE2014004, name=Sam, age=23.0}
{registerNumber=ECE2014003, name=Hari, age=24.0}
{registerNumber=ECE2014002, name=James, age=23.0}
{registerNumber=ECE2014001, name=Jon, age=24.0}
In-order to deserialize json string to map of objects, do as below.
Type listType = new TypeToken<HashMap<String,StudentFormBean>>(){}.getType();
Code
Map<String,StudentFormBean> convertedMap = new Gson().fromJson(json, listType);
for(Entry<String,StudentFormBean> studentEntry : convertedMap.entrySet()){
StudentFormBean bean = studentEntry.getValue();
System.out.println(bean);
}
Custom Json Conversion(serialization of JavaObject to JSON String):
We can write custom serialization logic by implementing JsonSerializer interface.
Below is the sample implementation to convert Integer object to String while serialization.
public class JsonIntegerStringConversion implements JsonSerializer{ public JsonElement serialize(Integer integer, Type type, JsonSerializationContext context) { return new JsonPrimitive(String.valueOf(integer)); } }
Below is the code to use the custom serialization class while converting javaObject to json string.
final Mapmap = new HashMap (); map.put("Name", "KK"); map.put("Age", new Integer(27)); map.put("Sex", "Male"); map.put("Address1", "India"); map.put("Address2", null); final String jsonString = new GsonBuilder().serializeNulls() .registerTypeAdapter(Integer.class, new JsonIntegerStringConversion()).create() .toJson(map);
Result
{"Name":"KK","Age":"27","Address2":null,"Address1":"India","Sex":"Male"}
without custom logic the Integer object will be converted to int value(with out quotes in json string). Look at the age attribute.
System.out.println(new Gson().toJson(map));
{"Name":"KK","Age":27,"Address1":"India","Sex":"Male"}
Conversion of custom objects
Consider the below bean class and I need to serialize some of the properties using custom serialization class.
public class Address implements Serializable {
private static final long serialVersionUID = -291393950554966155L;
private String address1;
private String street;
private String state;
private String pincode;
/** Setter getters removed from here*/
}
public class StudentFormBean implements Serializable {
private static final long serialVersionUID = -4256927871832916527L;
private String registerNumber;
private String name;
private int age;
/** Setter getters removed from here*/
}
public class FormBean implements Serializable {
private static final long serialVersionUID = -5600189373922519204L;
private StudentFormBean studentFormBean;
private Address address;
/** Setter getters removed from here*/
}
Custom serialization implementation
return new JsonSerializer() {
public JsonElement serialize(FormBean bean, Type arg1, JsonSerializationContext arg2) {
JsonObject object = new JsonObject();
object.addProperty("registerNumber", bean.getStudentFormBean().getRegisterNumber());
object.addProperty("Name", bean.getStudentFormBean().getName());
object.addProperty("address", bean.getAddress().getAddress1());
return object;
}
};
In the above custom conversion will serialize registerNumber, Name, and address properties.
Result
{"registerNumber":"100","Name":"KK","address":"India"}
We have a JsonIntegerStringConversion class which has custom conversion logic when Integer object is serialized. We can avoid by creating individual class for each type(Integer,Boolean, etc) by writing one utility class.
Complete Source code
/**
* Utility class for custom json serialization.
*
* @author krishnakumar
*
*/
public class JsonConversionUtil {
/**
* Used to convert FormBean object to custom defined JSON object.
*
* @return
*/
public static JsonSerializer formBeanCustomSerializer() {
return new JsonSerializer() {
public JsonElement serialize(FormBean bean, Type arg1, JsonSerializationContext arg2) {
JsonObject object = new JsonObject();
object.addProperty("registerNumber", bean.getStudentFormBean().getRegisterNumber());
object.addProperty("Name", bean.getStudentFormBean().getName());
object.addProperty("address", bean.getAddress().getAddress1());
return object;
}
};
}
/**
* Convert integer object to String.
*
* @return
*/
public static JsonSerializer integerToStringSerializer() {
return new JsonSerializer() {
public JsonElement serialize(Integer integer, Type type,
JsonSerializationContext context) {
System.out.println("Custom Serialization Called : " + integer);
return new JsonPrimitive(String.valueOf(integer));
}
};
}
}
/**
* convert Integer object to String while serialization.
*
* @author krishnakumar
*
*/
public class JsonIntegerStringConversion implements JsonSerializer {
public JsonElement serialize(Integer integer, Type type, JsonSerializationContext context) {
return new JsonPrimitive(String.valueOf(integer));
}
}
/**
* Custom JSON converter.
*
* @author krishnakumar
*
*/
public class JSonCustomConversion {
public static void main(String[] args) {
final StudentFormBean studentBean = new StudentFormBean("100", "KK", 27);
final Address addressBean = new Address("India", "27-New Street", "TamilNadu", "638056");
final FormBean bean = new FormBean(studentBean, addressBean);
// Serialization of custom java object using default serialization.
System.out.println("Default Serialization : "
+ new GsonBuilder().serializeNulls().create().toJson(bean));
// Serialization of custom java object using default custom
// serialization logic.
System.out.println("Serialization of custom java object with custom logic :"
+ new GsonBuilder()
.serializeNulls()
.registerTypeAdapter(FormBean.class,
JsonConversionUtil.formBeanCustomSerializer()).create()
.toJson(bean));
final Map map = new HashMap();
map.put("Name", "KK");
map.put("Age", new Integer(27));
map.put("Sex", "Male");
map.put("Address1", "India");
map.put("Address2", null);
// Default conversion
System.out.println(new Gson().toJson(map));
// Custom conversion logic implemented in separate class.
final String jsonString = new GsonBuilder().serializeNulls()
.registerTypeAdapter(Integer.class, new JsonIntegerStringConversion()).create()
.toJson(map);
System.out.println("Integer to String conversion using separate class : " + jsonString);
// Utility class related to JSON conversion.
System.out.println("Integer to String conversion using common utility class :"
+ new GsonBuilder()
.registerTypeAdapter(Integer.class,
JsonConversionUtil.integerToStringSerializer()).create()
.toJson(map));
// Inline implementation.
System.out.println("Custom serialization logic using inline implementation :"
+ new GsonBuilder()
.registerTypeAdapter(Integer.class, new JsonSerializer() {
public JsonElement serialize(Integer integer, Type type,
JsonSerializationContext context) {
System.out.println("Custom Serialization Called : " + integer);
return new JsonPrimitive(String.valueOf(integer));
}
}).create().toJson(map));
}
}
Default Serialization : {"studentFormBean":{"registerNumber":"100","name":"KK","age":27},"address":{"address1":"India","street":"27-New Street","state":"TamilNadu","pincode":"638056"}}
Serialization of custom java object with custom logic :{"registerNumber":"100","Name":"KK","address":"India"}
{"Name":"KK","Age":27,"Address1":"India","Sex":"Male"}
Integer to String conversion using separate class : {"Name":"KK","Age":"27","Address2":null,"Address1":"India","Sex":"Male"}
Custom Serialization Called : 27
Integer to String conversion using common utility class :{"Name":"KK","Age":"27","Address1":"India","Sex":"Male"}
Custom Serialization Called : 27
Custom serialization logic using inline implementation :{"Name":"KK","Age":"27","Address1":"India","Sex":"Male"}
Complete source code can be downloaded from
https://github.com/krishnakumarsamy/JSONConversion.git