Skip to content

Releases: streamnative/lightproto

v0.7.3

12 May 20:47

Choose a tag to compare

Dependency cleanup

This release shrinks the lightproto-code-generator dependency footprint and removes the transitive log4j 1.2.17 that came in via jibx-tools. Generated code is byte-identical to v0.7.2.

Drop jibx-tools dependency (#8)

jibx-tools was only used for two simple pluralize / depluralize helpers feeding into generated repeated-field accessor names (addItem, getItemsCount, …). The actual logic — ~40 lines of suffix-rule manipulation from org.jibx.util.NameUtilities — is now vendored directly into the code generator (BSD 3-clause, attributed in source). This drops:

  • org.jibx:jibx-tools 1.3.3
  • log4j:log4j 1.2.17 (multiple CVEs)
  • ~10 ancient org.eclipse.* JDT jars

The vendored behavior is locked in by a new parameterized UtilTest that covers every branch of the rules (including the case-sensitivity quirk where "ANY" pluralizes to "ANYs").

Drop guava dependency (#9)

The code generator used guava for three small utilities: Joiner.on('/').join(...) (replaced by String.join), Maps.newHashMap() (replaced by new HashMap<>()), and CaseFormat snake↔camel conversions (replaced by two small in-tree helpers, verified byte-identical to guava's output for every input shape that appears in the code generator). Removes:

  • com.google.guava:guava 32.0.0-jre
  • 6 transitive annotation jars (failureaccess, listenablefuture, jsr305, checker-qual, error_prone_annotations, j2objc-annotations)

Net effect

After these two changes, the lightproto-code-generator runtime dependency tree is just protobuf-java + slf4j-api + roaster. The generated runtime is unchanged.

v0.7.2

09 May 18:55

Choose a tag to compare

What's New

JSON serialization is now opt-in (#7)

Breaking: JSON methods (writeJsonTo, parseFromJson, toJson) are no longer generated by default. To opt back in, set the new generateJson plugin option (Maven <generateJson>true</generateJson>, Gradle generateJson = true), mirroring how generateTextFormat already worked. The package-private LightProtoMessage interface no longer declares the JSON methods, so messages compile cleanly when JSON is disabled.

Required-field getters return defaults instead of throwing (#5)

proto2 required-field getters used to throw IllegalStateException when the field was unset. They now return the type-appropriate default (0 / false / "" / empty bytes / valueOf(0) / lazily-created empty message), matching protobuf-java. Required-field validation still runs at writeTo() and parseFrom() time, so missing required fields are still caught at the message boundary.

bytes field setters no longer consume the source ByteBuf reader index (#6)

Setting a bytes field from a ByteBuf no longer advances the source buffer's readerIndex during serialization, so a message remains safe to re-serialize (e.g., on a gRPC retry) and two fields can safely alias the same backing buffer.

v0.7.0

07 May 19:36

Choose a tag to compare

What's New

Protobuf TextFormat (de)serialization (opt-in)

  • New generateTextFormat plugin option (Maven <generateTextFormat>true</generateTextFormat>, Gradle generateTextFormat = true). When enabled, every generated message gets toTextFormat(), writeTextFormatTo(StringBuilder), and parseFromTextFormat(String|byte[]|ByteBuf).
  • Output is canonical multi-line, indented protobuf TextFormat — compatible with com.google.protobuf.TextFormat.printer() for serialization and TextFormat.merge() for parsing, so existing TextFormat data round-trips.
  • Cross-package sub-messages share a ByteBuf cursor, so messages that reference types from a different generated package parse correctly (same handoff used by JSON parsing).

Generated equals() / hashCode()

  • All generated message types now implement equals(Object) and hashCode(), making LightProto messages safe to use directly as keys in HashMap / HashSet and to compare with assertEquals in tests.

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