Skip to main content
2026-02-03
Java/Kotlin SDK v2.6.0

Release 2.6.0

We’re excited to announce Restate Java SDK 2.6.0!

Virtual Threads by default (Java 21+)

The default executor for Java services now uses virtual threads on Java 21+, falling back to Executors.newCachedThreadPool() for older Java versions.You can still customize the executor providing HandlerRunner.Options.withExecutor() to Endpoint#bind, or for Spring users, use the new Spring properties (restate.executor or restate.components.<name>.executor).Note: This change only applies to Java services. Kotlin services continue to Dispatchers.Default as default coroutine dispatcher.

[Spring Boot] Configure services using Spring’s Properties

You can now configure Restate services directly from Spring’s application.properties or application.yml files. This provides a centralized way to configure service behavior without modifying code.

Example Configuration

# Global executor for all services (Java only)
restate.executor=myExecutorBean

# Configuration for a service named "MyService"
restate.components.MyService.executor=myServiceExecutor
restate.components.MyService.inactivity-timeout=10m
restate.components.MyService.abort-timeout=1m
restate.components.MyService.idempotency-retention=7d
restate.components.MyService.journal-retention=1d
restate.components.MyService.ingress-private=false
restate.components.MyService.enable-lazy-state=true
restate.components.MyService.documentation=My service description
restate.components.MyService.metadata.version=1.0
restate.components.MyService.metadata.team=platform
restate.components.MyService.retry-policy.initial-interval=100ms
restate.components.MyService.retry-policy.exponentiation-factor=2.0
restate.components.MyService.retry-policy.max-interval=10s
restate.components.MyService.retry-policy.max-attempts=10
restate.components.MyService.retry-policy.on-max-attempts=PAUSE

# Per-handler configuration
restate.components.MyService.handlers.myHandler.inactivity-timeout=5m
restate.components.MyService.handlers.myHandler.ingress-private=true
restate.components.MyService.handlers.myHandler.documentation=Handler description
restate.components.MyService.handlers.myWorkflowHandler.workflow-retention=30d

Annotation based configuration

The configuration attribute on @RestateService, @RestateVirtualObject, and @RestateWorkflow annotations now accepts a bean name of type RestateComponentProperties (previously RestateServiceConfigurator):
@RestateService(configuration = "myServiceConfig")
public class MyService {
    // ...
}

@Bean
public RestateComponentProperties myServiceConfig() {
    return new RestateComponentProperties()
        .setInactivityTimeout(Duration.ofMinutes(10))
        .setDocumentation("My service");
}

[Kotlin] New experimental API

Following the introduction of the new experimental API for Java in v2.5.0, we’re now bringing the same experience to Kotlin!The new API removes the need for the KSP code generator, making it significantly simpler to use the Restate SDK:
  • No KSP code generator required: The SDK now uses reflection to discover and bind your services, eliminating the need for build-time code generation and making your build simpler and faster.
  • No more Context parameters: Handler methods no longer need to accept a Context parameter. Instead, use top-level functions from dev.restate.sdk.kotlin to access state, promises, and other Restate functionality.
  • Cleaner method signatures: Your handler methods now have cleaner signatures that focus on your business logic rather than Restate infrastructure.
The new API is opt-in and can be incrementally adopted in an existing project, meaning the existing API will continue to work as usual. It is marked as experimental and subject to change in the next releases.We’re looking for your feedback to evolve it and stabilize it!

