Creating Custom (De)serializers
Suppose you have an object that's not straightforward like a POJO, and you want to serialize it in a special way.
In this example, Class A may contain information about either an array or an instance of Class B. We only want to serialize one of them at a time. The other will always be null.
Attempting to serialize this as a POJO would result in a larger structure containing a null value, a filled value representing the correct structure, and the boolean that tells us which structure to pick.
But we obviously only want it to only result in the correct structure.
Attempting to deserialize either type would result in an error in both cases, because the structure of Class A matches neither an array nor Class B.
To get the correct results, we have to implement a custom deserializer:
import blue.endless.jankson.Jankson;
import blue.endless.jankson.annotation.Deserializer;
import blue.endless.jankson.annotation.Serializer;
import blue.endless.jankson.api.SyntaxError;
public class ClassA {
private static final Jankson JANKSON = Jankson.builder().build();
// Variables described above
// Use the Serializer annotation to create a serializer
@Serializer
public JsonElement toJson() {
// The boolean isClassB is a stand-in for your logic that decides what type to parse
// You might use an enum if you have more than two types of data
if (isClassB && classB != null) return JANKSON.toJson(classB);
// If we can't do that, it might be the other type.
else if (!isClassB && arr != null) return JANKSON.toJson(arr);
// This object is invalid. Return an empty JSON object.
else return JANKSON.toJson(new Object());
}
// Use the Deserializer annotation to create a deserializer
@Deserializer
// Take a JsonArray as an argument when you want to parse an array
public static ClassA fromArray(JsonArray array) throws SyntaxError {
var value = new ClassA();
// Convert from a JsonArray to an int array
value.arr = JANKSON.fromJson(array.toJson(), int[].class);
// Set the boolean so we can re-serialize the data later
value.isClassB = false;
return value;
}
@Deserializer
// Take a JsonObject when you want to parse a POJO
public static ClassA fromObject(JsonObject object) throws SyntaxError {
var value = new ClassA();
// Convert from an object to your POJO instance
value.classB = JANKSON.fromJson(object.toJson(), ClassB.class);
// Set the boolean so we can re-serialize the data later
value.isClassB = true;
return value;
}
}
import blue.endless.jankson.Jankson
import blue.endless.jankson.annotation.Deserializer
import blue.endless.jankson.annotation.Serializer
import blue.endless.jankson.api.SyntaxError as JanksonSyntaxError
class ClassA {
// Variables described above
// Use the Serializer annotation to create a serializer
@Serializer
fun toJson(): JsonElement {
// The boolean isClassB is a stand-in for your logic that decides what type to parse
// You might use an enum if you have more than two types of data
return if (isClassB && classB != null) JANKSON.toJson(classB)
// If we can't do that, it might be the other type.
else if (!isClassB && arr != null) JANKSON.toJson(arr)
// This object is invalid. Return an empty JSON object.
else JANKSON.toJson(Any())
}
companion object {
private val JANKSON: Jankson = Jankson.builder().build()
// Use the Deserializer annotation to create a deserializer
@Deserializer // Take a JsonArray as an argument when you want to parse an array
@Throws(JanksonSyntaxError::class)
fun fromArray(array: JsonArray): ClassA {
val value = ClassA()
// Convert from a JsonArray to an int array
value.arr = JANKSON.fromJson(array.toJson(), IntArray::class.java)
// Set the boolean so we can re-serialize the data later
value.isClassB = false
return value
}
@Deserializer // Take a JsonObject when you want to parse a POJO
@Throws(JanksonSyntaxError::class)
fun fromObject(`object`: JsonObject): ClassA {
val value = ClassA()
// Convert from an object to your POJO instance
value.classB = JANKSON.fromJson(`object`.toJson(), ClassB::class.java)
// Set the boolean so we can re-serialize the data later
value.isClassB = true
return value
}
}
}
import blue.endless.jankson.Jankson
import blue.endless.jankson.annotation.Deserializer
import blue.endless.jankson.annotation.Serializer
import blue.endless.jankson.api.SyntaxError
class ClassA {
def JANKSON = Jankson.builder().build()
// Variables described above
// Use the Serializer annotation to create a serializer
@Serializer
JsonElement toJson() {
// The boolean isClassB is a stand-in for your logic that decides what type to parse
// You might use an enum if you have more than two types of data
if (isClassB && classB != null) return JANKSON.toJson(classB)
// If we can't do that, it might be the other type.
else if (!isClassB && arr != null) return JANKSON.toJson(arr)
// This object is invalid. Return an empty JSON object.
else return JANKSON.toJson(new Object())
}
// Use the Deserializer annotation to create a deserializer
@Deserializer
// Take a JsonArray as an argument when you want to parse an array
static ClassA fromArray(JsonArray array) throws SyntaxError {
def value = new ClassA()
// Convert from a JsonArray to an int array
value.arr = JANKSON.fromJson(array.toJson(), int[].class)
// Set the boolean so we can re-serialize the data later
value.isClassB = false
return value
}
@Deserializer
// Take a JsonObject when you want to parse a POJO
static ClassA fromObject(JsonObject object) throws SyntaxError {
def value = new ClassA()
// Convert from an object to your POJO instance
value.classB = JANKSON.fromJson(object.toJson(), ClassB.class)
// Set the boolean so we can re-serialize the data later
value.isClassB = true
return value
}
}