Releases: streamnative/lightproto
v0.6.6
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
JsonReaderto useByteBufinternally, eliminating cross-package type incompatibilities
Generated file headers
- All generated
.javafiles now include a header comment with LightProto version and source.protofilename
v0.6.5
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
LightProtoCodecwith no external dependencies - Supports all field types: scalars, strings, bytes, enums, nested messages, repeated fields, and maps
ByteBufoverload avoidsStringallocation when JSON is already in a buffer
Lightproto 0.6.3
Bug Fixes
- Fixed ByteBuf leak in gRPC marshaller — The generated
Marshaller.stream()was allocating a NettyByteBufthat could leak when gRPC failed to close the returnedInputStream(e.g., whenNoopClientStreamorFailingClientStreamsilently discards the message). The marshaller now serializes into anUnpooled.buffer(), extracts the backingbyte[]directly (zero-copy), and wraps it in a GC-safeByteArrayInputStreamsubclass. Even ifclose()is never called, there is no resource leak. (grpc-java#12729)
Improvements
-
Implemented
DrainableandKnownLengthon marshaller InputStream — The stream returned byMarshaller.stream()now implementsio.grpc.Drainableandio.grpc.KnownLength. This enables gRPC'sMessageFramerto use the fastdrainTo()path — a singlewrite(byte[], off, len)call directly into the transport buffer — instead of falling back to byte-by-byteByteStreams.copy(). -
Replaced
sun.misc.Unsafetype references withMethodHandles— The generated codec no longer referencessun.misc.Unsafetypes, avoiding deprecation warnings and ensuring forward compatibility with future JDK releases.
LightProto 0.6.2
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 throwingIllegalStateException. This matches standard Protobuf behavior.IllegalStateExceptionis now only thrown for required fields. Theclear()method also properly resets all field values back to defaults. -
Fix Unsafe string optimizations when
-XX:-CompactStringsis 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, andBlockingStub.
LightProto 0.6.1
LightProto 0.6.1
Improvements
- Make
materialize()a public API for cross-package usage — Renamed the internal_materialize()method tomaterialize()with public visibility, allowing generated messages in different packages to call it on referenced message types. TheparseFrom(buffer, size, eager)overload was removed in favor of explicitmaterialize()calls.
Full Changelog: v0.6.0...v0.6.1
LightProto 0.6.0
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 combinationsoneoffields — 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
ArrayListfor 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:guavafrom 30.1-jre to 32.0.0-jre - Bump
org.apache.maven:maven-corefrom 3.2.5 to 3.8.1