How to use it

  1. Remove the KSP code generator dependency sdk-api-kotlin-gen
  2. Remove the Context, ObjectContext, SharedObjectContext, WorkflowContext, SharedWorkflowContext parameters from your @Handler annotated methods. For example:
    @VirtualObject
    class Counter {
    
      @Handler
      suspend fun add(ctx: ObjectContext, value: Long) {}
    
      @Shared
      @Handler
      suspend fun get(ctx: SharedObjectContext): Long {}
    }
    
    Becomes:
    import dev.restate.sdk.kotlin.*
    
    @VirtualObject
    class Counter {
    
      @Handler
      suspend fun add(value: Long) {}
    
      @Shared
      @Handler
      suspend fun get(): Long {}
    }
    
    The same applies for interfaces using Restate annotations.
  3. Replace all the usages of ctx. with the top-level functions. For example:
    @Handler
    suspend fun add(ctx: ObjectContext, value: Long) {
        val currentValue = ctx.get(TOTAL) ?: 0L
        val newValue = currentValue + value
        ctx.set(TOTAL, newValue)
    }
    
    Becomes:
    @Handler
    suspend fun add(value: Long) {
        val state = state()
        val currentValue = state.get(TOTAL) ?: 0L
        val newValue = currentValue + value
        state.set(TOTAL, newValue)
    }
    
  4. Replace all the usages of code-generated clients. There are two ways to invoke services: Simple proxy (for direct calls): The top-level functions let you create proxies to call services directly using service<T>(), virtualObject<T>(key) and workflow<T>(key):
    virtualObject<Counter>("my-key").add(1) // Direct method call
    
    Handle-based (for advanced patterns): For asynchronous handling, request composition, or invocation options (such as idempotency keys), use toService&lt;T&gt;(), toVirtualObject&lt;T&gt;(key) and toWorkflow&lt;T&gt;(key):
    // Use call() with a lambda to return a DurableFuture you can await asynchronously and/or compose with other futures
    val count = toVirtualObject<Counter>("my-counter")
        .request { add(1) }
        .call()
        .await()
    
    // Use send() for one-way invocation without waiting
    val handle = toVirtualObject<Counter>("my-counter")
        .request { add(1) }
        .send()
    
    // Add request options such as idempotency key
    val count = toVirtualObject<Counter>("my-counter")
        .request { add(1) }
        .options { idempotencyKey = "my-idempotency-key" }
        .call()
        .await()
    

Reference sheet

Context API (2.5.x)New reflection API (2.6.0)
ctx.runBlock &#123; ... &#125;/ctx.runAsync &#123; ... &#125;runBlock &#123; ... &#125;/runAsync &#123; ... &#125;
ctx.random()random()
ctx.timer()timer()
ctx.awakeable()awakeable&lt;T&gt;()
ctx.get(key) / ctx.set(key, value)state().get(key) / state().set(key, value)
ctx.promise(key)promise(key)
Code generated clients (Services)service&lt;T&gt;() / toService&lt;T&gt;()
Code generated clients (Virtual Objects)virtualObject&lt;T&gt;(key) / toVirtualObject&lt;T&gt;(key)
Code generated clients (Workflows)workflow&lt;T&gt;(key) / toWorkflow&lt;T&gt;(key)

Using concrete classes with proxy clients

By default, Kotlin classes are final, preventing libraries like Restate to generate runtime client proxies.We generally suggest one of the following three options:
  • Define an interface with all Restate annotations and have your class implement it. Use the interface type for proxy calls, e.g. service&lt;MyServiceInterface&gt;().
  • Use open in all Restate annotated classes/methods.
  • Setup the Kotlin allopen compiler plugin with the following configuration:
Gradle (Kotlin DSL)
plugins {
    kotlin("plugin.allopen") version "<kotlin-version>"
}

allOpen {
    annotations("dev.restate.sdk.annotation.Service", "dev.restate.sdk.annotation.VirtualObject", "dev.restate.sdk.annotation.Workflow")
}
This configuration automatically makes any class annotated with Restate annotations open, along with all their methods.

Gradual migration

You can gradually migrate to the new API by disabling the KSP code generator for specific classes. For example, if you have a project with a my.example.Greeter and a my.example.Counter, you can decide to migrate only my.example.Counter to use the new API.To do so, keep the KSP code generator dependency and pass the KSP option dev.restate.codegen.disabledClasses as follows:Gradle (Kotlin DSL)
ksp {
  val disabledClassesCodegen =
    listOf(
      // Ignore Counter in the KSP code generator
      "my.example.Counter")

  arg("dev.restate.codegen.disabledClasses", disabledClassesCodegen.joinToString(","))
}

New API for Deterministic Time

We’ve added a new API to get the current time deterministically that’s consistent across replays.

Java

import java.time.Instant;

@Handler
public String myHandler() {
    Instant now = Restate.instantNow();
    // or using the context-based API:
    // Instant now = ctx.instantNow();
    return "Current time: " + now;
}

Kotlin

import kotlin.time.Clock
import kotlin.time.ExperimentalTime
import dev.restate.sdk.kotlin.*

@OptIn(ExperimentalTime::class)
@Handler
suspend fun myHandler(): String {
    val now = Clock.Restate.now()
    return "Current time: $now"
}
Note: in Kotlin you need to opt in the Kotlin experimental time APIs.

