Skip to content

Commit

Permalink
Final updates to runtime and codegen fixes (#352)
Browse files Browse the repository at this point in the history
Uncovered a few bugs when starting to demonstrate some internal upgrades.
- A few message interface implementation bugs
- Removed files break Buf breaking checks

Puts back a non-null accessor generator option for oneof fields.

New extension number reservation has been approved: protocolbuffers/protobuf#20485
  • Loading branch information
andrewparmet authored Feb 27, 2025
1 parent 1a295b9 commit d5fcf93
Show file tree
Hide file tree
Showing 52 changed files with 2,179 additions and 392 deletions.
26 changes: 21 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ Supports only version 3 of the Protocol Buffers language.

### Features
- Idiomatic and concise [Kotlin builder DSL](#generated-code)
- Protokt-specific options: [non-null types (dangerous)](#non-null-fields),
- Protokt-specific options: [non-null accessors](#non-null-accessors),
[wrapper types](#wrapper-types),
[interface implementation](#interface-implementation),
and more
Expand Down Expand Up @@ -636,8 +636,9 @@ dependencies {
```

Wrapper types that wrap protobuf messages are nullable. For example,
`java.time.Instant` wraps the well-known type `google.protobuf.Timestamp`. They
can be made non-nullable by using the non-null option described below.
`java.time.Instant` wraps the well-known type `google.protobuf.Timestamp`. You
can generate non-null accessors with the `generate_non_null_accessor` option
described below.

Wrapper types that wrap protobuf primitives, for example `java.util.UUID`
which wraps `bytes`, are nullable when they cannot wrap their wrapped type's
Expand All @@ -659,7 +660,8 @@ google.protobuf.BytesValue nullable_uuid = 3 [
];
```
This behavior can be overridden with the [`non_null` option](#non-null-fields).
As for message types, you can generate non-null accessors with the
`generate_non_null_accessor` option.
Wrapper types can be repeated:
Expand Down Expand Up @@ -687,7 +689,7 @@ _N.b. Well-known type nullability is implemented with
for each message defined in
[wrappers.proto](https://github.com/protocolbuffers/protobuf/blob/main/src/google/protobuf/wrappers.proto)._
### Non-null fields
### Non-null accessors
If a message has no meaning whatsoever when a particular non-scalar field is
missing, you can emulate proto2's `required` key word by using the
`(protokt.v1.property).generate_non_null_accessor` option:
Expand All @@ -705,6 +707,20 @@ message NonNullSampleMessage {
Generated code will include a non-null accessor prefixed with `require`, so the field can be referenced
without using Kotlin's `!!`.
This option also works on oneof fields:
```protobuf
message Sample {}
message NonNullSampleMessage {
oneof non_null_sample {
option (protokt.v1.oneof).generate_non_null_accessor = true;
Sample sample = 1;
}
}
```
### Interface implementation
#### Messages
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/src/main/kotlin/RemotePublishing.kt
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ fun Project.enablePublishing(defaultJars: Boolean = true) {
configure(KotlinMultiplatform(JavadocJar.Empty()))
}
pluginManager.withPlugin(KotlinPlugins.JVM) {
configure(KotlinJvm(JavadocJar.Empty(), true))
configure(KotlinJvm(JavadocJar.Empty()))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ allprojects {
targetExclude("buildSrc/build/**")
licenseHeaderFile(
rootProject.file("gradle/license-header-c-style"),
"(package |@file|import |fun )|buildscript |plugins |subprojects |spotless "
"(package |@file|import |fun )|buildscript |plugins |subprojects |spotless |group ="
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 Toast, Inc.
* Copyright (c) 2022 Toast, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -13,6 +13,4 @@
* limitations under the License.
*/

subprojects {
group = "${rootProject.group}.thirdparty"
}
group = "com.toasttab.protokt.thirdparty"
305 changes: 304 additions & 1 deletion extensions/protokt-extensions-lite/api/protokt-extensions-lite.api

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,219 @@
/*
* Copyright (c) 2019 Toast, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

syntax = "proto3";

package protokt;

import "google/protobuf/descriptor.proto";

option java_package = "com.toasttab.protokt.ext";
option java_outer_classname = "ProtoktProto";

option deprecated = true;

message ProtoktFileOptions {
option deprecated = true;

// Specify the Kotlin package for the generated file. Precedence is given
// first to this Kotlin package, then to the Java package if enabled in
// the plugin options, and finally to the protobuf package.
string kotlin_package = 1 [deprecated = true];

// Specify the name of the Kotlin object that contains the reference to this
// file's FileDescriptor object.
string file_descriptor_object_name = 2 [deprecated = true];
}

extend google.protobuf.FileOptions {
ProtoktFileOptions file = 1072 [deprecated = true];
}

message ProtoktMessageOptions {
option deprecated = true;

// Declares that the message class implements an interface. Scoping rules
// are the same as those for declaring wrapper types.
string implements = 1 [deprecated = true];

// Provides a message for deprecation
string deprecation_message = 2 [deprecated = true];
}

extend google.protobuf.MessageOptions {
ProtoktMessageOptions class = 1072 [deprecated = true];
}

message ProtoktFieldOptions {
option deprecated = true;

// Makes a message-type field non-nullable in the generated Kotlin code.
// Beware that deserialization will NPE if the field is missing from the
// protobuf payload. Adding a non-null field to an existing message is a
// backwards-incompatible change.
//
// For example:
//
// message Foo {
// string id = 1 [(protokt.property).non_null = true];
// }
bool non_null = 1 [deprecated = true];

// Expose a wrapper class instead of a raw protobuf type.
//
// For example:
//
// message Foo {
// string id = 1 [(protokt.property).wrap = "com.foo.FooId"];
// }
//
// data class FooId(val value: String)
//
// will yield:
// class Foo(val id: FooId) ...
//
// If the Kotlin package (or Java package, if the Kotlin package is
// unspecified) of this file is the same as the package of the wrapper type,
// full qualification is optional.
//
// This option can be applied to repeated fields.
string wrap = 2 [deprecated = true];

// Maps a bytes field to BytesSlice. If deserialized from a byte array,
// BytesSlice will point to the source array without copying the subarray.
bool bytes_slice = 3 [deprecated = true];

// Provides a message for deprecation
string deprecation_message = 4 [deprecated = true];

// Expose a wrapper class instead of a raw protobuf type for the key type of
// a map.
//
// For example:
//
// message Foo {
// map<string, int32> map = 1 [(protokt.property).key_wrap = "com.foo.FooId"];
// }
//
// data class FooId(val value: String)
//
// will yield:
// class Foo(val map: Map<FooId, String>) ...
//
// Scoping rules are the same as those for declaring regular field wrapper types.
string key_wrap = 5 [deprecated = true];

// Expose a wrapper class instead of a raw protobuf type for the value type of
// a map.
//
// For example:
//
// message Foo {
// map<int32, strig> map = 1 [(protokt.property).value_wrap = "com.foo.FooId"];
// }
//
// data class FooId(val value: String)
//
// will yield:
// class Foo(val map: Map<Int, FooId>) ...
//
// Scoping rules are the same as those for declaring regular field wrapper types.
string value_wrap = 6 [deprecated = true];
}

extend google.protobuf.FieldOptions {
ProtoktFieldOptions property = 1072 [deprecated = true];
}

message ProtoktOneofOptions {
option deprecated = true;

// Makes a oneof field non-nullable in generated Kotlin code. Beware that
// deserialization will NPE if the field is missing from the protobuf payload.
// Adding a non-null field to an existing message is a backwards-incompatible
// change.
//
// For example:
//
// message Message {
// oneof some_field_name {
// option (protokt.oneof).non_null = true;
//
// string id = 1;
// }
// }
//
bool non_null = 1 [deprecated = true];

// Make the sealed class implement an interface, enforcing the presence of a
// property in each possible variant. Scoping rules are the same as those
// for declaring wrapper types.
string implements = 2 [deprecated = true];

// Provides a message for deprecation
string deprecation_message = 3 [deprecated = true];
}

extend google.protobuf.OneofOptions {
ProtoktOneofOptions oneof = 1072 [deprecated = true];
}

message ProtoktEnumOptions {
option deprecated = true;

// Provides a message for deprecation
string deprecation_message = 1 [deprecated = true];
}

extend google.protobuf.EnumOptions {
ProtoktEnumOptions enum = 1072 [deprecated = true];
}

message ProtoktEnumValueOptions {
option deprecated = true;

// Provides a message for deprecation
string deprecation_message = 1 [deprecated = true];
}

extend google.protobuf.EnumValueOptions {
ProtoktEnumValueOptions enum_value = 1072 [deprecated = true];
}

message ProtoktServiceOptions {
option deprecated = true;
}

extend google.protobuf.ServiceOptions {
ProtoktServiceOptions service = 1072 [deprecated = true];
}

message ProtoktMethodOptions {
option deprecated = true;

// Provides a custom request marshaller for the generated method descriptor.
// Substitutes the provided expression directly for
// `com.toasttab.protokt.grpc.KtMarshaller(<request_type>)`
string request_marshaller = 1 [deprecated = true];

// Provides a custom response marshaller for the generated method descriptor.
// Substitutes the provided expression directly for
// `com.toasttab.protokt.grpc.KtMarshaller(<response_type>)`
string response_marshaller = 2 [deprecated = true];
}

extend google.protobuf.MethodOptions {
ProtoktMethodOptions method = 1072 [deprecated = true];
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ message FileOptions {
}

extend google.protobuf.FileOptions {
FileOptions file = 1072;
FileOptions file = 1253;
}

message MessageOptions {
Expand All @@ -42,7 +42,7 @@ message MessageOptions {
}

extend google.protobuf.MessageOptions {
MessageOptions class = 1072;
MessageOptions class = 1253;
}

message FieldOptions {
Expand Down Expand Up @@ -120,11 +120,23 @@ message FieldOptions {
}

extend google.protobuf.FieldOptions {
FieldOptions property = 1072;
FieldOptions property = 1253;
}

message OneofOptions {
reserved 1;
// Generates a non-nullable accessor for a oneof field.
//
// For example:
//
// message Message {
// oneof some_field_name {
// option (protokt.v1.oneof).generate_non_null_accessor = true;
//
// string id = 1;
// }
// }
//
bool generate_non_null_accessor = 1;

// Make the sealed class implement an interface, enforcing the presence of a
// property in each possible variant. Scoping rules are the same as those
Expand All @@ -136,7 +148,7 @@ message OneofOptions {
}

extend google.protobuf.OneofOptions {
OneofOptions oneof = 1072;
OneofOptions oneof = 1253;
}

message EnumOptions {
Expand All @@ -145,7 +157,7 @@ message EnumOptions {
}

extend google.protobuf.EnumOptions {
EnumOptions enum = 1072;
EnumOptions enum = 1253;
}

message EnumValueOptions {
Expand All @@ -154,13 +166,13 @@ message EnumValueOptions {
}

extend google.protobuf.EnumValueOptions {
EnumValueOptions enum_value = 1072;
EnumValueOptions enum_value = 1253;
}

message ServiceOptions {}

extend google.protobuf.ServiceOptions {
ServiceOptions service = 1072;
ServiceOptions service = 1253;
}

message MethodOptions {
Expand All @@ -176,5 +188,5 @@ message MethodOptions {
}

extend google.protobuf.MethodOptions {
MethodOptions method = 1072;
MethodOptions method = 1253;
}
Loading

0 comments on commit d5fcf93

Please sign in to comment.