You can serialize any object using Odin. Like explained in the Odn format, there are three types of entries: value, field and row.

Each entry type contains one method per primitive and many methods to handle other Objects



As each primitive has its own method to read and write, no additional type is required to read the value .

writer.writeString("just a String");
1,5,true,"just a String"
byte b = reader.readByte();
int i = reader.readInt();
boolean bool = reader.readBoolean();
String s = reader.readString();
Unknown objects

If your object is not a primitive or if you don't know the type, there as other methods that take an Object with an optional generic type.

With the example below, there is no given type, so Odin will add the type definition to know the object type

Foo foo = reader.read();

Note that this reading process will parse the value and detect the primitive type. But byte, short and long that can be cast asint return a int. Same for double that can return a float.
If you try to read a byte using read() you will get a ClassCastException.

Generic types

You have two ways of giving the object type: using a Type, or an AnyType instance that you can get inside an adapter.

If your object class is the same as your given Type, no type definitions are added.

writer.writeTyped(foo, Foo.class);
Foo foo = reader.readTyped(Foo.class);

The Type can be a Class, but if you need to pass a generic parameter you can build the Type using TypeBuilder:

new TypeBuilder<List<Foo>>() {}.type

This way, all of the elements in the list are known as Foo and do not write any type definition.


Fields contain an additional key compared to simple values.


To write a field, you need to write the key and then to set the associated value.

writer.writeField("a value").withInt(5);
a value=5

The writeField method returns a OdinFieldWriter in order to specify the value. You have to give a value only once per writeField call. A field cannot have 0 or 2 values.

Read in two step

There are two ways of reading this field: first of all, using the old school methods which means you get the key and then read the value in the desired field

String key = reader.readKey();
if ("a value".equals(key)) {
    this.value = reader.readInt();
Read with listeners

On the other hand, you can also use the listener method: you tell Odin to read the field with a specific listener and when Odin reaches the given key, the listener is called

reader.readField("a value").listenInt((Integer i) -> this.value = i);

Using listeners, you can also add a not found action, which is a listener that is called if the field is not present in the current object

reader.readField("a value")
        .listenNotFound(() -> this.value = -1)
        .listenInt((Integer i) -> this.value = i);



Same as field, you have a method to write row. By calling writeRow(), you get a OdinRowWriter containing all of the methods in order to add an object to the new row.

As long as you call add methods from this OdinRowWriter, all of the objects are added to the same row. You need to make a new call to writeRow() in order to create a new line.

Every add methods return the current OdinRowWriter.

        .addTyped(foo1, Foo.class)
        .addTyped(foo2, Foo.class)

When reading a row, you can use hasRowNext() to know if there is any remaining value inside the current row.

while(reader.hasNext()) {
    OdinRowReader row = reader.readRow();
    Foo foo = row.takeTyped(Foo.class)
    while(row.hasRowNext()) {
        int value = row.takeInt();