Other changes

  • Fix detection of @Raw annotation in Java Reflection API
  • Serde.RAW.contentType() now correctly returns application/octet-stream
  • Dependency updates:
    • Jackson 2.19.4
    • Spring Boot 3.4.13
    • Vert.x 4.5.24
    • OpenTelemetry 1.58.0
    • JUnit 5.14.1
View on GitHub
2026-01-13
Java/Kotlin SDK v2.5.0

Release 2.5.0

We’re excited to announce Restate Java SDK 2.5.0, featuring a major improvement to the developer experience with a new reflection-based API.

Experimental Reflection-Based API

The new reflection-based API removes the need for the annotation processor, making it significantly simpler to use the Restate SDK:
  • No annotation processor required: The SDK now uses reflection to discover and bind your services, eliminating the need for build-time annotation processing and making your build simpler and faster.
  • No more Context parameters: Handler methods no longer need to accept a Context parameter. Instead, use static methods from the Restate class to access state, promises, and other Restate functionality.
  • Cleaner method signatures: Your handler methods now have cleaner signatures that focus on your business logic rather than Restate infrastructure.
The new API is opt-in and can be incrementally adopted in an existing project, meaning the existing API will continue to work as usual. It is marked as experimental and subject to change in the next releases.This API is currently available only for Java, but we plan to add an equivalent for Kotlin in future releases.We’re looking for your feedback to evolve it and stabilize it!

How to use it

  1. Remove the annotation processor dependency sdk-api-gen
  2. Remove the Context, ObjectContext, SharedObjectContext, WorkflowContext, SharedWorkflowContext parameters from your @Handler annotated methods. For example:
    @VirtualObject
    public class Counter {
    
      @Handler
      public void add(ObjectContext ctx, long request) {}
    
      @Shared
      @Handler
      public long get(SharedObjectContext ctx) {}
    }
    
    Becomes:
    @VirtualObject
    public class Counter {
    
      @Handler
      public void add(long request) {}
    
      @Shared
      @Handler
      public long get() {}
    }
    
    The same applies for interfaces using Restate annotations.
  3. Replace all the usages of ctx. with Restate.. For example:
    @Handler
    public void add(ObjectContext ctx, long value) {
        long currentValue = ctx.get(TOTAL).orElse(0L);
        long newValue = currentValue + value;
        ctx.set(TOTAL, newValue);
    }
    
    Becomes:
    @Handler
    public void add(long value) {
        var state = Restate.state();
        long currentValue = state.get(TOTAL).orElse(0L);
        long newValue = currentValue + value;
        state.set(TOTAL, newValue);
    }
    
  4. Replace all the usages of code-generated clients. There are two ways to invoke services: Simple proxy (for direct calls): The Restate class lets you create proxies to call services directly using service(Class), virtualObject(Class, key) and workflow(Class, key):
    Restate.virtualObject(Counter.class, "my-key").add(1); // Direct method call
    
    Handle-based (for advanced patterns): For asynchronous handling, request composition, or invocation options (such as idempotency keys), use serviceHandle(Class), virtualObjectHandle(Class, key) and workflowHandle(Class, key):
    // Use call() with method reference to return a DurableFuture you can await asynchronously and/or compose with other futures
    int count = Restate.virtualObjectHandle(Counter.class, "my-counter")
        .call(Counter::increment)
        .await();
    
    // Use send() for one-way invocation without waiting
    InvocationHandle<Integer> handle = Restate.virtualObjectHandle(Counter.class, "my-counter")
        .send(Counter::increment);
    
    // Add request options such as idempotency key
    int count = Restate.virtualObjectHandle(Counter.class, "my-counter")
            .call(Counter::increment, InvocationOptions.idempotencyKey("my-idempotency-key"))
            .await();
    

Reference sheet

Context API (2.4.x)New Restate API (2.5.0)
ctx.run(...)Restate.run(...)
ctx.random()Restate.random()
ctx.timer()Restate.timer()
ctx.awakeable()Restate.awakeable()
ctx.get(key) / ctx.set(key, value)Restate.state().get(key) / Restate.state().set(key, value)
ctx.promise(key)Restate.promise(key)
Code generated clients (Services)Restate.service(Class) / Restate.serviceHandle(Class)
Code generated clients (Virtual Objects)Restate.virtualObject(Class, key) / Restate.virtualObjectHandle(Class, key)
Code generated clients (Workflows)Restate.workflow(Class, key) / Restate.workflowHandle(Class, key)

