zio.temporal.json

Members list

Type members

Classlikes

final class CodecRegistry

Thread-safe (per-index under append-only use) registry that maps runtime types to the zio-json encoders/decoders that ZioJsonPayloadConverter uses to cross a Temporal boundary.

Thread-safe (per-index under append-only use) registry that maps runtime types to the zio-json encoders/decoders that ZioJsonPayloadConverter uses to cross a Temporal boundary.

'''Concurrency contract.''' Each of the three indexes (byClass, byType, byRawClass) is individually safe for concurrent access — a hit after a completed register is always seen by every reader. Cross-index visibility ''during'' a single register call is '''not''' atomic: a concurrent lookup may transiently see one index updated while another hasn't yet observed the same codec. Under the stated append-only usage the only observable effect is a transient miss (retriable by the caller); no partial overwrite is possible.

The registry is indexed three ways:

  • By java.lang.Class on the '''encode''' path (byClass). Temporal hands the DataConverter only v.getClass, so we must look up the encoder from that. Only ground-type codecs go here; see register for the rationale on keeping parameterized types out.
  • By java.lang.reflect.Type on the '''decode''' path (byType). Temporal hands the DataConverter a fully parameterized type (from the stub's method signature) that carries generic arguments — so List[Foo] and List[Bar] are distinguishable here.
  • By raw java.lang.Class with all parameterized-type candidates collected in a list (byRawClass). This is the fallback the encode path uses for user-defined generic case classes like Triple[A, B, C] where neither a direct byClass hit nor the container-iteration escape hatch applies. When a single parameterized candidate exists for a given raw class, its encoder is used; when multiple candidates exist, encode fails with a clear error listing both registered parameterized types.

All three views are populated in a single call to register so they stay in sync. Registrations are append-only: once a (class, type, codec) triple is in, it does not change.

In normal use the registry is populated at client/worker-construction time by zio-temporal's macros walking each workflow and activity interface. Manual registration via register is available for edge cases (e.g. an ad-hoc untyped stub).

Attributes

Companion
object
Supertypes
class Object
trait Matchable
class Any
object CodecRegistry

Attributes

Companion
class
Supertypes
class Object
trait Matchable
class Any
Self type
final class TemporalInternalsPayloadConverter extends PayloadConverter

Handles Temporal Java SDK internal POJOs that leak into the DataConverter chain as part of workflow mechanics the user never writes codecs for.

Handles Temporal Java SDK internal POJOs that leak into the DataConverter chain as part of workflow mechanics the user never writes codecs for.

The only class currently needed is io.temporal.internal.sync.WorkflowRetryerInternal$SerializableRetryOptions, which Workflow.retry serializes through a mutableSideEffect marker so that retry configuration is recorded in the workflow history (see WorkflowRetryerInternal.getRetryOptionsSideEffect). The SDK's default chain has Jackson as the last-resort converter and handles this transparently; since we've deliberately excluded Jackson (zio-temporal is Scala-only and zio-json covers the full user-facing surface), we have to encode this one class explicitly.

The allow-list is kept tight on purpose: open reflection over io.temporal.* would accidentally claim legitimate user-facing types like io.temporal.common.RetryOptions (builder-pattern, nested Duration) whose round-trip semantics are not ours to define.

Attributes

Companion
object
Supertypes
trait PayloadConverter
class Object
trait Matchable
class Any

Attributes

Companion
class
Supertypes
class Object
trait Matchable
class Any
Self type
trait ZTemporalCodec[A]

Evidence that a value of type A can be serialized to / deserialized from JSON for crossing a Temporal boundary (workflow/activity/signal/query arguments and results).

Evidence that a value of type A can be serialized to / deserialized from JSON for crossing a Temporal boundary (workflow/activity/signal/query arguments and results).

The presence of a ZTemporalCodec[A] is enforced at compile time by zio-temporal's macros wherever a Temporal interaction is performed. This replaces the previous Jackson-based runtime reflection, which silently emitted malformed JSON when Scala-aware modules were not registered.

Provide a ZTemporalCodec[A] by placing a given JsonEncoder[A] + JsonDecoder[A] (or a JsonCodec[A]) in A's companion object. For case classes and sealed traits, the simplest forms are

 final case class Foo(x: Int, y: String) derives ZTemporalCodec

 // or, if you'd rather derive zio-json directly and let the bridges pick it up:
 final case class Foo(x: Int, y: String) derives JsonCodec

which derives zio-json encoder/decoder and wraps them in a ZTemporalCodec.

The typeclass carries (in addition to the encoder and decoder) a java.lang.Class and a java.lang.reflect.Type, so the underlying Temporal Java SDK can dispatch on generic types such as List[Foo] vs. List[Bar].

Attributes

Companion
object
Supertypes
class Object
trait Matchable
class Any

Attributes

Companion
trait
Supertypes
class Object
trait Matchable
class Any
Self type

Entry point for constructing a DataConverter that uses zio-json for all user-owned payloads. Jackson is deliberately excluded from the chain — zio-temporal is Scala-only and zio-json covers the full encoding surface.

Entry point for constructing a DataConverter that uses zio-json for all user-owned payloads. Jackson is deliberately excluded from the chain — zio-temporal is Scala-only and zio-json covers the full encoding surface.

Chain ordering (Temporal's DefaultDataConverter tries each in order):

  1. NullPayloadConverter — null values
  2. ByteArrayPayloadConverter — raw byte buffers
  3. ProtobufJsonPayloadConverter — Temporal-internal protobuf types like WorkflowExecution
  4. TemporalInternalsPayloadConverter — an allow-listed set of Temporal Java SDK internal POJOs (currently WorkflowRetryerInternal$SerializableRetryOptions) that leak into the chain via Workflow.retry's mutableSideEffect and for which no user-provided codec exists. The upstream SDK relies on Jackson's reflective fallback here; we substitute a surgical reflective encoder.
  5. ZioJsonPayloadConverter encoding json/zio — user-owned payloads; claimed first on encode.
  6. ZioJsonPayloadConverter encoding json/plain — decode-only compatibility with recorded workflow histories that were originally written by the Jackson-based DefaultDataConverter. json/plain is just vanilla JSON, so the same registry decodes it correctly. Position matters: on encode, DefaultDataConverter stops at the first converter returning non-empty, so the json/zio instance wins and fresh payloads never get stamped json/plain.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
final class ZioJsonPayloadConverter(registry: CodecRegistry, encodingName: String) extends PayloadConverter

A Temporal PayloadConverter backed by zio-json and a CodecRegistry.

A Temporal PayloadConverter backed by zio-json and a CodecRegistry.

Encoding: looks up a JsonEncoder by the value's runtime class. Decoding: looks up a JsonDecoder by the requested generic Type (not just raw class), so List[Foo] and List[Bar] dispatch distinctly.

The encodingName argument controls the Temporal payload-encoding metadata string this converter claims. Default is "json/zio". A second instance in the chain with "json/plain" is used purely for decode — it lets recorded workflow histories that were originally written with Temporal's Jackson-based DefaultDataConverter (and therefore carry encoding=json/plain) replay through zio-json, since json/plain is just vanilla JSON and the registry's decoders handle it identically.

Throws DataConverterException with a specific message if a codec is missing — this should not happen for types exercised via zio-temporal's typed stubs/workers (the compile-time gate ensures registration) but can occur for untyped stubs or manual payload manipulation.

Attributes

Companion
object
Supertypes
trait PayloadConverter
class Object
trait Matchable
class Any

Attributes

Companion
class
Supertypes
class Object
trait Matchable
class Any
Self type