Skip to content

Serialization

Ralph Niemitz edited this page Dec 6, 2022 · 2 revisions

Setting up a Class for Serialization

SimpleJSON supports serialization and deserialization for JSON objects. In order to use this functionality you first have to annotate the classes you want to serialize using the JSONRoot and JSONAttribute annotations. JSONRoot is applied on class level and marks the class as a JSON object. JSONAttribute can be applied to public fields and methods. It has 3 parameters. name is a required parameter and defines the key for the attribute. type is an array which defines if the attribute can read, written or both. And genericType should be applied on maps and lists to define the generic type of the value. In case of maps the type of the key will always be interpreted as a string.

Important things to note

  • A class that was marked with JSONRoot must have a public constructor without parameters otherwise the instantiation through Reflection will fail.
  • Attributes with the transient modifier will not be serialized.
  • Attributes whose type is an interface can be serialized but not deserialized since Reflection cannot create instances of interfaces. Because of that it is recommended to instead use implementations of these interfaces. Instead of List and Map use ArrayList and HashMap
  • Character arrays can be serialized but not deserialized. This is because upon serialization the character array will become a string array
  • It is not necessary to implement the Serializable interface.
  • The parameter genericType of JSONAttribute should always be set when handling collections and maps.
  • The parameter name of JSONAttribute should always be unique.

Example with Public Fields

@JSONRoot
public class Person {

	@JSONAttribute(name = "first_name")
	public String firstName;
	
	@JSONAttribute(name = "last_name")
	public String lastName;
	
	@JSONAttribute(name = "age")
	public int age;
	
	@JSONAttribute(name = "city")
	public String city;
	
	@JSONAttribute(name = "country")
	public String country;
	
	@JSONAttribute(name = "friends", genericType = Person.class)
	public ArrayList<Person> friends;
}

Example with Getters/Setters

@JSONRoot
public class Person {

	private String firstName;
	private String lastName;
	private int age;
	private String city;
	private String country;
	private ArrayList<Person> friends;
	
	@JSONAttribute(type = JSONAttribute.Type.SETTER, name = "first_name")
	public void setFirstName(String firstName) {
		
		this.firstName = firstName;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.SETTER, name = "last_name")
	public void setLastName(String lastName) {
		
		this.lastName = lastName;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.SETTER, name = "age")
	public void setAge(int age) {
		
		this.age = age;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.SETTER, name = "city")
	public void setCity(String city) {
		
		this.city = city;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.SETTER, name = "country")
	public void setCountry(String country) {
		
		this.country = country;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.SETTER, name = "friends", genericType = Person.class)
	public void setFriends(ArrayList<Person> friends) {
		
		this.friends = friends;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.GETTER, name = "first_name")
	public String getFirstName() {
		
		return this.firstName;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.GETTER, name = "last_name")
	public String getLastName() {
		
		return this.lastName;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.GETTER, name = "age")
	public int getAge() {
		
		return this.age;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.GETTER, name = "city")
	public String getCity() {
		
		return this.city;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.GETTER, name = "country")
	public String getCountry() {
		
		return this.country;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.GETTER, name = "friends")
	// It is OK to only use List here since GETTER is only relevant for serialization
	// and will have no relevance for deserialization
	public List<Person> getFriends() {
		
		return this.friends;
	}
}

Serialization/Deserialization

A simple call of JSONSerializer#serialize or JSONSerializer#deserialize is all it takes.

Code Example for Serialization

Person person = new Person();
person.setFirstName("John");
person.setLastName("Doe");
person.setAge(21);
person.setCity("Example City");
person.setCountry("Example Country");
person.setFriends(johnDoesFriends);

try {

	JSONObject jsonDOM = JSONSerializer.serialize(person);
	System.out.println(jsonDOM);

} catch(Exception exception) {

	exception.printStackTrace();
}

Code Example for Deserialization

try {

	Person person = new Person();
	JSONSerializer.deserialize(person, jsonDOM);
	
	System.out.println(person.getFirstName());
	System.out.println(person.getLastName());
	System.out.println(person.getAge());
	System.out.println(person.getCity());
	System.out.println(person.getCountry());
	System.out.println(person.getFriends());

} catch(Exception exception) {

	exception.printSTackTrace();
}

Handling non-JSON types

A non-JSON type is every type that is not a primitive, collection or map. Normally these values are treated as strings by calling their toString method but that may not always be wanted. An example of such a case would be dates and times. In order to properly handle such cases your class has to implement JSONTypeSerializationHandler.

Code Example

In this example we will add a birth date to person.

@JSONRoot
public class Person implements JSONTypeSerializationHandler {

	private String firstName;
	private String lastName;
	private int age;
	private String city;
	private String country;
	private ArrayList<Person> friends;
	private LocalDate birthDate;
	
	@JSONAttribute(type = JSONAttribute.Type.SETTER, name = "first_name")
	public void setFirstName(String firstName) {
		
		this.firstName = firstName;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.SETTER, name = "last_name")
	public void setLastName(String lastName) {
		
		this.lastName = lastName;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.SETTER, name = "age")
	public void setAge(int age) {
		
		this.age = age;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.SETTER, name = "city")
	public void setCity(String city) {
		
		this.city = city;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.SETTER, name = "country")
	public void setCountry(String country) {
		
		this.country = country;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.SETTER, name = "friends", genericType = Person.class)
	public void setFriends(ArrayList<Person> friends) {
		
		this.friends = friends;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.SETTER, name = "birth_date")
	public void setBirthDate(LocalDate birthDate) {
		
		this.birthDate = birthDate;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.GETTER, name = "first_name")
	public String getFirstName() {
		
		return this.firstName;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.GETTER, name = "last_name")
	public String getLastName() {
		
		return this.lastName;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.GETTER, name = "age")
	public int getAge() {
		
		return this.age;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.GETTER, name = "city")
	public String getCity() {
		
		return this.city;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.GETTER, name = "country")
	public String getCountry() {
		
		return this.country;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.GETTER, name = "friends")
	// It is OK to only use List here since GETTER is only relevant for serialization
	// and will have no relevance for deserialization
	public List<Person> getFriends() {
		
		return this.friends;
	}
	
	@JSONAttribute(type = JSONAttribute.Type.GETTER, name = "birth_date")
	public LocalDate getBirthDate() {
		
		return this.birthDate;
	}
	
	@Override
	public Object serialize(Class<?> type, Object value) {
		
		if(LocalDate.class.equals(type) && value != null) {
			
			return value.toString();
		}
		
		return value;
	}

	@Override
	public Object deserialize(Class<?> type, Object value) {
		
		if(LocalDate.class.equals(type) && value != null) {
			
			return LocalDate.parse(value.toString());
		}
		
		return value;
	}
}

Clone this wiki locally