Gradual migration

You can gradually migrate to the new API by disabling the annotation processor for specific classes. For example, if you have a project with a my.example.Greeter and a my.example.Counter, you can decide to migrate only my.example.Counter to use the new API.To do so, keep the annotation processor dependency and pass the compiler option dev.restate.codegen.disabledClasses as follows:Gradle
tasks.withType<JavaCompile> {
  val disabledClassesCodegen =
    listOf(
      // Ignore Counter in the annotation processor
      "my.example.Counter")

  options.compilerArgs.addAll(
    listOf(
      "-Adev.restate.codegen.disabledClasses=${disabledClassesCodegen.joinToString(",")}",
    ))
}
Maven
<build>
    <plugins>
      <!-- Setup annotation processor -->
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.11.0</version>
        <configuration>
          <annotationProcessorPaths>
            <path>
              <groupId>dev.restate</groupId>
              <artifactId>sdk-api-gen</artifactId>
              <version>${restate.version}</version>
            </path>
          </annotationProcessorPaths>
          <compilerArgs>
            <!-- Ignore Counter in the annotation processor -->
            <arg>-Adev.restate.codegen.disabledClasses=my.example.Counter</arg>
          </compilerArgs>
        </configuration>
      </plugin>
    </plugins>
</build>
View on GitHub
2025-12-09
Java/Kotlin SDK v2.4.2

What’s Changed

  • Various improvements to the code generator

New Contributors

View on GitHub
2025-11-03
Java/Kotlin SDK v2.4.1

Notable changes

New Contributors

View on GitHub
2025-09-16
Java/Kotlin SDK v2.4.0

Invocation retry policy

When used with Restate 1.5, you can now configure the invocation retry policy from the SDK directly. See https://github.com/restatedev/restate/releases/tag/v1.5.0 for more details on the new invocation retry policy configuration.

[Spring integration] Configure service options

A new API was introduced to configure services using the Spring integration:
// Specifiy the bean name of the configuration
@RestateService(configuration = "greeterConfiguration")
public class Greeter {
  // Your service
}

// Example configuration class
public class Configuration {
  @Bean
  public RestateServiceConfigurator greeterConfiguration() {
    return configurator -> configurator.inactivityTimeout(Duration.ofMinutes(2));
  }
}

What’s Changed

View on GitHub
2025-08-18
Java/Kotlin SDK v2.3.0
IMPORTANT For Spring Users: Due to MadeYourReset CVE, we bumped Vert.x and Netty to latest releases. This results in misaligned Netty dependency when used in combination with Spring Parent POM/Gradle dependency management plugin. To fix it, force the correct Netty version:
  • If you use Maven with spring parent POM add <netty.version>4.1.124.Final</netty.version> to your POM
  • If you use Gradle Spring dependency management plugin add netty.version = 4.1.124.Final to the gradle.properties file

Improvements

  • Added ability to disable bidirectional streaming. This can be useful in some environments where HTTP/2 streaming doesn’t work properly. To disable it using RestateHttpServer:
var handler = HttpEndpointRequestHandler.fromEndpoint(
      Endpoint.builder().bind(new Counter()).build(),
      /* disableBidirectionalStreaming */ true
);
RestateHttpServer.listen(handler);
To disable it when using the spring boot integration, add restate.sdk.http.disableBidirectionalStreaming=true to your application.properties
  • Add delay to generated workflow clients submit method
  • Added few extension methods to Kotlin ingress client

Bug fixes

  • Removed double logging of TerminalException
  • Removed noisy logging of coroutine cancellation when irrelevant
  • Dependency bumps
    • Vert.x 4.5.18
    • Kotlin 2.2.10
View on GitHub
2025-08-06
Java/Kotlin SDK v2.2.1

What’s Changed

View on GitHub
2025-07-03
Java/Kotlin SDK v2.2.0
  • You can now configure the service/handler options when binding the services, e.g. in Kotlin:
endpoint {
  bind(MyService()) {
    it.journalRetention = 10.days
    it.configureHandler("myHandler") {
      it.inactivityTimeout = 10.minutes
    }
  }
}
  • The following new configuration options are available for services and handlers: inactivityTimeout, abortTimeout, idempotencyRetention, journalRetention, ingressPrivate, enableLazyState. Please note, these will only work with Restate 1.4 onward.

What’s Changed

