Skip to content

trendvidia/protowire-java

protowire-java

License: MIT Maven Central CI

Native Java port of protowire — a protobuf-backed serialization toolkit. Implements the canonical wire format defined in trendvidia/protowire and verified for byte-equivalence against eight sibling ports (Go, C++, Rust, TypeScript, Python, C#, Swift, Dart).

Java 21, Gradle multi-module, protobuf-gradle-plugin, JUnit 5.

Install

Maven:

<dependency>
  <groupId>org.protowire</groupId>
  <artifactId>protowire-pxf</artifactId>
  <version>0.70.0</version>
</dependency>

Gradle (Kotlin DSL):

implementation("org.protowire:protowire-pxf:0.70.0")
// or pick the modules you need:
//   protowire-pb, protowire-pxf, protowire-sbe, protowire-envelope, protowire-proto-annotations

All published artifacts share the 0.70.x line; ports at the same minor implement the same wire contract.

Modules

Module Java package Notes
:pb org.protowire.pb Schema-free struct ↔ proto3 binary marshaling. Field numbers come from the @ProtoField(N) annotation — the Java analogue of Go's protowire:"N" struct tag.
:pxf org.protowire.pxf PXF text ↔ Message / DynamicMessage. Two-tier decoder split: Pxf.parse() returns an AST with comments; Pxf.unmarshal / Pxf.unmarshalFull use a fused fast decoder.
:sbe org.protowire.sbe FIX SBE binary codec, driven by SBE annotations on .proto schemas. Codec.marshal, Codec.unmarshal, and a zero-allocation View. Includes Convert.xmlToProto / Convert.protoToXml.
:envelope org.protowire.envelope Standard API response envelope, generated from envelope/v1/envelope.proto, with Envelopes builders + queries.
:proto-annotations org.protowire.proto.{pxf,sbe} Compiled proto annotations: pxf.required, pxf.default, pxf.BigInt/Decimal/BigFloat, sbe.schema_id/template_id/length/encoding.
:dump-envelope, :bench-pxf, :bench-sbe (test harnesses) Per-port binaries used by the cross-port runner scripts in the spec repo. Not part of the public library API.

Build & test

./gradlew build       # compile + test all modules
./gradlew :pxf:test   # only PXF

Java 21 toolchain is required (configured automatically via Gradle).

PXF API

Decode

import org.protowire.pxf.Pxf;
import org.protowire.pxf.Result;

// schema-bound (compiled-in proto)
ServerConfig.Builder b = ServerConfig.newBuilder();
Pxf.unmarshal(pxfBytes, b);

// dynamic
DynamicMessage msg = Pxf.unmarshal(pxfBytes, descriptor);

// presence tracking
Result r = Pxf.unmarshalFull(pxfBytes, b);
r.isSet("name");
r.isNull("email");
r.isAbsent("role");

Encode

byte[] out = Pxf.marshal(msg);

// with options
byte[] out = MarshalOptions.defaults()
    .withTypeUrl("infra.v1.ServerConfig")
    .withEmitDefaults(true)
    .marshal(msg);

Parse → AST → format (comment-preserving)

Ast.Document doc = Pxf.parse(pxfBytes);
byte[] formatted = Pxf.formatDocument(doc);

The AST is a sealed hierarchy of records (Ast.Document, Ast.Entry, Ast.Value); pattern matching is used throughout the formatter and decoder.

Two-tier decoder split

Mirrors the Go module and the C++ port:

  • AST pathParser.parse() produces an Ast.Document with comments attached. Used when comment preservation is needed.
  • Fast pathFastDecoder fuses lexing + decoding in a single pass, writing directly into a Message.Builder with no intermediate AST allocation. Used by Pxf.unmarshal and Pxf.unmarshalFull.

Feature coverage

PXF (:pxf):

  • ✅ Lexer: single/triple strings, base64 bytes, RFC 3339 timestamps, Go-style durations, comments, dedent.
  • ✅ Schema-bound encoder + decoder via Java protobuf reflection (descriptors / DynamicMessage).
  • ✅ Scalars, enums, repeated, maps, nested messages, oneof.
  • ✅ Well-known types: Timestamp, Duration, all wrapper types (sugar form).
  • ✅ Field-presence tracking (unmarshalFull returns a Result).
  • google.protobuf.Any sugar (block syntax with @type =).
  • pxf.BigInt / pxf.Decimal / pxf.BigFloat sugar inside PXF text.
  • _null FieldMask discovery and emission across binary round-trips.
  • (pxf.required) / (pxf.default) annotation enforcement in unmarshalFull.
  • ✅ AST-preserving formatDocument.

SBE (:sbe):

  • ✅ Codec construction from FileDescriptors, schema/version/template-id discovery via SBE annotations.
  • marshal / unmarshal for proto messages, including composites and repeating groups.
  • ✅ Type-narrowing via (sbe.encoding) overrides.
  • ✅ Zero-allocation View / GroupView.
  • ✅ XML schema parsing and Convert.xmlToProto / Convert.protoToXml.

pb (:pb):

  • ✅ Wire format for all proto3 scalar types, repeated, embedded messages.
  • BigInteger / BigDecimal byte-backed types matching pxf.BigInt/Decimal schemas.
  • ✅ Unknown-field skipping on decode.

envelope (:envelope):

  • ✅ Generated Envelope/AppError/FieldError from proto plus Envelopes builders + queries.

GraalVM native-image

Every published jar carries reachability metadata under META-INF/native-image/org.protowire/<artifact>/, so the native-image agent doesn't warn about missing hints when consumers build a native binary.

:pb consumers using the schema-free @ProtoField-driven marshaler must register their own DTO classes for reflection — see pb/src/main/resources/META-INF/native-image/org.protowire/protowire-pb/native-image.properties for the rationale and template.

Command-line tool

The protowire CLI is shared across every port and lives in the spec repo at github.com/trendvidia/protowire/cmd/protowire. Install:

go install github.com/trendvidia/protowire/cmd/protowire@latest

Java users use this library for in-process encode/decode and the shared CLI for command-line operations. There is no separate Java CLI binary.

Wire compatibility

Verified by the exampleFixtureRoundTrip test in pxf/src/test/java/.../PxfTest.java: the same testdata/example.pxf from the Go module is parsed, marshaled, and re-parsed; the two DynamicMessage instances must compare equal.

Why a native Java JAR (vs a wrapper)

For Kotlin, Scala, Clojure, and any other JVM language, the native Java JAR is consumed directly. A wrapper around a non-JVM implementation would not be.

About

Java port of trendvidia/protowire - a serialization toolkit built around PXF (Proto eXpressive Format), SBE (Simple Binary Encoding), and a cross-port Envelope. PXF is a human-friendly text serialization format backed by protobuf schemas; SBE is a fixed-offset binary format for ultra-low-latency workloads; both share the same .proto file.

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages