Skip to main content
Restate sends data over the network for storing state, journaling actions, awakeables, etc. Therefore, Restate needs to serialize and deserialize the journal entries.

Default serialization

The SDK uses by default Jackson Databind for the Java API, and Kotlinx serialization for the Kotlin API. For example, for state keys:
// Primitive types
var myString = StateKey.of("myString", String.class);
// Generic types need TypeRef (similar to Jackson's TypeReference)
var myMap = StateKey.of("myMap", TypeTag.of(new TypeRef<Map<String, String>>() {}));
The same applies to journaling actions, awakeables, etc.

Customizing serialization

There are different entrypoints in the SDK to customize (de)serialization, depending on your needs.

Custom Jackson ObjectMapper

You can customize the Jackson’s ObjectMapper by subclassing the JacksonSerdeFactory class:
class MyJacksonSerdeFactory extends JacksonSerdeFactory {
  public MyJacksonSerdeFactory() {
    super(new ObjectMapper().configure(SerializationFeature.INDENT_OUTPUT, true));
  }
}
And annotating your services with @CustomSerdeFactory:
@CustomSerdeFactory(MyJacksonSerdeFactory.class)
@Service
class ServiceWithCustomJacksonObjectMapper {
  @Handler
  public String greet(Context context) {
    return "Hello world";
  }
}

Custom Kotlinx Serialization Json

You can customize the Kotlinx Serialization Json by subclassing the KotlinSerializationSerdeFactory class:
class MyJsonSerdeFactory : KotlinSerializationSerdeFactory(json = Json { prettyPrint = true })
And annotating your services with @CustomSerdeFactory:
@CustomSerdeFactory(MyJsonSerdeFactory::class)
@Service
class ServiceWithCustomSerdeFactory {
  @Handler suspend fun greet(ctx: Context) = "Hello world!"
}

Use custom serializer for a specific operation

If you need for a specific operation (e.g. for Context.run or Context.Awakeable) a custom (de)serializer, you can implement one using the interface Serde:
class MyPersonSerde implements Serde<Person> {
  @Override
  public Slice serialize(Person person) {
    // convert value to a byte array, then wrap in a Slice
    return Slice.wrap(person.toBytes());
  }

  @Override
  public Person deserialize(Slice slice) {
    // convert value to Person
    return Person.fromBytes(slice.toByteArray());
  }
}
And then use it, for example, in combination with ctx.run:
ctx.run(new MyPersonSerde(), () -> new Person());

Use another serialization library

If you want to use a different serialization library throughout your service, we suggest implementing SerdeFactory and annotating the service class with @CustomSerdeFactory. Refer to the Javadocs for more details.
I