View on GitHub
2025-06-05
Java/Kotlin SDK v2.1.1

What’s Changed

View on GitHub
2025-04-29
Java/Kotlin SDK v2.1.0

What’s Changed

Kotlin now supports JSON Schema

The Kotlin API now supports OOTB generating Json Schemas, using https://github.com/SMILEY4/schema-kenerator. The schemas will be automatically propagated to restate-server, and they will be available in the generated OpenAPI and in the Restate Playground.

Changelog

View on GitHub
2025-04-10
Java/Kotlin SDK v2.0.0

Java/Kotlin SDK 2.0

We’re pleased to announce the release of Java/Kotlin SDK 2.0, in combination with Restate 1.3. Check out the announcement blog post for more details about Restate 1.3 and the new SDK features: https://restate.dev/blog/announcing-restate-1.3/Below are the changes specific to the Java/Kotlin SDK.

What’s new and what changed

New meta packages

From now on you don’t need to pick individual packages of the SDK to get started, but you can use the new meta packages:
  • dev.restate:sdk-java-http for Java API + HTTP endpoint (example build.gradle.kts/pom.xml)
  • dev.restate:sdk-java-lambda for Java API + Lambda endpoint
  • dev.restate:sdk-kotlin-http for Kotlin API + HTTP endpoint (example build.gradle.kts)
  • dev.restate:sdk-kotlin-lambda for Kotlin API + Lambda endpoint
E.g. for Java (gradle):
annotationProcessor("dev.restate:sdk-api-gen:2.0.0")

// Java API + HTTP endpoint
implementation("dev.restate:sdk-java-http:2.0.0")
For kotlin:
// Code generator
ksp("dev.restate:sdk-api-kotlin-gen:2.0.0")

// Kotlin API + HTTP endpoint
implementation("dev.restate:sdk-kotlin-http:2.0.0")
You still need to individually import the code generator packages, as before, because those are not required at runtime.

Code generation and sharing code-generated artifacts

We made few changes to the generated code, with the goal of simplifying sharing code generated artifacts with 3rd party consumers of your Restate services.Among the notable breaking changes:
  • All methods in generated clients, both for normal client and Context client, have an overload/optional parameter that allows to set additional options, including headers and idempotencyKey to use. Removed the old overloads accepting CallRequestOptions. For example this code:
client.handler("input", CallRequestOptions.DEFAULT.withIdempotency("my key"))
becomes
client.handler("input", opts -> opts.idempotencyKey("my key"))
  • Annotations @Service/@VirtualObject/@Workflow name argument is deprecated, you can now override the name used by Restate for both services and handlers using the @Name annotation. This name won’t affect anymore the name prefix of the generated classes.
  • The clients method .send(Duration) has been removed in favor of overloads/optional parameter to perform one way calls with delay.
  • The new class [your service name]Handlers contains inside the old class [your service name]Metadata.
  • All send methods in context clients now return InvocationHandle.
A new class will now be generated, called [your service name]Handlers, that lets you easily call your service as follows:
// For service to service
GreeterHandlers.greet(request).call(ctx)
GreeterHandlers.greet(request).send(ctx)

// For Client
val restateClient: Client = Client.connect("https://my-restate/")
GreeterHandlers.greet(request).call(restateClient)
GreeterHandlers.greet(request).send(restateClient)
This class has few dependencies on some core classes of the SDK, that we commit to maintain ABI stable. You can publish/share this generated class, and use it in combination with the Client simply importing the module dev.restate:client for Java or dev.restate:client-kotlin for Kotlin.On top of that, this class works both for Kotlin API users and with Java API users, letting you call from Java to Kotlin and vice versa.If you don’t use the [...]Client class, but you use only the [...]Handlers, we suggest disabling its code generation as follows. For Java (gradle):
tasks {
  withType<JavaCompile> {
    options.compilerArgs.addAll(
      listOf(
        "-Adev.restate.codegen.disabledClientGeneration=my.fqcn.ServiceName"
      )
    )
  }
}
In Kotlin KSP (gradle):
ksp {
  arg("dev.restate.codegen.disabledClientGeneration", "my.fqcn.ServiceName")
}
Note: the generated artifacts from the SDK 1.x versions ARE NOT compatible with the generated artifacts from 2.x onward. From SDK 2.x, we commit to a stable ABI between generated code artifacts and the SDK versions, meaning you’ll be able to safely mix code generated artifacts with SDK version. For example, you’ll be able to import a code generated artifact using SDK 2.0 in a project using SDK 2.1.

