Skip to content

Serialization

Mario edited this page Sep 23, 2026 · 1 revision

Serialization & wire formats

In Vyra, the serializer you choose IS the wire format.

Unlike systems that wrap binary payloads inside base64 strings or hand-roll custom binary codecs, Vyra uses a single pure serializer to encode both the outer Message envelope and your inner application objects.


How it works: pure serialization

When Vyra sends a message, it passes the entire Message envelope and your application object to the configured serializer. The serializer encodes the entire structure in a single pass, producing a clean byte array for transport.

Because your application object is placed directly in the payload field, JSON serializers embed it as native, clean JSON:

{
  "messageId": "9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d",
  "correlationId": "a1c7d200-5e3e-4fa0-8bb2-3d849cf1a111",
  "source": "api-gateway-1",
  "kind": "REQUEST",
  "destination": "billing-service",
  "messageType": "invoice.create",
  "timestamp": 1716382000000,
  "payload": {
    "customerId": "cust-88",
    "items": [
      { "sku": "ITEM-1", "quantity": 2, "price": 49.99 }
    ]
  },
  "headers": {}
}

Benefits of pure serialization

  • Inspectable: you can monitor traffic directly in redis-cli using MONITOR or LRANGE req:billing-service 0 -1.
  • No base64 overhead: no 33% base64 size penalty or extra string allocations.
  • Single pass: envelopes and payloads are serialized together in a single pass.

Supported serializers

Vyra provides official serializer modules in separate artifacts:

Serializer Factory method Format Characteristics Best for
Jackson JSON JacksonSerializer.jackson() JSON Human-readable JSON, broad Java ecosystem support. Default choice for development and general microservices.
Jackson Smile JacksonSerializer.smile() Binary (Smile) 30% to 50% smaller than JSON, fast parsing, Jackson API. High-throughput services where bandwidth or broker memory matters.
Jackson CBOR JacksonSerializer.cbor() Binary (CBOR) RFC 8949 standard binary format, fast parsing. Environments requiring standard IETF binary formats.
Gson JSON GsonSerializer.gson() JSON Lightweight JSON alternative with minimal dependencies. Applications already centered around Google Gson.

Setting up a serializer

Add the chosen serializer to your build.gradle.kts:

// For Jackson (JSON, Smile, and CBOR)
implementation("com.marioded.vyra:vyra-jackson:0.1.0")

// Or for Gson
// implementation("com.marioded.vyra:vyra-gson:0.1.0")

Then configure it on the Vyra builder:

import com.marioded.vyra.jackson.JacksonSerializer;

// Human-readable JSON
Vyra vyraJson = Vyra.builder()
        .transport(transport)
        .serializer(JacksonSerializer.jackson())
        .build();

// High-performance binary Smile
Vyra vyraSmile = Vyra.builder()
        .transport(transport)
        .serializer(JacksonSerializer.smile())
        .build();

The uniform network constraint

Important

Every node communicating on the same transport MUST use the same serializer format.

Because the serializer controls the entire wire envelope:

  • A node using JacksonSerializer.smile() cannot decode a message sent by a node using JacksonSerializer.jackson().
  • If a node receives an unparseable message from an incompatible serializer, Vyra drops the message safely and logs a warning with troubleshooting hints. The application node will never crash.

Type conversion on deserialization

When a message arrives over the wire:

  1. The transport reads raw bytes.
  2. The serializer decodes the outer Message envelope. At this stage, the payload is represented as a generic tree structure (e.g., a Map or JsonNode).
  3. Core looks up the target Java class from your registered messageType.
  4. Core calls Serializer.convert(payload, targetClass) to transform the generic tree into your strongly-typed Java record.

Jackson and Gson implementations perform this conversion in-memory using optimized tree-to-object conversions without re-serializing.


Production caveats & best practices

1. Google Gson integer precision

In Google Gson, all numbers in untyped JSON structures default to Double. For integers larger than $2^{53}$, precision can be lost during deserialization.

  • Tip: if you use Gson with large IDs (e.g., Twitter Snowflakes or 64-bit unsigned longs), model them as String or BigDecimal.
  • Jackson is unaffected by this issue.

2. Custom naming strategies

If you configure a custom naming strategy on your ObjectMapper (such as PropertyNamingStrategies.SNAKE_CASE), it will apply to the envelope fields as well as your payload:

{ "message_id": "...", "correlation_id": null, "message_type": "...", ... }

This works as long as all nodes share the same serializer configuration (uniform network constraint).


Next steps

Vyra documentation

Getting started and messaging patterns

Transports and formats

Inside the framework

Reference

Clone this wiki locally