Schemas
Schemas
dictate what and how everything should be serialized.
Built-in and non-built-in types
Built-in types are: booleans, numbers and strings. Both boxed and unboxed primitives are considered built-in.
Default Types
Some types are supported out of the box. Here’s a list of them:
List<T>(viaArrayList<T>) -JavaListSchema<T>Set<T>(viaHashSet<T>) -JavaSetSchema<T>Map<K, V>(viaHashMap<K, V>, works only when the key has a string schema -JavaMapSchema<K, V>Map<String, V>(viaHashMap<String, V>) -String2ObjectMapSchema<V>T[](any array, including the primitives) -JavaArraySchema<T, E>Enum-JavaEnumSchema<T>UUID-UUIDSchema
BakedClassAutoSchema is used as a fallback for objects. Read more here.
Registering
Schemas are contained and registered in a SchemaHolder.
To regiser a schema you need to call the appropriate schema method:
import dev.drtheo.autojson.AutoJSON;
class YourClass {
void yourMethod() { AutoJSON auto = new AutoJSON(); auto.schema(YourData.class, new YourDataSchema()); }}
class YourData { }Templates
Templates allow you to register a template that will be used to dynamically create a new schema on the fly for a certain type:
import dev.drtheo.autojson.AutoJSON;import dev.drtheo.autojson.schema.base.Schema;import dev.drtheo.autojson.schema.base.ObjectSchema;
class YourClass { void yourMethod() { AutoJSON auto = new AutoJSON(); auto.template(User.class, MyUserSchema::new); }}
class User<T> { public int id; public String name;}
class MyUserSchema<T> implements ObjectSchema<T> {
private final Class<T> tClass; private final Schema<T> tSchema;
public MyUserSchema(SchemaHolder holder, ParameterizedType type) { this.tClass = type.getActualTypeArguments()[0]; this.tSchema = holder.schema(tClass); }
@Override public User<T> instantiate() { return new User<>(); }
@Override public <To> void serialize(JsonAdapter<Object, To> adapter, JsonSerializationContext.Obj ctx, User<T> user) { ctx.obj$put("id", user.id); ctx.obj$put("name", user.name); }
@Override public <To> void deserialize(JsonAdapter<Object, To> adapter, JsonDeserializationContext ctx, User<T> user, String key) { if (key.equals("id")) { user.id = ctx.decodeBuiltIn(); } else if (key.equals("name") { user.name = ctx.decodeBuiltIn(); } }}With the example above, the class User<T> will serialize properly.
Objects
ObjectSchemas allow you serialize into a JSON object of key-value pairs:
import dev.drtheo.autojson.schema.base.Schema;import dev.drtheo.autojson.schema.base.ObjectSchema;
class Phone { int[] numbers;}
class User { public int id; public String name;
public Phone phone;}
class MyUserSchema implements ObjectSchema<User> {
@Override public User instantiate() { return new User(); }
@Override public <To> void serialize(JsonAdapter<Object, To> adapter, JsonSerializationContext.Obj ctx, User user) { ctx.obj$put("id", user.id); ctx.obj$put("name", user.name); ctx.obj$put("phone", user.phone); }
@Override public <To> void deserialize(JsonAdapter<Object, To> adapter, JsonDeserializationContext ctx, User user, String key) { if (key.equals("id")) { user.id = ctx.decodeBuiltIn(); } else if (key.equals("name") { // identical to #decodeBuiltIn() user.name = ctx.decode(String.class); } else if (key.equals("phone")) { user.phone = ctx.decode(Phone.class); } }}Baked
By default, AutoJSON will make a BakedClassAutoSchema
if no schema was registered for the type.
The baked schemas are always serialized as JSON objects.
String Schema
For utility purposes there’s the AbstractMapSchema,
which is used by String2ObjectMapSchema and JavaMapSchema.
Array
ArraySchemas allow you to serialize your object as a JSON array.
import dev.drtheo.autojson.schema.base.Schema;import dev.drtheo.autojson.schema.base.ArraySchema;
class Phone { int[] numbers;}
class MyPhoneSchema implements ArraySchema.Simple<Phone> {
@Override public Phone instantiate() { return new Phone(); }
@Override public <To> void serialize(JsonAdapter<Object, To> adapter, JsonSerializationContext.Array ctx, Phone phone) { for (int i = 0; i < phone.numbers.length; i++) { ctx.array$element(phone.numbers[i]); } }
@Override public <To> void deserialize(JsonAdapter<Object, To> adapter, JsonDeserializationContext ctx, Phone phone, int i) { phone[i] = ctx.decodeBuiltIn(); }}It’s recommended to supply the elements in the #serialize method from index 0 to the last one in ascending order.
ArraySchemas can also have an intermediate type, for more information read the javadoc.
Primitive
PrimitiveSchemas allow you to serialize and deserialize objects as built-in types.
import dev.drtheo.autojson.schema.base.Schema;import dev.drtheo.autojson.schema.base.PrimitiveSchema;
class Phone { int[] numbers;
public Phone(int[] numbers) { this.numbers = numbers; }}
class MyPhoneSchema implements PrimitiveSchema<Phone> {
@Override public <To> void serialize(JsonAdapter<Object, To> adapter, JsonSerializationContext.Primitive ctx, Phone phone) { String result = "";
for (int i = 0; i < phone.numbers.length - 1; i++) { result += phone.numbers[i]; result += "-"; }
result += phone.numbers[phone.numbers.length - 1]; ctx.primitive$value(result); }
@Override public <To> Phone deserialize(JsonAdapter<Object, To> adapter, JsonDeserializationContext ctx) { String raw = ctx.decodeBuiltIn(); String[] parts = raw.split("-");
int[] numbers = new int[parts.length];
for (int i = 0; i < numbers.length; i++) { numbers[i] = Integer.parseInt(parts[i]); }
return new Phone(numbers); }}String Schema
For utility purposes there’s the StringSchema,
which is used by String2ObjectMapSchema and such.
Wrappers New
In some situations, you want to wrap a value. For example, it could be a lock. Or an object that allows you to lazily initialize the value or something else entirely.
Wrapper schemas redirect serialization to their child schema and supply the deserialized object.