Client changes

We overhauled the client to interact with Restate. Now it lives in a new maven module ad hoc called dev.restate:client, which you can import separately from the rest of the SDK when you need to interact only with Restate from another Java/Kotlin application.Notable changes:
  • Renamed package dev.restate.sdk.client to dev.restate.client
  • Renamed dev.restate.sdk.client.CallRequestOptions to dev.restate.client.RequestOptions
  • Now all client methods returns headers and status code, see interface dev.restate.client.ResponseHead.
  • It is possible to bootstrap your own Client implementation using the HTTP client of your choice extending dev.restate.client.base.BaseClient

Endpoint and RestateHttpServer

We now expose a uniform API across Http and Lambda support to build your service endpoint. In Java:
var endpoint = Endpoint
        .bind(new Greeter())
        // Run Counter on virtual threads
        .bind(new Counter(), HandlerRunner.Options.withExecutor(Executors.newVirtualThreadPerTaskExecutor()));

// E.g. bind to server
RestateHttpServer.listen(endpoint);
In Kotlin:
val endpoint = endpoint {
  bind(Greeter())
  // Decorate the coroutine context used by the handler
  bind(Counter(), HandlerRunner.Options(Dispatchers.Default + CoroutineName("counter")))
}

// E.g. bind to server
RestateHttpServer.listen(endpoint)
Using HttpEndpointRequestHandler.fromEndpoint(Endpoint) it is also possible to get a Vert.x request handler for your endpoint, that can be used to build the HTTP server manually.Notable changes:
  • RestateHttpEndpointBuilder was deprecated, use RestateHttpServer instead.
  • RestateLambdaEndpointBuilder was removed, now BaseRestateLambdaHandler.register takes Endpoint.Builder as argument.

The DurableFuture interface

We renamed the Awaitable to DurableFuture and reworked few of its methods, to make it easier to interact with asynchronous events and compose them:
  • Added DurableFuture.withTimeout(Duration) to return a future composed with the timeout. This has the same behavior as DurableFuture.await(Duration) but it returns a future that can be later awaited, instead of awaiting the future immediately.
  • DurableFuture.await(Duration) now throws dev.restate.sdk.common.TimeoutException instead of java.util.concurrent.TimeoutException.
  • Added DurableFuture.map(successMapper), DurableFuture.map(successMapper, failureMapper) and DurableFuture.mapFailure(failureMapper), to map futures result once completed.
Check out the respective DurableFuture Javadocs/DurableFuture KotlinDocs for more details.

Deterministic resilient concurrency

As described in the blog post, Restate 1.3 improves support over deterministic concurrency.In Java we expose the new API Select to await on multiple futures at the same time:
DurableFuture<String> a12 = Select.<String>select()
        .or(a1)
        .or(a2);
In Kotlin you can use the select function, which now returns a DurableFuture itself and can be composed too:
select {
  a1.onAwait { it }
  a2.onAwait { it }
}

ctx.runAsync to compose asynchronous side effects

Both in Java and Kotlin you can now use the ctx.runAsync API in order to execute a side effect, and return a DurableFuture instead than the result immediately. You can then compose this future with other DurableFutures, for example to implement fan-in/fan-out operations.

InvocationHandle for finer control over service-to-service communication

As described in the blog post, Restate 1.3 features new APIs to interact with running invocations.All these features are encapsulated in the new InvocationHandle(Javadocs/Kotlin docs) API:
val handle = GreeterClient.fromContext(context).send().greet(request)

// Get invocation id
val invocationId = handle.invocationId()

// Cancel invocation
handle.cancel()

// Attach and await result
val result = handle.attach().await()

New Serde stack

We overhauled the Serde stack completely. Now you don’t need to pass around, neither figure out Serdes anymore, but you just need to focus on what types you need. For example:
// Defining a state key
StateKey<Integer> REMINDER_COUNT = StateKey.of("reminder_count", Integer.TYPE);

