Skip to content

Releases: streamnative/lightproto

v0.6.6

26 Mar 23:48

Choose a tag to compare

What's New

Cross-package proto import support for JSON parsing

  • Fixed JSON deserialization when messages reference types from different protobuf packages (different Java packages)
  • Refactored JsonReader to use ByteBuf internally, eliminating cross-package type incompatibilities

Generated file headers

  • All generated .java files now include a header comment with LightProto version and source .proto filename

v0.6.5

25 Mar 23:17

Choose a tag to compare

What's New

JSON Deserialization (parseFromJson)

Every generated message now supports JSON deserialization with three overloads:

message.parseFromJson(String json);
message.parseFromJson(byte[] jsonBytes);
message.parseFromJson(ByteBuf jsonBuf);

The JSON format is fully compatible with protobuf's JsonFormat output:

  • lowerCamelCase field names
  • int64/uint64 values quoted as strings
  • Enum values as string names
  • Bytes fields as base64-encoded strings
  • Unknown fields silently ignored (forward compatibility)

This enables drop-in replacement of JsonFormat.parser().merge() when migrating from Google Protobuf to LightProto.

Implementation Details

  • Lightweight recursive-descent JSON parser in LightProtoCodec with no external dependencies
  • Supports all field types: scalars, strings, bytes, enums, nested messages, repeated fields, and maps
  • ByteBuf overload avoids String allocation when JSON is already in a buffer

Lightproto 0.6.3

25 Mar 05:01

Choose a tag to compare