// Using ctx.run
String result = ctx.run(String.class, () -> doSideEffect());
Or for generic types:
List<SubTask> subTasks = ctx.run(new TypeRef<>() {}, () -> split(task));
In Kotlin, defining state keys/durable promise keys is easier than ever:
val COUNT = stateKey<Int>("greet-count")
By default, we still use Jackson for Java, and Kotlinx serialization for Kotlin, but you can completely override these choices by bringing in your serialization/deserialization stack. For this, and more details on how to customize the Jackson or Kotlinx serialization defaults, check this documentation page: https://docs.restate.dev/develop/java/serializationNotable changes:
  • Renamed dev.restate.sdk.common.Serde to dev.restate.serde.Serde
  • JsonSerdes is deprecated, use the Class and TypeTag overloads of Context methods instead. Check above how the new Serde stack works.
  • KtSerdes/KtDurablePromiseKey/KtStateKey are deprecated. To create a state key in Kotlin use stateKey&lt;T&gt;(name), for a durable promise key durablePromiseKey&lt;T&gt;(name). Check above how the new Serde stack works.
  • Serde interface now uses dev.restate.common.Slice instead of directly byte arrays/NIO ByteBuffer.

Kotlin Spring Boot integration

In the SDK release 1.2 we introduced an integration with Spring Boot, specifically designed for the Java API. We now introduced a similar integration in Kotlin too, to let you easily build Restate applications using Kotlin and Spring boot. Check out the quickstart: https://docs.restate.dev/get_started/quickstart?sdk=kotlin

Other changes

  • SDK Java 2.0 works only with Restate 1.3 onward.
  • There is a new API to call/send requests between services, without using the client. Check out the dev.restate.common.Request javadocs for more details.
  • protobuf is now distributed shaded, in order to avoid dependency conflicts.
  • Package sdk-serde-protobuf was removed.
  • Removed deprecations.
View on GitHub
2024-11-20
Java/Kotlin SDK v1.2.0
We’re pleased to announce the release of the Java SDK 1.2.0

New features

Notable changes

  • The ctx.run with RetryPolicy has been promoted to stable feature, check the Javadocs for more details.
  • You can now use checked exceptions within your @Handler annotated methods.

Breaking changes

  • Bumped minimum JDK version to 17
  • Because of a breaking change within log4j, you MUST either bump log4j-core to >= 2.24, or exclude the log4j-api dependency when depending on the SDK. For example, in gradle:
// Restate SDK
implementation("dev.restate:sdk-api:$restateVersion") {
   // Exclude transitive deps on log4j2
  exclude(group = "org.apache.logging.log4j")
}
implementation("dev.restate:sdk-http-vertx:$restateVersion") {
  exclude(group = "org.apache.logging.log4j")
}
// To use Jackson to read/write state entries (optional)
implementation("dev.restate:sdk-serde-jackson:$restateVersion") {
  exclude(group = "org.apache.logging.log4j")
}

// Pin log4j2 to 2.20
implementation("org.apache.logging.log4j:log4j-core:2.20.0")
implementation("org.apache.logging.log4j:log4j-api:2.20.0") 
  • This release is not bytecode compatible with previous releases, meaning you can’t mix the annotation processor generated code from SDK <= 1.2.0 with this release.
  • This release is compatible with Restate >= 1.1

Changelog

View on GitHub
2024-10-16
Java/Kotlin SDK v1.1.1

What’s Changed

View on GitHub
2024-09-09
Java/Kotlin SDK v1.1.0

New features

  • [Preview] Add retry policies for run operations, to limit the amount of retries/the duration of the retries
  • The ingress client now supports the ability to retrieve invocations/attach to existing invocations using idempotency id

What’s Changed

View on GitHub
2024-06-07
Java/Kotlin SDK v1.0.0
We’re happy to announce that Restate has reached the 1.0 milestone!Check the Restate 1.0 release for more details.

Workflow API

We have introduced a new API to simplify building workflows, check out the documentation: https://docs.restate.dev/develop/java/workflows

Breaking changes from 0.9

Other changes

View on GitHub
2024-05-03
Java/Kotlin SDK v0.9.2

What’s Changed

View on GitHub
2024-04-30
Java/Kotlin SDK v0.9.1

What’s Changed

View on GitHub
2024-04-25
Java/Kotlin SDK v0.9.0
This release features a completely overhauled development experience. We suggest checking out the new documentation https://docs.restate.dev/develop/java/overview for more details and the new examples https://github.com/restatedev/examples.

What’s Changed

View on GitHub
2024-03-01
Java/Kotlin SDK v0.8.0

What’s Changed

New Contributors

View on GitHub
2024-02-01
Java/Kotlin SDK v0.7.0

What’s Changed

View on GitHub
2023-12-13
Java/Kotlin SDK v0.6.0