Bug Fixes

  • Fixed ByteBuf leak in gRPC marshaller — The generated Marshaller.stream() was allocating a Netty ByteBuf that could leak when gRPC failed to close the returned InputStream (e.g., when NoopClientStream or FailingClientStream silently discards the message). The marshaller now serializes into an Unpooled.buffer(), extracts the backing byte[] directly (zero-copy), and wraps it in a GC-safe ByteArrayInputStream subclass. Even if close() is never called, there is no resource leak. (grpc-java#12729)

Improvements

  • Implemented Drainable and KnownLength on marshaller InputStream — The stream returned by Marshaller.stream() now implements io.grpc.Drainable and io.grpc.KnownLength. This enables gRPC's MessageFramer to use the fast drainTo() path — a single write(byte[], off, len) call directly into the transport buffer — instead of falling back to byte-by-byte ByteStreams.copy().

  • Replaced sun.misc.Unsafe type references with MethodHandles — The generated codec no longer references sun.misc.Unsafe types, avoiding deprecation warnings and ensuring forward compatibility with future JDK releases.

LightProto 0.6.2

17 Mar 22:19

Choose a tag to compare

LightProto 0.6.2

Bug Fixes

  • Return default values for unset optional fields instead of throwing (#2) — Accessing an unset optional field (proto2) now returns the type-appropriate default value (0, false, "", empty bytes, valueOf(0) for enums, empty message instance) instead of throwing IllegalStateException. This matches standard Protobuf behavior. IllegalStateException is now only thrown for required fields. The clear() method also properly resets all field values back to defaults.

  • Fix Unsafe string optimizations when -XX:-CompactStrings is used (#1) — String serialization could produce corrupt output on JVMs running with -XX:-CompactStrings. The Unsafe-based fast path now correctly detects compact string encoding and falls back to the safe path when compact strings are disabled.

  • Catch specific exceptions in LightProtoCodec static initializer — The static initializer for Unsafe access now catches specific exception types instead of a broad Exception, improving debuggability when initialization fails.

Improvements

  • Add javadoc to generated gRPC service classes (#3) — All public methods and inner types in generated gRPC service classes now have javadoc comments, including method descriptor getters, stub factories, AsyncService, ImplBase, Stub, and BlockingStub.

LightProto 0.6.1

17 Mar 20:05

Choose a tag to compare

LightProto 0.6.1

Improvements

  • Make materialize() a public API for cross-package usage — Renamed the internal _materialize() method to materialize() with public visibility, allowing generated messages in different packages to call it on referenced message types. The parseFrom(buffer, size, eager) overload was removed in favor of explicit materialize() calls.

Full Changelog: v0.6.0...v0.6.1

LightProto 0.6.0

17 Mar 00:10

Choose a tag to compare

LightProto v0.6.0

This release moves LightProto under the StreamNative organization and includes all changes since v0.4.

Proto3 Support

Full proto3 syntax support including implicit field presence, packed-by-default repeated fields, and the optional keyword. Proto2 remains fully supported.

New Field Types

  • map<K, V> fields — complete support for protobuf map fields with all key/value type combinations
  • oneof fields — proto2 oneof support with efficient memory layout

gRPC Service Stubs

Generate complete *Grpc.java service stubs from service definitions in .proto files. Includes AsyncService, ImplBase, Stub, BlockingStub, MethodDescriptors, and ServiceDescriptor. Features zero-copy marshaller using Netty pooled direct buffers and cross-package type resolution.

Gradle Plugin

New io.streamnative.lightproto Gradle plugin for build-time code generation, complementing the existing Maven plugin.

Parser Rewrite

Replaced protostuff-parser with protoc descriptor sets for more accurate and complete proto file parsing.

Serialization Performance Overhaul

  • Unsafe-based serialization and string deserialization
  • Pre-ensureWritable in writeTo() eliminates per-field capacity checks
  • ASCII fast-path for string serialization
  • Native arrays replace ArrayList for repeated fields
  • Precomputed tag sizes for fixed-size types
  • Unrolled VarInt64 decoding
  • Cached serialized size after parseFrom

Eager deserialization support

A new parseFrom(ByteBuf buffer, int size, boolean eager) overload was introduced. Setting eager to true immediately resolves all lazily-deserialized fields (strings, bytes, and nested messages), preventing the resulting object from retaining references to the source ByteBuf. This proves valuable when buffers may be recycled after parsing.

Zero-copy gRPC deserialization

The gRPC marshaller implementation now leverages reflection to access the underlying ByteBuf from gRPC's ByteBufInputStream, deserializing eagerly without creating an intermediate byte[] copy. If the InputStream isn't a ByteBufInputStream, the system reverts to parseFrom(byte[]).

Javadoc generation

Proto source comments are now converted to Javadoc on generated message classes and enum types. All generated accessor methods including get, set, has, clear, add, getCount, and getList now feature Javadoc explaining their functionality.

Java 21+ compatibility

Warnings regarding sun.misc.Unsafe removal on Java 21+ were suppressed to maintain cleaner build output.

Performance: v0.4 → v0.6

Benchmark v0.4 v0.6 Speedup
ProtoBenchmark Serialize 8.3 22.6 +172%
ProtoBenchmark FillAndSerialize 5.9 12.8 +117%
ProtoBenchmark Deserialize 16.7 19.2 +15%
SimpleBenchmark Serialize 251.1 245.6 ~same
SimpleBenchmark Deserialize 93.2 100.9 +8%
SimpleBenchmark DeserializeReadString 39.4 54.1 +37%
PulsarAPI SerializeBaseCommand 12.4 26.8 +116%
PulsarAPI SerializeMessageMetadata 6.1 10.9 +79%
PulsarAPI DeserializeBaseCommand 39.1 40.3 +3%
PulsarAPI DeserializeMessageMetadata 14.0 14.1 ~same

LightProto v0.6 vs Google Protobuf (PulsarAPI)

Benchmark Protobuf LightProto Speedup
Serialize MessageMetadata 2.84 10.85 3.8x
Serialize BaseCommand 15.82 26.81 1.7x
Deserialize MessageMetadata 4.18 14.14 3.4x
Deserialize BaseCommand 12.77 40.30 3.2x

Dependency Updates

  • Bump com.google.guava:guava from 30.1-jre to 32.0.0-jre
  • Bump org.apache.maven:maven-core from 3.2.5 to 3.8.1