\u201cA man got to have a code!\u201d - Omar Little
As our teams and programs grow, the variety and volume of data also grows. Success will turn your simple data models into complex ones! Whether your application is storing data to disk or transmitting it over a network, the structure and interpretation of that data should be clear. Consumers work best with data they understand!
Schemas describe and document data models. If you have data, you should have a schema.
Google\u2019s Protocol Buffers are built around a great schema language:
It\u2019s cross platform and language independent. Whatever programming language you use, you\u2019ll be able to use proto schemas with your application.
Proto schemas are backwards-compatible and future-proof. You can evolve your schema as your application loses old features and gains new ones.
It\u2019s focused. Proto schemas describe your data models. That\u2019s it.
Protocol Buffer Examples Here's a [sample message][dinosaur_proto] definition:
syntax = \"proto3\";\n\npackage squareup.dinosaurs;\n\noption java_package = \"com.squareup.dinosaurs\";\n\nimport \"squareup/geology/period.proto\";\n\nmessage Dinosaur {\n // Common name of this dinosaur, like \"Stegosaurus\".\n string name = 1;\n\n // URLs with images of this dinosaur.\n repeated string picture_urls = 2;\n\n squareup.geology.Period period = 5;\n}\n
And here's an [enum][period_proto] definition:
syntax = \"proto3\";\n\npackage squareup.geology;\n\n\noption java_package = \"com.squareup.geology\";\n\nenum Period {\n // 145.5 million years ago \u2014 66.0 million years ago.\n CRETACEOUS = 0;\n\n // 201.3 million years ago \u2014 145.0 million years ago.\n JURASSIC = 1;\n\n // 252.17 million years ago \u2014 201.3 million years ago.\n TRIASSIC = 2;\n}\n
This schema language is Protocol Buffers' best feature. You might even use it purely for documentation purposes, such as to describe a JSON API. Protocol Buffers also defines a compact binary encoding of messages that conform to the schema. This encoding is fast to encode, fast to decode, small to transmit, and small to store. The binary encoding uses numeric tags from the schema, like the `5` for `period` above. For example, let's encode this dinosaur:
The Protocol Buffers schema language and binary encoding are both defined by Google. Wire is an independent implementation from Square that\u2019s specifically designed for Android and Java.
For each message type defined in the schema, Wire generates an immutable model class and its builder. The generated code looks like code you\u2019d write by hand: it\u2019s documented, formatted, and simple. Wire\u2019s APIs should feel at home to programmers who like Effective Java.
That said, there are some interesting design decisions in Wire:
Wire messages declare public final fields instead of the usual getter methods. This cuts down on both code generated and code executed. Less code is particularly beneficial for Android programs.
Wire avoids case mapping. A field declared as picture_urls in a schema yields a Java field picture_urls and not the conventional pictureUrls camel case. Though the name feels awkward at first, it\u2019s fantastic whenever you use grep or more sophisticated search tools. No more mapping when navigating between schema, Java source code, and data. It also provides a gentle reminder to calling code that proto messages are a bit special.
Primitive types are always boxed. If a field is absent, its value is null. This is used for naturally optional fields, such as a dinosaur whose period is unknown. A field may also be null due to schema evolution: if tomorrow we add a carnivore boolean to our message definition, today\u2019s data won\u2019t have a value for that field.
Generated Java Code Here's the compact [generated code][dinosaur_java] for the `Dinosaur` message defined above:
// Code generated by Wire protocol buffer compiler, do not edit.\n// Source: squareup.dinosaurs.Dinosaur in squareup/dinosaurs/dinosaur.proto\npackage com.squareup.dinosaurs;\n\nimport com.squareup.geology.Period;\nimport com.squareup.wire.Message;\nimport com.squareup.wire.ProtoAdapter;\nimport com.squareup.wire.Syntax;\nimport com.squareup.wire.WireField;\nimport com.squareup.wire.internal.Internal;\nimport java.lang.Object;\nimport java.lang.Override;\nimport java.lang.String;\nimport java.util.List;\nimport okio.ByteString;\n\npublic final class Dinosaur extends Message<Dinosaur, Dinosaur.Builder> {\n public static final ProtoAdapter<Dinosaur> ADAPTER = ProtoAdapter.newMessageAdapter(Dinosaur.class, \"type.googleapis.com/squareup.dinosaurs.Dinosaur\", Syntax.PROTO_3);\n\n private static final long serialVersionUID = 0L;\n\n /**\n * Common name of this dinosaur, like \"Stegosaurus\".\n */\n @WireField(\n tag = 1,\n adapter = \"com.squareup.wire.ProtoAdapter#STRING\",\n label = WireField.Label.OMIT_IDENTITY\n )\n public final String name;\n\n /**\n * URLs with images of this dinosaur.\n */\n @WireField(\n tag = 2,\n adapter = \"com.squareup.wire.ProtoAdapter#STRING\",\n label = WireField.Label.REPEATED,\n jsonName = \"pictureUrls\"\n )\n public final List<String> picture_urls;\n\n @WireField(\n tag = 5,\n adapter = \"com.squareup.geology.Period#ADAPTER\",\n label = WireField.Label.OMIT_IDENTITY\n )\n public final Period period;\n\n public Dinosaur(String name, List<String> picture_urls, Period period) {\n this(name, picture_urls, period, ByteString.EMPTY);\n }\n\n public Dinosaur(String name, List<String> picture_urls, Period period, ByteString unknownFields) {\n super(ADAPTER, unknownFields);\n if (name == null) {\n throw new IllegalArgumentException(\"name == null\");\n }\n this.name = name;\n this.picture_urls = Internal.immutableCopyOf(\"picture_urls\", picture_urls);\n if (period == null) {\n throw new IllegalArgumentException(\"period == null\");\n }\n this.period = period;\n }\n\n @Override\n public Builder newBuilder() {\n Builder builder = new Builder();\n builder.name = name;\n builder.picture_urls = Internal.copyOf(picture_urls);\n builder.period = period;\n builder.addUnknownFields(unknownFields());\n return builder;\n }\n\n @Override\n public boolean equals(Object other) {\n if (other == this) return true;\n if (!(other instanceof Dinosaur)) return false;\n Dinosaur o = (Dinosaur) other;\n return unknownFields().equals(o.unknownFields())\n && Internal.equals(name, o.name)\n && picture_urls.equals(o.picture_urls)\n && Internal.equals(period, o.period);\n }\n\n @Override\n public int hashCode() {\n int result = super.hashCode;\n if (result == 0) {\n result = unknownFields().hashCode();\n result = result * 37 + (name != null ? name.hashCode() : 0);\n result = result * 37 + picture_urls.hashCode();\n result = result * 37 + (period != null ? period.hashCode() : 0);\n super.hashCode = result;\n }\n return result;\n }\n\n public static final class Builder extends Message.Builder<Dinosaur, Builder> {\n public String name;\n\n public List<String> picture_urls;\n\n public Period period;\n\n public Builder() {\n name = \"\";\n picture_urls = Internal.newMutableList();\n period = Period.CRETACEOUS;\n }\n\n /**\n * Common name of this dinosaur, like \"Stegosaurus\".\n */\n public Builder name(String name) {\n this.name = name;\n return this;\n }\n\n /**\n * URLs with images of this dinosaur.\n */\n public Builder picture_urls(List<String> picture_urls) {\n Internal.checkElementsNotNull(picture_urls);\n this.picture_urls = picture_urls;\n return this;\n }\n\n public Builder period(Period period) {\n this.period = period;\n return this;\n }\n\n @Override\n public Dinosaur build() {\n return new Dinosaur(name, picture_urls, period, super.buildUnknownFields());\n }\n }\n}\n
The Java code to create and access proto models is compact and readable:
Dinosaur stegosaurus = new Dinosaur.Builder()\n .name(\"Stegosaurus\")\n .period(Period.JURASSIC)\n .build();\n\nSystem.out.println(\"My favorite dinosaur existed in the \" + stegosaurus.period + \" period.\");\n
Each type has a corresponding `ProtoAdapter` that can encode a message to bytes and decode bytes back into a message.
Since version 3.0.0, Wire can generate Kotlin code. See Wire Compiler & Gradle Plugin to learn how to configure your build.
Kotlin is a pragmatic and expressive programming language that makes it easy to model data. Here\u2019s how we used Kotlin to model Protocol Buffers messages:
Messages feel like data classes, but in fact they\u2019re not. Compiler still generates equals(), hashCode(), toString() and copy() for you. Wire does not generate componentN() functions though, we believe that destructuring declarations are not a good fit for Protocol Buffers: a change in the schema that removes or adds a field might lead to a situation when your destructuring declaration still compiles but now describes a completely different subset of fields, rendering your code incorrect.
copy() is a substitute for the Builder, which is not used anymore. If your program relies on the Builder to be present, you may generate code in Java interoperability mode - Wire Compiler & Gradle Plugin explains how that works.
Fields are generated as properties. While this is idiomatic in Kotlin, Java code will now have to access fields using getters. If your program relies on accessing fields directly, use Java interoperability mode - the compiler will generate @JvmField annotations for each field.
The nullability of each field\u2019s type depends on its label: required, repeated and map fields get non-nullable types, whereas optional fields are of nullable types.
With the exception of required fields, each field has a default value:
null for optional fields,
emptyList() for repeated fields,
emptyMap() for map fields.
Generated Kotlin Code Here's the compact [generated code][dinosaur_kotlin] for the `Dinosaur` message defined above:
// Code generated by Wire protocol buffer compiler, do not edit.\n// Source: squareup.dinosaurs.Dinosaur in squareup/dinosaurs/dinosaur.proto\npackage com.squareup.dinosaurs\n\nimport com.squareup.geology.Period\nimport com.squareup.wire.FieldEncoding\nimport com.squareup.wire.Message\nimport com.squareup.wire.ProtoAdapter\nimport com.squareup.wire.ProtoReader\nimport com.squareup.wire.ProtoWriter\nimport com.squareup.wire.Syntax.PROTO_3\nimport com.squareup.wire.WireField\nimport com.squareup.wire.internal.immutableCopyOf\nimport com.squareup.wire.internal.sanitize\nimport kotlin.Any\nimport kotlin.AssertionError\nimport kotlin.Boolean\nimport kotlin.Deprecated\nimport kotlin.DeprecationLevel\nimport kotlin.Int\nimport kotlin.Long\nimport kotlin.Nothing\nimport kotlin.String\nimport kotlin.collections.List\nimport kotlin.hashCode\nimport kotlin.jvm.JvmField\nimport okio.ByteString\n\nclass Dinosaur(\n /**\n * Common name of this dinosaur, like \"Stegosaurus\".\n */\n @field:WireField(\n tag = 1,\n adapter = \"com.squareup.wire.ProtoAdapter#STRING\",\n label = WireField.Label.OMIT_IDENTITY\n )\n val name: String = \"\",\n picture_urls: List<String> = emptyList(),\n @field:WireField(\n tag = 5,\n adapter = \"com.squareup.geology.Period#ADAPTER\",\n label = WireField.Label.OMIT_IDENTITY\n )\n val period: Period = Period.CRETACEOUS,\n unknownFields: ByteString = ByteString.EMPTY\n) : Message<Dinosaur, Nothing>(ADAPTER, unknownFields) {\n /**\n * URLs with images of this dinosaur.\n */\n @field:WireField(\n tag = 2,\n adapter = \"com.squareup.wire.ProtoAdapter#STRING\",\n label = WireField.Label.REPEATED,\n jsonName = \"pictureUrls\"\n )\n val picture_urls: List<String> = immutableCopyOf(\"picture_urls\", picture_urls)\n\n @Deprecated(\n message = \"Shouldn't be used in Kotlin\",\n level = DeprecationLevel.HIDDEN\n )\n override fun newBuilder(): Nothing = throw AssertionError()\n\n override fun equals(other: Any?): Boolean {\n if (other === this) return true\n if (other !is Dinosaur) return false\n if (unknownFields != other.unknownFields) return false\n if (name != other.name) return false\n if (picture_urls != other.picture_urls) return false\n if (period != other.period) return false\n return true\n }\n\n override fun hashCode(): Int {\n var result = super.hashCode\n if (result == 0) {\n result = unknownFields.hashCode()\n result = result * 37 + name.hashCode()\n result = result * 37 + picture_urls.hashCode()\n result = result * 37 + period.hashCode()\n super.hashCode = result\n }\n return result\n }\n\n override fun toString(): String {\n val result = mutableListOf<String>()\n result += \"\"\"name=${sanitize(name)}\"\"\"\n if (picture_urls.isNotEmpty()) result += \"\"\"picture_urls=${sanitize(picture_urls)}\"\"\"\n result += \"\"\"period=$period\"\"\"\n return result.joinToString(prefix = \"Dinosaur{\", separator = \", \", postfix = \"}\")\n }\n\n fun copy(\n name: String = this.name,\n picture_urls: List<String> = this.picture_urls,\n period: Period = this.period,\n unknownFields: ByteString = this.unknownFields\n ): Dinosaur = Dinosaur(name, picture_urls, period, unknownFields)\n\n companion object {\n @JvmField\n val ADAPTER: ProtoAdapter<Dinosaur> = object : ProtoAdapter<Dinosaur>(\n FieldEncoding.LENGTH_DELIMITED,\n Dinosaur::class,\n \"type.googleapis.com/squareup.dinosaurs.Dinosaur\",\n PROTO_3,\n null\n ) {\n override fun encodedSize(value: Dinosaur): Int {\n var size = value.unknownFields.size\n if (value.name != \"\") size += ProtoAdapter.STRING.encodedSizeWithTag(1, value.name)\n size += ProtoAdapter.STRING.asRepeated().encodedSizeWithTag(2, value.picture_urls)\n if (value.period != Period.CRETACEOUS) size += Period.ADAPTER.encodedSizeWithTag(5,\n value.period)\n return size\n }\n\n override fun encode(writer: ProtoWriter, value: Dinosaur) {\n if (value.name != \"\") ProtoAdapter.STRING.encodeWithTag(writer, 1, value.name)\n ProtoAdapter.STRING.asRepeated().encodeWithTag(writer, 2, value.picture_urls)\n if (value.period != Period.CRETACEOUS) Period.ADAPTER.encodeWithTag(writer, 5, value.period)\n writer.writeBytes(value.unknownFields)\n }\n\n override fun decode(reader: ProtoReader): Dinosaur {\n var name: String = \"\"\n val picture_urls = mutableListOf<String>()\n var period: Period = Period.CRETACEOUS\n val unknownFields = reader.forEachTag { tag ->\n when (tag) {\n 1 -> name = ProtoAdapter.STRING.decode(reader)\n 2 -> picture_urls.add(ProtoAdapter.STRING.decode(reader))\n 5 -> try {\n period = Period.ADAPTER.decode(reader)\n } catch (e: ProtoAdapter.EnumConstantNotFoundException) {\n reader.addUnknownField(tag, FieldEncoding.VARINT, e.value.toLong())\n }\n else -> reader.readUnknownField(tag)\n }\n }\n return Dinosaur(\n name = name,\n picture_urls = picture_urls,\n period = period,\n unknownFields = unknownFields\n )\n }\n\n override fun redact(value: Dinosaur): Dinosaur = value.copy(\n unknownFields = ByteString.EMPTY\n )\n }\n\n private const val serialVersionUID: Long = 0L\n }\n}\n
Creating and accessing proto models is easy:
val stegosaurus = Dinosaur(\n name = \"Stegosaurus\",\n period = Period.JURASSIC\n)\n\nprintln(\"My favorite dinosaur existed in the ${stegosaurus.period} period.\")\n
Here's how you can modify the object to add extra fields:
val stegosaurus = stegosaurus.copy(\n picture_urls = listOf(\"https://www.flickr.com/photos/tags/Stegosaurus/\")\n)\n\nprintln(\"Here are some photos of ${stegosaurus.name}: ${stegosaurus.picture_urls}\")\n
Since version 3.3.0, Wire can generate Swift code. See Wire Compiler & Gradle Plugin to learn how to configure your build.
Swift support is considered a \u201cbeta\u201d and may still feature breaking changes. That being said, Block is shipping it in production apps and SDKs.
Swift is a pragmatic and expressive programming language with rich support for value types. Here\u2019s how we used Swift to model Protocol Buffers messages:
Messages are structs that conform to Equatable, Codable and Sendable. All Messages have value semantics.
Fields are generated as properties.
The nullability of each field\u2019s type depends on its label: required, repeated and map fields get non-nullable types, whereas optional fields are of nullable types.
Generated Swift Code Here's the compact [generated code][dinosaur_swift] for the `Dinosaur` message defined above:
// Code generated by Wire protocol buffer compiler, do not edit.\n// Source: squareup.dinosaurs.Dinosaur in squareup/dinosaurs/dinosaur.proto\nimport Foundation\nimport Wire\n\npublic struct Dinosaur {\n\n /**\n * Common name of this dinosaur, like \"Stegosaurus\".\n */\n @ProtoDefaulted\n public var name: String?\n /**\n * URLs with images of this dinosaur.\n */\n public var picture_urls: [String] = []\n @ProtoDefaulted\n public var length_meters: Double?\n @ProtoDefaulted\n public var mass_kilograms: Double?\n public var period: Period?\n public var unknownFields: Foundation.Data = .init()\n\n public init(configure: (inout Self) -> Swift.Void = { _ in }) {\n configure(&self)\n }\n\n}\n\n#if !WIRE_REMOVE_EQUATABLE\nextension Dinosaur : Equatable {\n}\n#endif\n\n#if !WIRE_REMOVE_HASHABLE\nextension Dinosaur : Hashable {\n}\n#endif\n\nextension Dinosaur : Sendable {\n}\n\nextension Dinosaur : ProtoDefaultedValue {\n\n public static var defaultedValue: Dinosaur {\n Dinosaur()\n }\n}\n\nextension Dinosaur : ProtoMessage {\n\n public static func protoMessageTypeURL() -> String {\n return \"type.googleapis.com/squareup.dinosaurs.Dinosaur\"\n }\n\n}\n\nextension Dinosaur : Proto2Codable {\n\n public init(from protoReader: ProtoReader) throws {\n var name: String? = nil\n var picture_urls: [String] = []\n var length_meters: Double? = nil\n var mass_kilograms: Double? = nil\n var period: Period? = nil\n\n let token = try protoReader.beginMessage()\n while let tag = try protoReader.nextTag(token: token) {\n switch tag {\n case 1: name = try protoReader.decode(String.self)\n case 2: try protoReader.decode(into: &picture_urls)\n case 3: length_meters = try protoReader.decode(Double.self)\n case 4: mass_kilograms = try protoReader.decode(Double.self)\n case 5: period = try protoReader.decode(Period.self)\n default: try protoReader.readUnknownField(tag: tag)\n }\n }\n self.unknownFields = try protoReader.endMessage(token: token)\n\n self._name.wrappedValue = name\n self.picture_urls = picture_urls\n self._length_meters.wrappedValue = length_meters\n self._mass_kilograms.wrappedValue = mass_kilograms\n self.period = period\n }\n\n public func encode(to protoWriter: ProtoWriter) throws {\n try protoWriter.encode(tag: 1, value: self.name)\n try protoWriter.encode(tag: 2, value: self.picture_urls)\n try protoWriter.encode(tag: 3, value: self.length_meters)\n try protoWriter.encode(tag: 4, value: self.mass_kilograms)\n try protoWriter.encode(tag: 5, value: self.period)\n try protoWriter.writeUnknownFields(unknownFields)\n }\n\n}\n\n#if !WIRE_REMOVE_CODABLE\nextension Dinosaur : Codable {\n\n public init(from decoder: Decoder) throws {\n let container = try decoder.container(keyedBy: StringLiteralCodingKeys.self)\n self._name.wrappedValue = try container.decodeIfPresent(String.self, forKey: \"name\")\n self.picture_urls = try container.decodeProtoArray(String.self, firstOfKeys: \"pictureUrls\", \"picture_urls\")\n self._length_meters.wrappedValue = try container.decodeIfPresent(Double.self, firstOfKeys: \"lengthMeters\", \"length_meters\")\n self._mass_kilograms.wrappedValue = try container.decodeIfPresent(Double.self, firstOfKeys: \"massKilograms\", \"mass_kilograms\")\n self.period = try container.decodeIfPresent(Period.self, forKey: \"period\")\n }\n\n public func encode(to encoder: Encoder) throws {\n var container = encoder.container(keyedBy: StringLiteralCodingKeys.self)\n let preferCamelCase = encoder.protoKeyNameEncodingStrategy == .camelCase\n let includeDefaults = encoder.protoDefaultValuesEncodingStrategy == .include\n\n try container.encodeIfPresent(self.name, forKey: \"name\")\n if includeDefaults || !self.picture_urls.isEmpty {\n try container.encodeProtoArray(self.picture_urls, forKey: preferCamelCase ? \"pictureUrls\" : \"picture_urls\")\n }\n try container.encodeIfPresent(self.length_meters, forKey: preferCamelCase ? \"lengthMeters\" : \"length_meters\")\n try container.encodeIfPresent(self.mass_kilograms, forKey: preferCamelCase ? \"massKilograms\" : \"mass_kilograms\")\n try container.encodeIfPresent(self.period, forKey: \"period\")\n }\n\n}\n#endif\n
Creating and accessing proto models is easy:
let stegosaurus = Dinosaur {\n $0.name = \"Stegosaurus\"\n $0.period = .JURASSIC\n}\n\nprint(\"My favorite dinosaur existed in the \\(stegosaurus.period) period.\")\n
Here's how you can modify the object to add extra fields:
var stegosaurus = stegosaurus\nstegosaurus.picture_urls = [\"https://www.flickr.com/photos/tags/Stegosaurus/\"]\n\nprint(\"Here are some photos of \\(stegosaurus.name): \\(stegosaurus.picture_urls)\")\n
"},{"location":"#generating-code-with-wire","title":"Generating Code With Wire","text":"
Wire can read .proto files from the local file system and from within .jar files.
The compiler can optionally prune your schema to a subset of root types and their transitive dependencies. This is useful when sharing a schema between projects: a Java service and Android app may each use a subset of a larger shared schema.
For more info on how to get started, see Wire Compiler & Gradle Plugin.
If you don\u2019t use Gradle, the compiler also has a command line interface. Just substitute wire-compiler-VERSION-jar-with-dependencies.jar with the path to your jar. Download the latest precompiled jar.
% java -jar wire-compiler-VERSION-jar-with-dependencies.jar \\\n --proto_path=src/main/proto \\\n --java_out=out \\\n squareup/dinosaurs/dinosaur.proto \\\n squareup/geology/period.proto\nWriting com.squareup.dinosaurs.Dinosaur to out\nWriting com.squareup.geology.Period to out\n
Supplying the --android flag to the compiler causes Wire messages to implement Parcelable.
If you use Proguard, then you need to add keep rules. The simplest option is to tell Proguard not to touch the Wire runtime library and your generated protocol buffers (of course these simple rules will miss opportunities to shrink and optimize the code):
-keep class com.squareup.wire.** { *; }\n-keep class com.yourcompany.yourgeneratedcode.** { *; }\n
Groups - they are skipped when parsing binary input data
Wire supports custom options on messages and fields. Other custom options are ignored. Pass --excludes=google.protobuf.* to the compiler to omit options from the generated code.
expose the grpc url when converting Response to GrpcException (#2920 by Travis Johnson)
Support very long field names with builders (#2959)
New enumMode option added to Kotlin targets in order to generate enum types as sealed classes. Its value can be either enum_class (default value) or sealed_class. enum_class will generate enum types as Kotlin enum classes, which is the current behavior. sealed_class will generate enum types as Kotlin sealed classes, generated each constant of the enum type as data objects. On top of those constants, the sealed class will contain a Unrecognized data class which will contain the real decoded value for this enum if the runtime didn\u2019t have any constant matching it. This is the analogue feature of protoc generating a UNRECOGNIZED(-1) constant for enums on proto3. Note however that Wire doesn\u2019t limit this option to proto3 enums, this can be used for proto2 enums too.
Switching to generating sealed class for enums can break the call-site for your consumers. In order to allow gradual migration of enum generation from/to sealed classes, a Protobuf enum option has also been created. This, when set in the .proto file, takes precedence over the global enum mode.
import \"wire/extensions.proto\";\n\nenum Period {\n option (wire.enum_mode) = \"sealed_class\"; // or `enum_class`.\n CRETACEOUS = 1;\n JURASSIC = 2;\n TRIASSIC = 3;\n}\n
\u26a0 Reject unused prunes and roots by default (#2846) This behavior used to be opt-in, now it\u2019s opt-out. You can opt out with rejectUnusedRootsOrPrunes = false in your wire { } block.
\u26a0 Remove deprecated SchemaHandler#create method (#2851) Override the other method create(includes, excludes, exclusive, outDirectory, options): SchemaHandler instead if you were not already doing it.
\u26a0 Adding a project dependency via srcJar used to work but not anymore. Use srcProject(\":my-project\") instead.
Don\u2019t warn about an unused emitting rule, when that rule is \u2018*\u2019 (#2829)
The internal of our Wire Gradle plugin has been refactored where behavior changes should not be expected. If you see anything different, please let us know.
Allow custom options to be passed in WireCompiler (#2909)
Propagates Request timeout as grpc-timeout (#2840 by Francisco Rojas)
Don\u2019t override RealGrpcCall.timeout when it\u2019s manually set (#2893 by Jeff Gulbronson)
Publish the gRPC Dispatcher (#2872) A new helper class GrpcDispatcher for gRPC testing is available under com.squareup.wire:wire-grpc-mockwebserver. Note that it does not support streaming calls. If you want to contribute, please do!
\u26a0 Refactored how extensions are emitted and provides a new API to get/set extension fields. Due to the refactor above, Codable fields that are defined in extensions will now break as part of this change. All done by Dimitris Koutsogiorgas and Adam Lickel!
\u26a0 wire-grpc-server has been moved into its own repo: https://github.com/square/wire-grpc-server. If you were using it, you can see how migration is to happen by checking these instructions.
Generate Grpc SERVICE_NAME as const (#2773 by Marius Volkhart)
Use %N in KotlinGenerator to ensure names are escaped (#2784 by Egor Andreevich)
Add escapeKotlinKeywords parameter to Kotlin target (#2785 by Egor Andreevich)
You can now set escapeKotlinKeywords = true within our kotlin {} targets to escape Kotlin keywords with backticks rather than having them suffixed with an _.
Don\u2019t retransmit a PipeDuplexRequestBody (#2791)
We had crashes that occurred when OkHttp attempted to retry sending the request body of a gRPC streaming connection.
Breaking: Encoding and decoding of negative Int32s was broken in Swift and did not match protobuf spec. Negative Int32s are now correctly encoded as unsigned Int64s. Prior versions of Wire that have serialized a proto containing negative Int32 fields will not be correctly decoded using this version onwards.
Fix: Swift ProtoDefaulted was incorrectly applied in cross-module contexts
Fix: Message\u2019s Builder won\u2019t break compilation on multiplatform projects.
Fix: No hanging anymore on gRPC when receiving an unexpected response.
New: Opaque types. You can now specify types you want Wire to evaluate as being of type bytes. On code generation, the fields of such types will be using the platform equivalent of bytes, like okio.ByteString for the JVM. Use this if there\u2019s a dependency heavy type which you do not use. Note that scalar types cannot be opaqued.
New: Adds a closure into generate types allowing the creation of an instance via the Kotlin DSL.
Fix: Don\u2019t arbitrarily prune oneOf options.
Change: Swift Defaulted has been renamed CustomDefaulted
New: Swift ProtoDefaulted property wrapper and ProtoDefaultedValue protocol
Similar to `CustomDefaulted, this adds as projection of the protocol defined default value
This should not take up any additional storage
This is attached to optional scalar values and messages with entirely optional values
New: ProtoDefaulted and CustomDefaulted include setter support
This enables you to do something like Foo().$bar.$baz += 1
Change: Swift ProtoEnum types now have a raw value of Int32.
The runtime and generated code both need to be updated to reflect this.
New: Swift messages now have the form init(REQUIRED FIELDS, (inout Storage) -> Void)
New: Swift, the member-wise initializer has been removed by default. It can be re-enabled by defining WIRE_INCLUDE_MEMBERWISE_INITIALIZER; however, it will be removed in November 2024. See https://github.com/square/wire/pull/2561 for details
Fix: Correctly define sources folders vs. resources folders for Wire generated code.
Fix: Generated .proto are correctly added to the built artifact.
New: All options of KotlinTarget available on CLI.
Fix: JSON to Kotlin deserialization is now really bullet-proofed against Class.getDeclaredFields random ordering.
Fix: proto3 types (Duration, Struct, etc) are now supported when doing dynamic serialization.
Fix: GrpcStatus is now serializable which enables GrpcException serialization.
New: GrpcClient is now abstract. You can customize how network calls are implemented.
New: You can now pass an event listener to receive metric events.
New: New option for the Wire Gradle plugin. rejectUnusedRootsOrPrunes = true will fail the build if any roots or prunes are not used when refactoring the schema. This can help discover incorrect configurations early and avoid mis-expectations about the built schema.
New: OneOf\u2019s options are now loaded to the schema.
New: Wire will now fail if it detects a type name collision which can happen if a same file is loaded from different paths.
New: wire-schema-tests is now multiplatform.
New: SchemaHandler.Factory can now receive payload set within the Wire Gradle plugin. Implement the method fun create(includes, excludes, exclusive, outDirectory. options): SchemaHandler to receive it.
New: custom targets can now pass custom payloads to their SchemaHandler.Factory. The custom {} takes a map to its new field options.
Swift: Default values are now generated via a Defaulted property wrapper.
Swift: Fully-qualify Foundation.Data to prevent name collisions with messages named Data.
Move: Some types have been moved from wire-compiler to wire-run: WireRun, Target, DirectedAcyclicGraph, PartitionedSchema.
New: Add a dry run option. If enabled, the compiler will just emit the names of the source files that would be otherwise * generated to stdout. You can use the flag --dry_run with the Wire compiler or define the option with Gradle as the following:
wire {\n dryRun = true\n}\n
* Fix: Correctly set task dependencies on processResources if protoLibrary is set to true. * Fix: If a valid grpc-status header is present, raise a GrpcException rather than an IOException."},{"location":"changelog/#version-462","title":"Version 4.6.2","text":"
2023-05-11
Fix: Explicitly adds jvm variants of multiplatform artifacts into the BOM.
Fix: Produce Descriptors for messages without fields after pruning.
Fix: the version 4.5.6 had a breaking change which has been reverted in 4.6.0 without losing any functionality.
Update descriptor.proto from the 7dbe742 version of protocolbuffers/protobuf.
"},{"location":"changelog/#version-456-note-that-this-holds-a-breaking-change-update-directly-to-460-to-avoid-it","title":"Version 4.5.6 (Note that this holds a breaking change, update directly to 4.6.0 to avoid it.)","text":"
2023-04-25
Fix: JSON serialization is now bullet-proofed against Class.getDeclaredFields random ordering.
Perf: Add option wire.use_array to use primitive arrays for packed scalars. This should improve performances as it avoids autoboxing on the JVM. It will use the appropriate array type, for example repeated float would be represented as a FloatArray.
New: Check HTTP2 protocol is set for passed client to GrpcClient.
New: Add buildersOnly option for Java and Kotlin target, setting it to true will change the visibility of generate types\u2019 constructor to non-public.
Fix: Properly define api dependency for okio in wire-schema.
Fix: Sort input locations so they match on all platforms.
Fix: Avoid NPEs with kotlin 1.7.20 around source sets.
New: Custom schema handlers! Wire lets you now plug in your own logic to deal with the protobuf schema the way you want. Check our documentation for details. You can also check our recipe directory for examples. Note that this API obsoletes the CustomHandlerBeta type Wire had until now.
New: You can now easily create an in-memory protobuf schema with the new SchemaBuilder class. This lives in the new wire-schema-tests artifact. For usage examples, check the tests in custom handler recipes.
Breaking: the wire-profiles artifact has been removed and is now inlined in wire-schema.
Breaking: CoreLoader \u2018s isWireRuntimeProto methods are now static.
Breaking: SchemaLoader and related classes have been moved from wire-compiler to wire-schema.
New: Support packed and map fields when converting to/from JSON with Kotlin.
New: Support typesafe accessors and version catalogs in Wire plugin.
New: Generate annotations for repeated options.
New: Allow parsing of oneof options.
New: Support map fields in options.
New: Add macosArm64 support to the KMP projects supporting mac.
Fix: Properly deal with maps of scalar types, deserializing missing scala key/value into identity.
Fix: Fix a crash where ProtoMember was populated with the wrong data.
New: Publish a bill of materials (BOM) for Wire. Depend on this from Gradle or Maven to keep all of your Wire artifacts on the same version, even if they\u2019re declared via transitive dependencies. You can even omit versions when declaring other Wire dependencies.
dependencies {\n implementation(platform(\"com.squareup.wire:wire-bom:4.2.0\"))\n implementation(\"com.squareup.wire:wire-compiler\") // No version!\n implementation(\"com.squareup.wire:wire-gradle-plugin\") // No version!\n implementation(\"com.squareup.wire:wire-grpc-client\") // No version!\n // Etc.\n}\n
New: When using Wire JSON factories, you can now override the proto3 behavior of skipping default values when writing JSON. Set writeIdentityValues to true for either WireJsonAdapterFactory or WireTypeAdapterFactory to enable it.
Breaking: WireLogger methods has been refactored to remove platform dependencies and allow more precise callbacks. We might add new methods in the future for better logging still.
Removal: The dry-run option on WireCompiler has been removed.
Swift: WireCompiler podspec is now backup by a jar so consumers will not have to locally build it on pod install.
New: Add \u2018nameSuffix\u2019 parameter for configuring generated service-class names in Kotlin.
New: Define oneofName in @WireField.
New: Enable iosSimulatorArm64 for Kotlin multiplatform.
New: Expose the source .proto file at ProtoAdaper.sourceFile. This is null for built-in types and types generated prior to this release.
New: Generate Kotlin code whose members match the declaration order of the corresponding .proto files. In previous releases, generated members were sorted by kind (fields, oneofs), then by declaration order. With this update only declaration order is used. Note that this will change the encoded-bytes of these messages. This change is both forwards and backwards-compatible. Identical encoding of equal messages across Wire releases is typical but not guaranteed, and this is a rare release that changes that encoding. If you do cryptographic hashes on encoded proto messages, you will notice that the hashes are different in this release.
New: Option in SchemaLoader to exhaustively load imported files. By default we only load what\u2019s immediately necessary to generate code; this new option loads everything reachable into the schema.
New: Programmatic API to prune schemas. See Pruner in wire-schema.
New: SchemaLoader doesn\u2019t extend the Closeable interface anymore.
New: Support rpcRole = 'none' in the Gradle plugin to generate neither client nor server code.
New: Support for Android variants.
New: Support for glob syntax in srcJar includes.
New: Support for special float literals.
New: Swift support Timestamp and Duration.
New: The Wire plugin requires an output to be set. Before, it would generate Java code by default; it will now throw if there are no output defined.
New: The default value of emitAppliedOptions for our Java and Kotlin target is now set to true.
New: Wire should build and execute properly on Windows.
New: @WireRpc has a new sourceFile attribute.
New: GrpcClient.Builder.minMessageToCompress() configures which messages are compressed. This will completely disable compression if the size is Long.MAX_VALUE. We\u2019ve seen problems where some Golang gRPC servers don\u2019t support compression; setting this to MAX_VALUE is necessary to interop with them.
New: SchemaReflector is our initial implementation of the gRPC Server Reflection Protocol. Note that although we implement the business logic of gRPC reflection, we don\u2019t offer a gRPC server built into Wire.
New: wire-reflector bundles gRPC\u2019s reflection.proto which it is built upon.
New: wire-runtime exposes a com.squareup.wire.VERSION constant reflecting the project version.
New: change the Gradle plugin so that (unstable) custom handlers can be configured with instance instead of with a class name.
Fix: Be more aggressive about loading transitive files with SchemaLoader.loadExhaustively.
Fix: Bugs in JSON serialization of builder-less Kotlin types have been addressed.
Fix: Compile Kotlin/JS with both LEGACY and IR compilers.
Fix: Deep copy metadata on GrpcCall.clone().
Fix: Don\u2019t break task caching by using absolute paths in the Gradle plugin. Wire now uses project-relative paths in any attribute that is used as a cache key.
Fix: Don\u2019t crash encoding schemas when an option contains a repeated field, an enum, or a double.
Fix: Don\u2019t depend on moshi-kotlin in wire-moshi. This caused a transitive dependency on kotlin-reflect, which we neither needed nor wanted.
Fix: Don\u2019t generate invalid code when an enum constant is named name or ordinal.
Fix: Don\u2019t re-use the cache if protobuf inputs have changed.
Fix: Emitting proper protobuf format for option values defined as a list of enum constants.
Fix: Explicitly defined Wire gRPC server generation as experimental: the feature isn\u2019t complete.
Fix: Generate @Deprecated annotations on deprecated messages, fields, enums, and enum constants.
Fix: Handle out of order proto fields when initializing Kotlin constructors.
Fix: Handle writing/reading exceptions for duplex calls in Wire gRPC.
Fix: In Java, rename instances to avoid field and class name conflicts.
Fix: Locate files in the root package when importing.
Fix: Memory fixes found with Address Sanitizer in Swift.
Fix: Permit values other than 0 and 1 when decoding protobuf-encoded booleans. Previously we threw an IOException for other values; now all non-zero values are true.
Fix: Redact boxed OneOf fields.
Fix: Redacted Kotlin scalars now respect nullability.
Fix: Retain field order when emitting a schema as .proto files.
Fix: Reverse the topological sort of dependent files in SchemaReflector. We had problems with grpc-curl which expects the requested file to be listed first.
Fix: Support Kotlin-generated annotations on Java fields.
Fix: Support for serializing builder-less Kotlin generated classes to JSON.
Fix: Support reporting errors in CustomHandlerBeta.
Fix: Suppress deprecation warnings on generated enum\u2019s fromValue method in Kotlin.
Fix: Swift adapters will throw an error when encountering an unexpected ProtoReader.beginMessage() rather than calling fatalError().
Fix: Update the Wire Gradle plugin to clear the output directory before generating code. This prevents the need to do a clean build after removing a message type.
Fix: Update the Wire Gradle plugin to register generated .java sources with the Java compiler. Previously this was broken if the Kotlin plugin was installed.
Fix: Use Gradle\u2019s logging mechanism to reduce output when Wire generates code.
Fix: Use correct type when referencing a custom adapter in Kotlin generated code.
Fix: Use relative path sensitivity and file collection.
Fix: Validate enum constant uniqueness for the entire package.
Fix: Wire Gradle plugin tasks have been modernized with configuration caching support.
Fix: Wire will not generate respective built-in types for Java, Kotlin, and Swift generation. Those are usually the google types for which Wire will provide its own implementation.
Upgrade: Update KotlinPoet to 1.8.0.
Upgrade: OkHttp 4.9.3.
Upgrade: Okio 3.0.0. We now use Okio 3\u2019s FileSystem in SchemaLoader, which makes it easier to load .proto files from the classpath. This is binary-incompatible with the Okio 3.0 alpha releases.
New: srcProject(\":project-name\") makes it easier to depend on .proto files of other projects.
Fix: Don\u2019t require source that .proto directories exist at Gradle plugin configuration time. This was preventing Wire from using other tasks\u2019 outputs as its inputs.
Fix: The Wire Gradle plugin now supports Java only Android projects.
Fix: In the Wire Gradle plugin, sourcePath will now include only protos defined with include if the option is present. It used to include all existing .proto files even if include was used.
New: Full support Optional Int64 and UInt64 for JSONString in Swift.
New: Automatically add a dependency when a protoPath or protoSource depends on a project.
New: protoPath and protoSource dependencies are now not transitive by default.
New: New protoLibrary option for the Wire Gradle plugin. Configuring a project as a protoLibrary will cause the generated .jar file to include .proto sources.
New: Code generation for plain gRPC server. The Kotlin target now has a new grpcServerCompatible option which if set to true will generate gRPC server-compatible classes.
New: Introduce GrpcException.
New: Add GrpcMethod tag to the request.
New: Adds redacting support for Moshi JSON adapters.
New: Publish plugin marker for Gradle plugin.
Fix: Escape square brackets in Kotlin generated code documentation.
New: Proto3 support! This includes the new behaviors, the new types, and the JSON.
New: Swift support for proto2 schemas. The details are in our blog post.
New: Wire will now throw an error when:
two generated files end up overriding each other,
imports form a cycle,
packages form a cycle. This can be turned off with the flag permitPackageCycles,
an option within the source set cannot be resolved,
there are name duplications of members in a message, or of rpcs in a service,
a map is used as an extension.
New: Support for the json_name pseudo option.
New: The wire_package file option allows one to set the JVM package where classes generated from the concerned file will be placed. wire_package takes precedence over java_package.
New: Lists and maps in Kotlin generated code are now immutable.
New: Support UTF-8 with BOM in proto files.
New: wire.since and wire.until have been renamed with the prefix constant_ for EnumValueOptions.
New: Wire generates 1) annotations for options which 2) gets assigned to the generated code where appropriate. Both behavior can be turn on or off via the flags:
emitDeclaredOptions: True to emit types for options declared on messages, fields, etc. Default to true,
emitAppliedOptions: True to emit annotations for options applied on messages, fields, etc. Default to false.
Fix: Recursive map values.
Fix: Long expressions in equals and encodedSize functions.
New: onlyVersion option on the Wire Gradle plugin to target a unique version. By and large, service code that supports many clients would target ranges via sinceVersion and untilVersion, while client code would target a unique version via onlyVersion.
New: Support for optional fields in Proto3.
Fix: Restored the GrpcClient.create API to create implementations for gRPC interfaces.
New: wire.since and wire.until options on members and enum values. You can prune fields or constants using these two options. When generating code with the Wire Gradle plugin, define sinceVersion and/or untilVersion to scope the generated code.
New: Messages\u2019 toString method on Kotlin and Java now escape string values for easy parsing.
Fix: Link the entire descriptor.proto every time when building the Schema.
Fix: Properly handle members named after keywords of the target language for both Java and Kotlin.
Fix: Use the declared name for keys in JSON when emitting/reading keyword named members.
Fix: Generated Kotlin code is malformed for long identifiers.
Fix: Make the Wire Gradle plugin compatible with instant execution.
This release includes major non-backwards-compatible API changes to the wire-schema module. This will break tools that use Wire\u2019s schema modeling as a standalone library. We are making big changes to this component and we sacrificed API compatibility to accelerate these improvements.
New: proto { ... } target in the Wire Gradle plugin. Use this to perform basic source code transformations on collections of .proto files. We use it to prune large collections of protos to just the subset used by the application.
Fix: Support all forms of reserved extensions, such as extensions 1, 3 to 5, 7;.
Fix: Don\u2019t re-generate source files when their .proto files haven\u2019t changed.
New: includes, excludes, root, and prune give precedence to the most precise rule. Previously excludes always took precedence over includes, and prune always took precedence over root.
Fix: Generate non-instantiable class for enclosing types in Kotlin. These are emitted when a nested type is retained but its enclosing type is pruned.
Fix: Do not fail to build when the profile cannot find a dependency.
Fix: Use the correct adapter path for gRPC endpoints that customize the Java package.
Fix: Preserve documentation in generated services.
Fix: Fail to generate code if the source directory doesn\u2019t exist.
Fix: Make Kotlin consistent with Java for unknown enum constants. We now treat these as unknown fields rather than failing to decode the enclosing message.
Update: Total rewrite of the generated interfaces for clients:
Introduce two interfaces, GrpcCall for simple RPCs, and GrpcStreamingCall fox duplex ones. Both will provide blocking and suspending API, including a reference to the underlying OkHttp Call object and its timeout.
Starting with this version, wire-runtime is published as a multiplatform Kotlin artifact. While the JVM artifact is binary- and behavior-compatible with 3.0.0-alpha01, artifacts for other platforms may not work correctly at this point. The artifact name for the JVM artifact has been changed to wire-runtime-jvm: now, in order to depend on the multiplatform runtime, use the following Gradle dependency declaration:
api \"com.squareup.wire:wire-runtime:3.0.0-alpha02\"\n
and if you want to depend on the JVM artifact only, use the following declaration:
api \"com.squareup.wire:wire-runtime-jvm:3.0.0-alpha02\"\n
New: Generate RPCs as Single Abstract Methods.
New: Add \u201csingleMethod\u201d Gradle plugin configuration for services.
New: Add \u201cblockingServices\u201d Gradle plugin configuration for services.
New: Support packageless services code generation.
Wire 3 can generate Kotlin data classes. To enable this feature via the command line API, pass in the --kotlin_out parameter that should specify the output directory for the generated *.kt files. Given the following simple proto:
message Person {\n required string name = 1;\n required int32 id = 2;\n optional string email = 3;\n}\n
the generated Kotlin code will look like the following:
data class Person(\n @field:WireField(tag = 1, adapter = \"com.squareup.wire.ProtoAdapter#STRING\")\n val name: String,\n @field:WireField(tag = 2, adapter = \"com.squareup.wire.ProtoAdapter#INT32\")\n val id: Int,\n @field:WireField(tag = 3, adapter = \"com.squareup.wire.ProtoAdapter#STRING\")\n val email: String? = null,\n val unknownFields: ByteString = ByteString.EMPTY\n) : Message<Person, Person.Builder>(ADAPTER, unknownFields) {\n companion object {\n @JvmField\n val ADAPTER: ProtoAdapter<Person> = ... // code omitted for brevity\n
The copy() method of a data class replaces most usages of the builder. If your code relies on the Builder, you can enable full Builder generation by passing the --java_interop parameter to the compiler.
New: gRPC support
In addition to generating Kotlin code from proto messages, Wire can now generate code for gRPC endpoints. Here\u2019s an example schema:
service RouteGuide {\n // A simple RPC.\n //\n // Obtains the feature at a given position.\n //\n // A feature with an empty name is returned if there's no feature at the given\n // position.\n rpc GetFeature(Point) returns (Feature) {}\n}\n
The generated code will look like the following (message protos, referenced by the schema, are omitted):
All four gRPC modes are supported: the generated code uses suspendable functions to implement non-blocking asynchronous execution. In streaming modes, ReceiveChannel and SendChannel are used to listen to asynchronous data in a non-blocking fashion.
This feature works out of the box in Wire 3 compiler as long as the input file contains a gRPC schema.
New: Gradle plugin
Here\u2019s an example Gradle configuration:
apply plugin: 'com.squareup.wire'\n\nwire {\n // Keeps only 'Dinosaur#name' as the root of the object graph\n roots 'squareup.dinosaurs.Dinosaur#name'\n\n // Keeps all fields, except 'name', in 'Dinosaur'\n prunes 'squareup.dinosaurs.Dinosaur#name'\n\n // Both roots and prunes in an external file\n rules 'rules.txt'\n\n kotlin {\n javaInterop true\n out \"${buildDir}/generated/custom\"\n }\n}\n
The wire extension introduces the concept of compilation targets, such as kotlin and java, where each target has its own configuration properties. Multiple targets can be supplied, which benefits use cases such as migrating Java protos to Kotlin.
New: Decouple the option of using Android annotations for nullability from the option of having messages implement Parcelable.
New: Wire Moshi adapter for serializing proto JSON representation using the Moshi library.
New: Implement support for custom enum types.
New: Generate AndroidX nullability annotations instead of old support library annotations.
New: Import JSR 305 and use it to mark nullability of public API.
New: Allow inline multiline comments.
New: Generate an empty class when a nested message is retained but its parent was pruned.
New: Support rendering a ProtoFile to its schema.
New: Support hexadecimal numeric literals.
New: Allow custom types to be constrained with a \u2018with\u2019 clause.
New: Generate a constructor which takes in a Message.Builder instead of all fields separately.
New: Add location to the error message about unsupported group elements.
New: Permit single files to be used on the proto path.
Fix: Emit \u2018=\u2019 for syntax declaration.
Fix: Don\u2019t crash when a comment has a dollar sign.
Fix: Return subclass type instead of abstract parameterized type for newBuilder.
Fix: Validate enum namespace in file context are unique.
New: Support for map type in the schema, compiler, and runtime!
New: AndroidMessage base class consolidates everything required for supporting Android and will now be used for generating code with --android.
New: stream keyword in RPC definitions is now parsed and exposed in the schema.
Fix: Nested types which are retained no longer cause their enclosing type to be retained. Instead, non-instantiable empty types will be generated for pruned enclosing types.
Fix: Remove per-type Parcelable.Creator classes and instead use a single type which delegates to the message\u2019s ProtoAdapter.
Fix: Retain information on redacted fields even when options were pruned.
Fix: Do not generate code for handling null from list types (and now map types) which are guaranteed to never be null.
Empty lists of packed values were being encoded incorrectly. In Wire 2.0.x our message adapters incorrectly included empty lists for [packed=true] rather than omitting them. This is now fixed.
New: Message.encode() to concisely encode a message.
New: MessageAdapter.decode(ByteString) to decode a message from a byte string without an intermediate byte array.
New: Wire now includes a sample code generation for service interfaces.
New: ProtoAdapter.get overload which returns an adapter given an instance of a message.
New: @Nullable annotations are emitted for optional fields when using --android.
Fix: Remove the need for javac to generate synthetic accessor methods in the generated code. This results in smaller code size and less method references (for Android users).
Fix: Exclude unknown fields when encoding JSON and drop unknown fields when parsing JSON.
Fix: Ensure JSON encoding and decoding works in the default generation mode (not just --compact) by always adding @WireField metadata to message fields.
Fix: Update to JavaPoet 1.4 for more accurate generation of valid Java code.
Fix: Do not emit case statements for aliased enum constant values. The first constant for a value will be returned when deserializing.
Fix: Emit @Deprecated annotation on deprecated enum constants.
Fix: Correctly prune dependencies of excluded message, enum, or service members. Previously the dependencies of an excluded member were retained despite the member itself being omitted.
Wire 2 is a backwards-incompatible release. It makes breaking changes to the compiler, runtime, extensions, and generated code. These changes aren\u2019t made lightly as we\u2019ve endured the upgrade in our own projects! We believe the cost of migration is worth the benefits.
We\u2019ve created the wire-schema library that models .proto schema definitions. This is a capable library that packs several neat features. You can load a Schema from .proto files located on the local file system, a ZIP or JAR file, or any java.nio.FileSystem like Jimfs. You can prune this schema with includes or excludes, allowing you to reuse .proto definitions with minimal code. And you can decode data directly from a schema: no code generation is necessary!
We\u2019ve flattened extensions. Wire 2.0 combines the fields defined directly on messages with fields defined far away in extensions. In the generated code, extension fields look just like every other field! One limitation of this approach is that it\u2019s no longer possible to compile extensions separately from the messages they extend. For this reason we now recommend always generating all Wire code in a single step.
We\u2019ve rearranged the runtime. Types related to the protocol buffers format are now prefixed Proto and types related to our implementation are prefixed Wire. To encode and decode messages you must first get an adapter either from the ADAPTER constant or from ProtoAdapter.get(). You no longer need a Wire instance!
New ADAPTER constant on most messages gives access to encode & decode values. This replaces the encoding and decoding methods on Wire.
Guard against null lists. Code that passes null to builder methods expecting a List used to accept that; now Wire throws a NullPointerException. Similarly list elements must also be non-null.
New Message.newBuilder() API. This replaces the previous copy constructor on Builder.
New: Always use Wire\u2019s bundled descriptor.proto. Previously to define custom options you needed to import a potentially-inconsistent descriptor.
New: Emit all types when no .proto files are explicitly specified.
New: Generate code for encoding and decoding messages. The previous, reflection-based encoder and decoder are accessible with --compact.
New: ServiceFactory has been removed. To generate code for your services, load a schema with wire-schema and then use a library like JavaPoet to generate your own code. The JavaGenerator class can be used to look up Java names of message types.
New: Compiler will load all .proto files if none are explicitly specified.
New: Load .proto files from ZIP and JAR files.
New: The --android flag causes Wire messages to implement Parcelable.
New: Support multiple --proto_path arguments
New: The --named_files_only flag limits which .proto files yield .java files. This was the default in Wire 1.x.
New: The --no_options flag has been deleted. Use --excludes=google.protobuf.* instead.
New: Messages implement Serializable. The serialized form follows protobuf encoding, so renaming fields is safe as long as tags are consistent. (Renaming classes is unsafe, however). Note that extension fields are deserialized as unknown fields.
"},{"location":"code_of_conduct/","title":"Open Source Code of Conduct","text":"
At Square, we are committed to contributing to the open source community and simplifying the process of releasing and managing open source software. We\u2019ve seen incredible support and enthusiasm from thousands of people who have already contributed to our projects\u200a\u2014\u200aand we want to ensure our community continues to be truly open for everyone.
This code of conduct outlines our expectations for participants, as well as steps to reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all and expect our code of conduct to be honored.
Square\u2019s open source community strives to:
Be open: We invite anyone to participate in any aspect of our projects. Our community is open, and any responsibility can be carried by a contributor who demonstrates the required capacity and competence.
Be considerate: People use our work, and we depend on the work of others. Consider users and colleagues before taking action. For example, changes to code, infrastructure, policy, and documentation may negatively impact others.
Be respectful: We expect people to work together to resolve conflict, assume good intentions, and act with empathy. Do not turn disagreements into personal attacks.
Be collaborative: Collaboration reduces redundancy and improves the quality of our work. We strive for transparency within our open source community, and we work closely with upstream developers and others in the free software community to coordinate our efforts.
Be pragmatic: Questions are encouraged and should be asked early in the process to avoid problems later. Be thoughtful and considerate when seeking out the appropriate forum for your questions. Those who are asked should be responsive and helpful.
Step down considerately: Members of every project come and go. When somebody leaves or disengages from the project, they should make it known and take the proper steps to ensure that others can pick up where they left off.
This code is not exhaustive or complete. It serves to distill our common understanding of a collaborative, shared environment, and goals. We expect it to be followed in spirit as much as in the letter.
We encourage everyone to participate and are committed to building a community for all. Although we may not be able to satisfy everyone, we all agree that everyone is equal.
Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong.
Although this list cannot be exhaustive, we explicitly honor diversity in age, culture, ethnicity, gender identity or expression, language, national origin, political beliefs, profession, race, religion, sexual orientation, socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected characteristics above, including participants with disabilities.
If you experience or witness unacceptable behavior\u200a\u2014\u200aor have any other concerns\u200a\u2014\u200aplease report it by emailing codeofconduct@squareup.com. For more details, please see our Reporting Guidelines below.
Some of the ideas and wording for the statements and guidelines above were based on work by the Twitter, Ubuntu, GDC, and Django communities. We are thankful for their work.
If you experience or witness unacceptable behavior\u200a\u2014\u200aor have any other concerns\u200a\u2014\u200aplease report it by emailing codeofconduct@squareup.com. All reports will be handled with discretion.
In your report please include:
Your contact information.
Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please include them as well.
Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link.
Any additional information that may be helpful.
After filing a report, a representative from the Square Code of Conduct committee will contact you personally. The committee will then review the incident, follow up with any additional questions, and make a decision as to how to respond.
Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the Square Code of Conduct committee may take any action they deem appropriate, up to and including a permanent ban from all of Square spaces without warning.
Keeping the project small and stable limits our ability to accept new contributors. We are not seeking new committers at this time, but some small contributions are welcome.
If you\u2019ve found a security problem, please follow our bug bounty program.
If you\u2019ve found a bug, please contribute a failing test case so we can study and fix it.
Before code can be accepted all contributors must complete our Individual Contributor License Agreement (CLA).
Square recognizes the important contributions the security research community can make. We therefore encourage reporting security issues with the code contained in this repository.
If you believe you have discovered a security vulnerability, please follow the guidelines at https://bugcrowd.com/squareopensource
Wire has two key components: a compiler that generates source code at build time, and a runtime library that supports the generated code when your program executes. The compiler is very configurable; this guide explains its features and their use.
plugins {\n id 'application'\n id 'org.jetbrains.kotlin.jvm'\n id 'com.squareup.wire'\n}\n\nwire {\n kotlin {}\n}\n
The plugin will read the .proto schema definitions, validate them, link them, and generate Kotlin code. It uses KotlinPoet internally to generate compact and legible source files.
If sourcePath isn\u2019t set, Wire will look for .proto files in src/main/proto by default.
Wire will generate files in build/generated/source/wire. It\u2019ll also register this directory as a source directory for the project so the generated sources are compiled by the Kotlin compiler.
Replace kotlin with java to generate the Java sources instead.
"},{"location":"wire_compiler/#inputs-and-outputs","title":"Inputs and Outputs","text":"
Wire can pull source .proto schema definitions from a local directory, a local .jar file, or an external artifact specified with Maven coordinates.
Wire can emit multiple languages in the same build. Use includes to specify which types are emitted for a target language; subsequent languages will emit what\u2019s left over.
Note that sources are specified as file system paths (slash delimiter) and targets are specified as Proto type names (dot delimiter).
You may also specify targets with excludes. If you have both includes and excludes, excludes take precedence.
wire {\n ...\n\n kotlin {\n // Kotlin emits everything but sales and geo packages.\n excludes = ['com.example.sales.*', 'com.example.geo.*']\n }\n java {\n // Java gets those because they're left over.\n }\n}\n
Wire will print a warning if any name in includes or excludes is unused.
When configuring Wire you must use the package name from the .proto file\u2019s package declaration. The option java_package name is not used for Wire configuration.
"},{"location":"wire_compiler/#proto-path-for-libraries","title":"Proto Path for Libraries","text":"
Large projects may span multiple modules. To support this Wire has a \u2018proto path\u2019. The .proto schema files on this path are used for linking and validation, but they do not yield files in the generated output.
The proto path supports the same inputs as the source path: directories, .jar files, and Maven coordinates. Similarly, the proto path may be filtered with include.
The source path and proto path are linked together but only types on the source path are generated.
"},{"location":"wire_compiler/#dependencies-between-gradle-modules","title":"Dependencies between Gradle Modules","text":"
Wire provides support to define dependencies between modules within the same project.
A module can include its .proto files into the output resources. Use this when your .jar file can be used as a library for other proto or Wire projects. Note that only the .proto files used in the library will be included.
wire {\n protoLibrary = true\n}\n
Wire also creates two configurations, protoPath and protoSource you can use to define a dependency on another proto or Wire project.
dependencies {\n // The task `:common-protos:jar` will be added into the dependency\n // graph of this module for the Wire generating tasks.\n protoPath(project(':common-protos'))\n implementation(project(':common-protos'))\n}\n\nwire {\n kotlin {\n }\n}\n
Note that protoPath and protoSource dependencies are not transitive by default. If needed, you can change it manually.
For mobile projects it\u2019s easy to generate a lot of unnecessary code. For example, a .proto schema might support types for obsolete features.
General-purpose code-shrinking tools like R8 and ProGuard have difficulty shrinking Wire-generated sources because the encode() and decode() functions still use them. Instead, Wire offers its own code shrinker to eliminate unwanted declarations early.
Use prune to precisely eliminate an unwanted type or member. These will be eliminated along with all references to them.
Another way to prune obsolete fields is to assign them a version, then to generate your code against a version range or a unique version. The fields out of the version range will get pruned.
Members may be declared with wire.since and wire.until options; enum constant can use wire.constant_since and wire.constant_until. For example, these options declare a field age that was replaced with birth_date in version \u201c5.0\u201d:
import \"wire/extensions.proto\";\n\nmessage Singer {\n optional string name = 1;\n optional int32 age = 2 [(wire.until) = \"5.0\"];\n optional Date birth_date = 3 [(wire.since) = \"5.0\"];\n}\n
Client code should typically target a single version. In this example, clients will have the name and birth_date fields only.
wire {\n onlyVersion \"5.0\"\n}\n
Service code that supports many clients should support the union of versions of all supported clients. Such code will have name, as well as both the age and birth_date fields.
By default, .proto input files are not included in the generated .jar artifact. Use the protoLibrary option to include them:
wire {\n protoLibrary = true\n}\n
This is most useful when building .jar files for other wire tasks to use as dependencies. Note that only the true sources are included \u2013 proto messages that are pruned or not used are not included in the output artifact.
Here\u2019s an exhaustive Java configuration. Booleans are shown with their default behavior.
wire {\n java {\n // Proto types to include generated sources for. Types listed here will be\n // generated for this target and not for subsequent targets in the task.\n //\n // This list should contain package names (suffixed with `.*`) and type\n // names only. It should not contain member names.\n includes = ['com.example.pizza.*']\n\n // Proto types to excluded generated sources for. Types listed here will\n // not be generated for this target.\n //\n // This list should contain package names (suffixed with `.*`) and type\n // names only. It should not contain member names.\n excludes = ['com.example.sales.*']\n\n // True if types emitted for this target should not also be emitted for\n // other targets. Use this to cause multiple outputs to be emitted for the\n // same input type.\n exclusive = true\n\n // Directory to emit to.\n out \"${buildDir}/custom\"\n\n // True for emitted types to implement android.os.Parcelable.\n android = false\n\n // True to enable the androidx.annotation. Nullable annotation\n // where applicable.\n androidAnnotations = false\n\n // True to emit code that uses reflection for reading, writing, and toString\n // methods which are normally implemented with generated code.\n compact = false\n\n // True to turn visibility of all generated types' constructors\n // to non-public.\n buildersOnly = false\n\n // True to emit types for options declared on messages, fields, etc.\n emitDeclaredOptions = true\n\n // True to emit annotations for options applied on messages, fields, etc.\n emitAppliedOptions = true\n }\n}\n
Here\u2019s an exhaustive Kotlin configuration. Booleans and enums are shown with their default behavior.
wire {\n kotlin {\n // Proto types to include generated sources for. Types listed here will be\n // generated for this target and not for subsequent targets in the task.\n //\n // This list should contain package names (suffixed with `.*`) and type\n // names only. It should not contain member names.\n includes = ['com.example.pizza.*']\n\n // Proto types to excluded generated sources for. Types listed here will not\n // be generated for this target.\n //\n // This list should contain package names (suffixed with `.*`) and type\n // names only. It should not contain member names.\n excludes = ['com.example.sales.*']\n\n // True if types emitted for this target should not also be emitted for\n // other targets. Use this to cause multiple outputs to be emitted for the\n // same input type.\n exclusive = true\n\n // Directory to emit to.\n out \"${buildDir}/custom\"\n\n // True for emitted types to implement android.os.Parcelable.\n android = false\n\n // True for emitted types to implement APIs for easier migration from the\n // Java target.\n javaInterop = false\n\n // True to turn visibility of all generated types' constructors\n // to non-public.\n buildersOnly = false\n\n // True to emit types for options declared on messages, fields, etc.\n emitDeclaredOptions = true\n\n // True to emit annotations for options applied on messages, fields, etc.\n emitAppliedOptions = true\n\n // `suspending` to generate coroutines APIs that require a Kotlin\n // coroutines context.\n // `blocking` to generate blocking APIs callable by Java and Kotlin.\n rpcCallStyle = 'blocking'\n\n // `client` to generate interfaces best suited to sending outbound calls.\n // `server` to generate interfaces best suited to receiving inbound calls.\n // `none` to not generate services.\n rpcRole = 'server'\n\n // If set, the value will be appended to generated service type names. If\n // null, their rpcRole will be used as a suffix instead.\n nameSuffix = \"Suffix\"\n\n // True for emitted services to implement one interface per RPC.\n singleMethodServices = false\n\n // Set how many oneof choices are necessary for generated message classes to use the\n // `OneOf<Key<T>, T>` form rather than the default, where options are flattened into the\n // enclosing type.\n boxOneOfsMinSize = 5000\n\n // True to escape Kotlin keywords like `value` and `data` with backticks. Otherwise an\n // underscore underscore is added as a suffix, like `value_` and `data_`.\n escapeKotlinKeywords = false\n\n // Defines how an protobuf enum type is to be generated. See `com.squareup.wire.kotlin.EnumMode`\n enumMode = \"enum_class\"\n }\n}\n
Here\u2019s an exhaustive Proto configuration. You can use this target to generate a pruned proto schema, or to pretty-print one. Note that even with multiple outputs set, the proto target will always emit all types, all services, and all extensions of the schema.
wire {\n proto {\n // Directory to emit to.\n out \"${buildDir}/custom\"\n }\n}\n
With a custom schema handler, you can handle a proto schema in any way you want, including code generation or other side effects such as validation, logging, etc.
You\u2019ll need to first extend the SchemaHandler class, and then the SchemaHandler.Factory interface which is to return an instance of the former. See our recipes for different use cases\u2019 implementations.
Build that into an jar artifact and add that as a buildscript dependency to your Gradle project.
Next configure the Wire plugin to call your custom handler. Here\u2019s an exhaustive custom configuration. Booleans and enums are shown with their default behavior.
wire {\n custom {\n // The name of a Java class to generate code with. This class must:\n // * be in the buildscript dependencies for this Gradle project\n // * be a public class\n // * have a public no-arguments constructor\n // * implement the com.squareup.wire.schema.SchemaHandler.Factory interface\n schemaHandlerFactoryClass = \"com.example.MyCustomHandlerFactory\"\n\n // These options work the same as the java and kotlin targets above.\n includes = ['com.example.pizza.*']\n excludes = ['com.example.sales.*']\n exclusive = true\n out \"${buildDir}/custom\"\n\n // Custom payload which can be passed to the `SchemaHandler.Factory`.\n options = [a: \"one\", b: \"two\", c: \"three\"]\n }\n}\n
The easiest way to get started is to use CocoaPods.
# Add the Wire compiler so that it is downloaded and available.\n# CocoaPods will download the source and build the compiler directly,\n# so you'll need Java installed.\npod 'WireCompiler'\n\n# Add the Wire runtime to do the serializing/deserializing\npod 'Wire'\n
Then run pod install to get the dependencies and build the Wire compiler.
Swift Package Manager is also supported for linking the Wire runtime.
"},{"location":"wire_compiler/#build-your-protos","title":"Build Your Protos","text":"
The Wire compiler uses SwiftPoet to generate Swift code. The resulting objects automatically conform to Equatable, Codable and Sendable.
Assuming you\u2019ve used CocoaPods to download the Wire compiler, to compile your protos into Swift files:
java -jar ./Pods/WireCompiler/compiler.jar \\\n \"--proto_path=<directory containing .proto files>\" \\\n \"--swift_out=<directory where the generated .swift files go>\" \\\n \"--experimental-module-manifest=<path to manifest yaml file>\"\n
Swift introduced a new challenge that didn\u2019t exist with Kotlin and Java: modules. Kotlin and Java both use fully-qualified package names, but Swift modules are defined by their compilation unit, and thus namespaces aren\u2019t declared at the type or file level. This meant that we needed to build a new packaging system for Swift that could deal with Swift module namespacing and imports.
We decided that the easiest way for a caller to define modules was to make those definitions handled directly by Wire. A single manifest file defines the modules, their names, their dependencies, and the content roots and prunes mentioned above.
In this example manifest the DarkSide and LightSide modules would depend on and import the CommonProtos module:
The Wire compiler will generate interfaces for your service RPCs defined in your protobuf schema; under the condition that the target is set to Kotlin.
You can configure how your services are generated via the Gradle plugin:
wire {\n // Kotlin target will generate code for services.\n kotlin {\n // `client` to generate interfaces best suited to sending outbound calls.\n // `server` to generate interfaces best suited to receiving inbound calls.\n rpcRole = 'server'\n // Server only\n // `suspending` to generate coroutines APIs that require a Kotlin coroutines context.\n // `blocking` to generate blocking APIs callable by Java and Kotlin.\n rpcCallStyle = 'suspending'\n // Server only\n // True for emitted services to generate one interface per RPC.\n singleMethodServices = false\n }\n}\n
The generated code varies depending on your RPC role, namely client or server. We\u2019ll use the following schema to demonstrate how they differ:
"},{"location":"wire_grpc/#grpc-for-clients","title":"gRPC for Clients","text":"
For the schema RouteGuide, when rpcRole is client, the Wire compiler will generate the following interface:
interface RouteGuideClient : Service {\n fun GetFeature(): GrpcCall<Point, Feature>\n\n fun ListFeatures(): GrpcStreamingCall<Rectangle, Feature>\n\n fun RecordRoute(): GrpcStreamingCall<Point, RouteSummary>\n\n fun RouteChat(): GrpcStreamingCall<RouteNote, RouteNote>\n}\n
For streaming APIs, we return a GrpcStreamingCall, and a GrpcCall otherwise. With these objects, the caller can communicate with the server. Both blocking and suspending APIs are provided.
To help you instantiate your service, we provide a small runtime, namely GrpcClient:
val grpcClient = GrpcClient.Builder()\n .client(OkHttpClient.Builder().protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE)).build())\n .baseUrl(serverUrl)\n .build()\nval routeGuideClient = grpcClient.create(RouteGuideClient::class)\n
"},{"location":"wire_grpc/#grpc-for-servers","title":"gRPC for Servers","text":""},{"location":"wire_grpc/#blocking-apis","title":"Blocking APIs","text":"
the Wire compiler will generate the following interface for the server to implement:
interface RouteGuideBlockingServer : Service {\n fun GetFeature(request: Point): Feature\n\n fun ListFeatures(request: Rectangle, response: MessageSink<Feature>)\n\n fun RecordRoute(request: MessageSource<Point>): RouteSummary\n\n fun RouteChat(request: MessageSource<RouteNote>, response: MessageSink<RouteNote>)\n}\n
For streaming connections, the server can use Wire\u2019s blocking APIs: MessageSource and MessageSink."},{"location":"wire_grpc/#suspending-apis","title":"Suspending APIs","text":"
the Wire compiler will generate the following interface for the server to implement:
interface RouteGuideServer : Service {\n suspend fun GetFeature(request: Point): Feature\n\n fun ListFeatures(request: Rectangle, response: SendChannel<Feature>)\n\n fun RecordRoute(request: ReceiveChannel<Point>): RouteSummary\n\n fun RouteChat(request: ReceiveChannel<RouteNote>, response: SendChannel<RouteNote>)\n}\n
The server can use Kotlin coroutines\u2019 suspend and Channels mechanisms to execute suspending network calls."},{"location":"wire_grpc/#implementing-client-interfaces","title":"Implementing Client Interfaces","text":"
Wire has helper functions to make it easier to implement its client interfaces. This can be particularly useful for testing. It supports both streaming and non-streaming APIs in Kotlin:
The client interface may also be implemented in Java. Wire only offers a non-streaming helper function. The GrpcStreamingCall above uses coroutines which is Kotlin-only.
public class FakeRouteGuideClient implements RouteGuideClient {\n @Override public GrpcCall<Point, Feature> GetFeature() {\n return GrpcCalls.grpcCall(new Function1<Point, Feature>() {\n @Override public Feature invoke(Point request) {\n return new Feature.Builder()\n .name(\"test\")\n .location(request)\n .build();\n }\n });\n }\n\n ...\n}\n
These similarly interact nicely with Java lambdas.
The modules wire-grpc-server and wire-grpc-server-generator have been extracted out of Wire 5. They now live as a standalone repository square/wire-grpc-server/.
grpcServerCompatible does not exist anymore. You are to pass the new GrpcServerSchemaHandler to Wire in a custom block.
After
wire {\n custom {\n // Be sure that `server-generator` is on the classpath for Gradle to resolve\n // `GrpcServerSchemaHandler`.\n schemaHandlerFactory = com.squareup.wire.kotlin.grpcserver.GrpcServerSchemaHandler.Factory()\n options = mapOf(\n // Defaults to `true` if absent. Any other value than `true` is considered false.\n \"singleMethodServices\" to \"false\",\n // Defaults to `suspending` if absent. Any other value than `suspending` is considered\n // non-suspending.\n \"rpcCallStyle\" to \"suspending\",\n )\n // We set the custom block exclusivity to false so that the next `kotlin {}` block can also\n // generate the protobuf Messages.\n exclusive = false\n }\n\n kotlin {\n rpcRole = \"server\"\n singleMethodServices = false\n rpcCallStyle = \"suspending\"\n }\n}\n
For any problem with the migration, please ask on wire-grpc-server.
Moshi support is part of the wire-moshi-adapter module. It has to be added to the project dependencies in order to plug the WireJsonAdapterFactory into Moshi.
The Maven coordinates are: com.squareup.wire:wire-moshi-adapter:<version>
Moshi support is part of the wire-gson-support module. It has to be added to the project dependencies in order to plug the WireTypeAdapterFactory into Gson.
The Maven coordinates are: com.squareup.wire:wire-gson-support:<version>
Wire is interoperable with protoc for all proto3 messages. The JSON representation of proto2 is unspecified. JSON representations of proto2 messages from Wire and protoc are not interoperable. Note that by default Protoc throws an error for unknown fields. Wire will ignore them.
"},{"location":"wire_vs_protoc/","title":"Wire versus Protoc","text":""},{"location":"wire_vs_protoc/#non-primitive-types","title":"Non-Primitive Types","text":"
Protoc generates literal equivalents for all the Proto3 new types like empty, struct, etc. Wire tries to reuse existing types in the corresponding language when possible. The only new type Wire brings is AnyMessage for the google.protobuf.Any proto type.
The Any type wraps an arbitrary protobuf message by holding a field to identify its type and another field for storing the serialized representation of the wrapped message. Wire comes with its own AnyMessage type to represent google.protobuf.Any.
class AnyMessage(\n val typeUrl: String,\n val value: okio.ByteString\n)\n
It comes with a few methods to wrap or unwrap the embedded message.
// Wire\nval anyMessage: AnyMessage = AnyMessage.pack(person)\nval person: Person = anyMessage.unpack(Person.ADAPTER)\n\n// Protoc\nval any: Any = Any.pack(foo)\nval person: Person = any.unpack(Person.class)\n
Both google.protobuf.Duration and google.protobuf.Timestamp types will be generated by using their JVM equivalent: java.time.Duration and java.time.Instant. For non-JVM platforms, we provide two new Wire types with the same APIs:
class com.squareup.wire.Duration {\n fun getSeconds(): Long\n fun getNano(): Int\n}\nfun durationOfSeconds(seconds: Long, nano: Long): Duration\n\nclass com.squareup.wire.Instant {\n fun getEpochSecond(): Long\n fun getNano(): Int\n}\nfun ofEpochSecond(epochSecond: Long, nano: Long): Instant\n
google.protobuf.Struct is meant mainly to represent JSON objects in code. Instead of building new types, Wire reuses Java/Kotlin native types to represent all Struct types.
Google Protobuf Type Wire\u2019s Java Equivalent Wire\u2019s Kotlin Equivalent StructMap<String, ?>Map<String, ?>?ListValueList<?>List<?>?ValueObjectAny?NullValueVoidNothing?
One difference worth noting between Protoc and Wire is that Protoc can make the difference between an absent value, and a null value, Wire doesn\u2019t. Wire will always write nulls in JSON objects except at the root of it.
Wire didn\u2019t create new types for wrappers either, each wrapper will be represented by a nullable version of the primitive type it defines. For instance google.protobuf.FloatValue will be represented in Java by the float boxed type @Nullable Float, in Kotlin by Float?.
While Proto2 didn\u2019t, Proto3 defines Protobuf serialization over JSON. Wire and Protoc are interoperable but their API are quite different. Wire offers JSON serialization over Moshi or Gson. Protoc brings its own JsonFormatter. Beware that Protoc throws an error for unknown fields, you need to configure it to opt-out of this behavior!
"}]}
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Wire","text":"
\u201cA man got to have a code!\u201d - Omar Little
As our teams and programs grow, the variety and volume of data also grows. Success will turn your simple data models into complex ones! Whether your application is storing data to disk or transmitting it over a network, the structure and interpretation of that data should be clear. Consumers work best with data they understand!
Schemas describe and document data models. If you have data, you should have a schema.
Google\u2019s Protocol Buffers are built around a great schema language:
It\u2019s cross platform and language independent. Whatever programming language you use, you\u2019ll be able to use proto schemas with your application.
Proto schemas are backwards-compatible and future-proof. You can evolve your schema as your application loses old features and gains new ones.
It\u2019s focused. Proto schemas describe your data models. That\u2019s it.
Protocol Buffer Examples Here's a [sample message][dinosaur_proto] definition:
syntax = \"proto3\";\n\npackage squareup.dinosaurs;\n\noption java_package = \"com.squareup.dinosaurs\";\n\nimport \"squareup/geology/period.proto\";\n\nmessage Dinosaur {\n // Common name of this dinosaur, like \"Stegosaurus\".\n string name = 1;\n\n // URLs with images of this dinosaur.\n repeated string picture_urls = 2;\n\n squareup.geology.Period period = 5;\n}\n
And here's an [enum][period_proto] definition:
syntax = \"proto3\";\n\npackage squareup.geology;\n\n\noption java_package = \"com.squareup.geology\";\n\nenum Period {\n // 145.5 million years ago \u2014 66.0 million years ago.\n CRETACEOUS = 0;\n\n // 201.3 million years ago \u2014 145.0 million years ago.\n JURASSIC = 1;\n\n // 252.17 million years ago \u2014 201.3 million years ago.\n TRIASSIC = 2;\n}\n
This schema language is Protocol Buffers' best feature. You might even use it purely for documentation purposes, such as to describe a JSON API. Protocol Buffers also defines a compact binary encoding of messages that conform to the schema. This encoding is fast to encode, fast to decode, small to transmit, and small to store. The binary encoding uses numeric tags from the schema, like the `5` for `period` above. For example, let's encode this dinosaur:
The Protocol Buffers schema language and binary encoding are both defined by Google. Wire is an independent implementation from Square that\u2019s specifically designed for Android and Java.
For each message type defined in the schema, Wire generates an immutable model class and its builder. The generated code looks like code you\u2019d write by hand: it\u2019s documented, formatted, and simple. Wire\u2019s APIs should feel at home to programmers who like Effective Java.
That said, there are some interesting design decisions in Wire:
Wire messages declare public final fields instead of the usual getter methods. This cuts down on both code generated and code executed. Less code is particularly beneficial for Android programs.
Wire avoids case mapping. A field declared as picture_urls in a schema yields a Java field picture_urls and not the conventional pictureUrls camel case. Though the name feels awkward at first, it\u2019s fantastic whenever you use grep or more sophisticated search tools. No more mapping when navigating between schema, Java source code, and data. It also provides a gentle reminder to calling code that proto messages are a bit special.
Primitive types are always boxed. If a field is absent, its value is null. This is used for naturally optional fields, such as a dinosaur whose period is unknown. A field may also be null due to schema evolution: if tomorrow we add a carnivore boolean to our message definition, today\u2019s data won\u2019t have a value for that field.
Generated Java Code Here's the compact [generated code][dinosaur_java] for the `Dinosaur` message defined above:
// Code generated by Wire protocol buffer compiler, do not edit.\n// Source: squareup.dinosaurs.Dinosaur in squareup/dinosaurs/dinosaur.proto\npackage com.squareup.dinosaurs;\n\nimport com.squareup.geology.Period;\nimport com.squareup.wire.Message;\nimport com.squareup.wire.ProtoAdapter;\nimport com.squareup.wire.Syntax;\nimport com.squareup.wire.WireField;\nimport com.squareup.wire.internal.Internal;\nimport java.lang.Object;\nimport java.lang.Override;\nimport java.lang.String;\nimport java.util.List;\nimport okio.ByteString;\n\npublic final class Dinosaur extends Message<Dinosaur, Dinosaur.Builder> {\n public static final ProtoAdapter<Dinosaur> ADAPTER = ProtoAdapter.newMessageAdapter(Dinosaur.class, \"type.googleapis.com/squareup.dinosaurs.Dinosaur\", Syntax.PROTO_3);\n\n private static final long serialVersionUID = 0L;\n\n /**\n * Common name of this dinosaur, like \"Stegosaurus\".\n */\n @WireField(\n tag = 1,\n adapter = \"com.squareup.wire.ProtoAdapter#STRING\",\n label = WireField.Label.OMIT_IDENTITY\n )\n public final String name;\n\n /**\n * URLs with images of this dinosaur.\n */\n @WireField(\n tag = 2,\n adapter = \"com.squareup.wire.ProtoAdapter#STRING\",\n label = WireField.Label.REPEATED,\n jsonName = \"pictureUrls\"\n )\n public final List<String> picture_urls;\n\n @WireField(\n tag = 5,\n adapter = \"com.squareup.geology.Period#ADAPTER\",\n label = WireField.Label.OMIT_IDENTITY\n )\n public final Period period;\n\n public Dinosaur(String name, List<String> picture_urls, Period period) {\n this(name, picture_urls, period, ByteString.EMPTY);\n }\n\n public Dinosaur(String name, List<String> picture_urls, Period period, ByteString unknownFields) {\n super(ADAPTER, unknownFields);\n if (name == null) {\n throw new IllegalArgumentException(\"name == null\");\n }\n this.name = name;\n this.picture_urls = Internal.immutableCopyOf(\"picture_urls\", picture_urls);\n if (period == null) {\n throw new IllegalArgumentException(\"period == null\");\n }\n this.period = period;\n }\n\n @Override\n public Builder newBuilder() {\n Builder builder = new Builder();\n builder.name = name;\n builder.picture_urls = Internal.copyOf(picture_urls);\n builder.period = period;\n builder.addUnknownFields(unknownFields());\n return builder;\n }\n\n @Override\n public boolean equals(Object other) {\n if (other == this) return true;\n if (!(other instanceof Dinosaur)) return false;\n Dinosaur o = (Dinosaur) other;\n return unknownFields().equals(o.unknownFields())\n && Internal.equals(name, o.name)\n && picture_urls.equals(o.picture_urls)\n && Internal.equals(period, o.period);\n }\n\n @Override\n public int hashCode() {\n int result = super.hashCode;\n if (result == 0) {\n result = unknownFields().hashCode();\n result = result * 37 + (name != null ? name.hashCode() : 0);\n result = result * 37 + picture_urls.hashCode();\n result = result * 37 + (period != null ? period.hashCode() : 0);\n super.hashCode = result;\n }\n return result;\n }\n\n public static final class Builder extends Message.Builder<Dinosaur, Builder> {\n public String name;\n\n public List<String> picture_urls;\n\n public Period period;\n\n public Builder() {\n name = \"\";\n picture_urls = Internal.newMutableList();\n period = Period.CRETACEOUS;\n }\n\n /**\n * Common name of this dinosaur, like \"Stegosaurus\".\n */\n public Builder name(String name) {\n this.name = name;\n return this;\n }\n\n /**\n * URLs with images of this dinosaur.\n */\n public Builder picture_urls(List<String> picture_urls) {\n Internal.checkElementsNotNull(picture_urls);\n this.picture_urls = picture_urls;\n return this;\n }\n\n public Builder period(Period period) {\n this.period = period;\n return this;\n }\n\n @Override\n public Dinosaur build() {\n return new Dinosaur(name, picture_urls, period, super.buildUnknownFields());\n }\n }\n}\n
The Java code to create and access proto models is compact and readable:
Dinosaur stegosaurus = new Dinosaur.Builder()\n .name(\"Stegosaurus\")\n .period(Period.JURASSIC)\n .build();\n\nSystem.out.println(\"My favorite dinosaur existed in the \" + stegosaurus.period + \" period.\");\n
Each type has a corresponding `ProtoAdapter` that can encode a message to bytes and decode bytes back into a message.
Since version 3.0.0, Wire can generate Kotlin code. See Wire Compiler & Gradle Plugin to learn how to configure your build.
Kotlin is a pragmatic and expressive programming language that makes it easy to model data. Here\u2019s how we used Kotlin to model Protocol Buffers messages:
Messages feel like data classes, but in fact they\u2019re not. Compiler still generates equals(), hashCode(), toString() and copy() for you. Wire does not generate componentN() functions though, we believe that destructuring declarations are not a good fit for Protocol Buffers: a change in the schema that removes or adds a field might lead to a situation when your destructuring declaration still compiles but now describes a completely different subset of fields, rendering your code incorrect.
copy() is a substitute for the Builder, which is not used anymore. If your program relies on the Builder to be present, you may generate code in Java interoperability mode - Wire Compiler & Gradle Plugin explains how that works.
Fields are generated as properties. While this is idiomatic in Kotlin, Java code will now have to access fields using getters. If your program relies on accessing fields directly, use Java interoperability mode - the compiler will generate @JvmField annotations for each field.
The nullability of each field\u2019s type depends on its label: required, repeated and map fields get non-nullable types, whereas optional fields are of nullable types.
With the exception of required fields, each field has a default value:
null for optional fields,
emptyList() for repeated fields,
emptyMap() for map fields.
Generated Kotlin Code Here's the compact [generated code][dinosaur_kotlin] for the `Dinosaur` message defined above:
// Code generated by Wire protocol buffer compiler, do not edit.\n// Source: squareup.dinosaurs.Dinosaur in squareup/dinosaurs/dinosaur.proto\npackage com.squareup.dinosaurs\n\nimport com.squareup.geology.Period\nimport com.squareup.wire.FieldEncoding\nimport com.squareup.wire.Message\nimport com.squareup.wire.ProtoAdapter\nimport com.squareup.wire.ProtoReader\nimport com.squareup.wire.ProtoWriter\nimport com.squareup.wire.Syntax.PROTO_3\nimport com.squareup.wire.WireField\nimport com.squareup.wire.internal.immutableCopyOf\nimport com.squareup.wire.internal.sanitize\nimport kotlin.Any\nimport kotlin.AssertionError\nimport kotlin.Boolean\nimport kotlin.Deprecated\nimport kotlin.DeprecationLevel\nimport kotlin.Int\nimport kotlin.Long\nimport kotlin.Nothing\nimport kotlin.String\nimport kotlin.collections.List\nimport kotlin.hashCode\nimport kotlin.jvm.JvmField\nimport okio.ByteString\n\nclass Dinosaur(\n /**\n * Common name of this dinosaur, like \"Stegosaurus\".\n */\n @field:WireField(\n tag = 1,\n adapter = \"com.squareup.wire.ProtoAdapter#STRING\",\n label = WireField.Label.OMIT_IDENTITY\n )\n val name: String = \"\",\n picture_urls: List<String> = emptyList(),\n @field:WireField(\n tag = 5,\n adapter = \"com.squareup.geology.Period#ADAPTER\",\n label = WireField.Label.OMIT_IDENTITY\n )\n val period: Period = Period.CRETACEOUS,\n unknownFields: ByteString = ByteString.EMPTY\n) : Message<Dinosaur, Nothing>(ADAPTER, unknownFields) {\n /**\n * URLs with images of this dinosaur.\n */\n @field:WireField(\n tag = 2,\n adapter = \"com.squareup.wire.ProtoAdapter#STRING\",\n label = WireField.Label.REPEATED,\n jsonName = \"pictureUrls\"\n )\n val picture_urls: List<String> = immutableCopyOf(\"picture_urls\", picture_urls)\n\n @Deprecated(\n message = \"Shouldn't be used in Kotlin\",\n level = DeprecationLevel.HIDDEN\n )\n override fun newBuilder(): Nothing = throw AssertionError()\n\n override fun equals(other: Any?): Boolean {\n if (other === this) return true\n if (other !is Dinosaur) return false\n if (unknownFields != other.unknownFields) return false\n if (name != other.name) return false\n if (picture_urls != other.picture_urls) return false\n if (period != other.period) return false\n return true\n }\n\n override fun hashCode(): Int {\n var result = super.hashCode\n if (result == 0) {\n result = unknownFields.hashCode()\n result = result * 37 + name.hashCode()\n result = result * 37 + picture_urls.hashCode()\n result = result * 37 + period.hashCode()\n super.hashCode = result\n }\n return result\n }\n\n override fun toString(): String {\n val result = mutableListOf<String>()\n result += \"\"\"name=${sanitize(name)}\"\"\"\n if (picture_urls.isNotEmpty()) result += \"\"\"picture_urls=${sanitize(picture_urls)}\"\"\"\n result += \"\"\"period=$period\"\"\"\n return result.joinToString(prefix = \"Dinosaur{\", separator = \", \", postfix = \"}\")\n }\n\n fun copy(\n name: String = this.name,\n picture_urls: List<String> = this.picture_urls,\n period: Period = this.period,\n unknownFields: ByteString = this.unknownFields\n ): Dinosaur = Dinosaur(name, picture_urls, period, unknownFields)\n\n companion object {\n @JvmField\n val ADAPTER: ProtoAdapter<Dinosaur> = object : ProtoAdapter<Dinosaur>(\n FieldEncoding.LENGTH_DELIMITED,\n Dinosaur::class,\n \"type.googleapis.com/squareup.dinosaurs.Dinosaur\",\n PROTO_3,\n null\n ) {\n override fun encodedSize(value: Dinosaur): Int {\n var size = value.unknownFields.size\n if (value.name != \"\") size += ProtoAdapter.STRING.encodedSizeWithTag(1, value.name)\n size += ProtoAdapter.STRING.asRepeated().encodedSizeWithTag(2, value.picture_urls)\n if (value.period != Period.CRETACEOUS) size += Period.ADAPTER.encodedSizeWithTag(5,\n value.period)\n return size\n }\n\n override fun encode(writer: ProtoWriter, value: Dinosaur) {\n if (value.name != \"\") ProtoAdapter.STRING.encodeWithTag(writer, 1, value.name)\n ProtoAdapter.STRING.asRepeated().encodeWithTag(writer, 2, value.picture_urls)\n if (value.period != Period.CRETACEOUS) Period.ADAPTER.encodeWithTag(writer, 5, value.period)\n writer.writeBytes(value.unknownFields)\n }\n\n override fun decode(reader: ProtoReader): Dinosaur {\n var name: String = \"\"\n val picture_urls = mutableListOf<String>()\n var period: Period = Period.CRETACEOUS\n val unknownFields = reader.forEachTag { tag ->\n when (tag) {\n 1 -> name = ProtoAdapter.STRING.decode(reader)\n 2 -> picture_urls.add(ProtoAdapter.STRING.decode(reader))\n 5 -> try {\n period = Period.ADAPTER.decode(reader)\n } catch (e: ProtoAdapter.EnumConstantNotFoundException) {\n reader.addUnknownField(tag, FieldEncoding.VARINT, e.value.toLong())\n }\n else -> reader.readUnknownField(tag)\n }\n }\n return Dinosaur(\n name = name,\n picture_urls = picture_urls,\n period = period,\n unknownFields = unknownFields\n )\n }\n\n override fun redact(value: Dinosaur): Dinosaur = value.copy(\n unknownFields = ByteString.EMPTY\n )\n }\n\n private const val serialVersionUID: Long = 0L\n }\n}\n
Creating and accessing proto models is easy:
val stegosaurus = Dinosaur(\n name = \"Stegosaurus\",\n period = Period.JURASSIC\n)\n\nprintln(\"My favorite dinosaur existed in the ${stegosaurus.period} period.\")\n
Here's how you can modify the object to add extra fields:
val stegosaurus = stegosaurus.copy(\n picture_urls = listOf(\"https://www.flickr.com/photos/tags/Stegosaurus/\")\n)\n\nprintln(\"Here are some photos of ${stegosaurus.name}: ${stegosaurus.picture_urls}\")\n
Since version 3.3.0, Wire can generate Swift code. See Wire Compiler & Gradle Plugin to learn how to configure your build.
Swift support is considered a \u201cbeta\u201d and may still feature breaking changes. That being said, Block is shipping it in production apps and SDKs.
Swift is a pragmatic and expressive programming language with rich support for value types. Here\u2019s how we used Swift to model Protocol Buffers messages:
Messages are structs that conform to Equatable, Codable and Sendable. All Messages have value semantics.
Fields are generated as properties.
The nullability of each field\u2019s type depends on its label: required, repeated and map fields get non-nullable types, whereas optional fields are of nullable types.
Generated Swift Code Here's the compact [generated code][dinosaur_swift] for the `Dinosaur` message defined above:
// Code generated by Wire protocol buffer compiler, do not edit.\n// Source: squareup.dinosaurs.Dinosaur in squareup/dinosaurs/dinosaur.proto\nimport Foundation\nimport Wire\n\npublic struct Dinosaur {\n\n /**\n * Common name of this dinosaur, like \"Stegosaurus\".\n */\n @ProtoDefaulted\n public var name: String?\n /**\n * URLs with images of this dinosaur.\n */\n public var picture_urls: [String] = []\n @ProtoDefaulted\n public var length_meters: Double?\n @ProtoDefaulted\n public var mass_kilograms: Double?\n public var period: Period?\n public var unknownFields: Foundation.Data = .init()\n\n public init(configure: (inout Self) -> Swift.Void = { _ in }) {\n configure(&self)\n }\n\n}\n\n#if !WIRE_REMOVE_EQUATABLE\nextension Dinosaur : Equatable {\n}\n#endif\n\n#if !WIRE_REMOVE_HASHABLE\nextension Dinosaur : Hashable {\n}\n#endif\n\nextension Dinosaur : Sendable {\n}\n\nextension Dinosaur : ProtoDefaultedValue {\n\n public static var defaultedValue: Dinosaur {\n Dinosaur()\n }\n}\n\nextension Dinosaur : ProtoMessage {\n\n public static func protoMessageTypeURL() -> String {\n return \"type.googleapis.com/squareup.dinosaurs.Dinosaur\"\n }\n\n}\n\nextension Dinosaur : Proto2Codable {\n\n public init(from protoReader: ProtoReader) throws {\n var name: String? = nil\n var picture_urls: [String] = []\n var length_meters: Double? = nil\n var mass_kilograms: Double? = nil\n var period: Period? = nil\n\n let token = try protoReader.beginMessage()\n while let tag = try protoReader.nextTag(token: token) {\n switch tag {\n case 1: name = try protoReader.decode(String.self)\n case 2: try protoReader.decode(into: &picture_urls)\n case 3: length_meters = try protoReader.decode(Double.self)\n case 4: mass_kilograms = try protoReader.decode(Double.self)\n case 5: period = try protoReader.decode(Period.self)\n default: try protoReader.readUnknownField(tag: tag)\n }\n }\n self.unknownFields = try protoReader.endMessage(token: token)\n\n self._name.wrappedValue = name\n self.picture_urls = picture_urls\n self._length_meters.wrappedValue = length_meters\n self._mass_kilograms.wrappedValue = mass_kilograms\n self.period = period\n }\n\n public func encode(to protoWriter: ProtoWriter) throws {\n try protoWriter.encode(tag: 1, value: self.name)\n try protoWriter.encode(tag: 2, value: self.picture_urls)\n try protoWriter.encode(tag: 3, value: self.length_meters)\n try protoWriter.encode(tag: 4, value: self.mass_kilograms)\n try protoWriter.encode(tag: 5, value: self.period)\n try protoWriter.writeUnknownFields(unknownFields)\n }\n\n}\n\n#if !WIRE_REMOVE_CODABLE\nextension Dinosaur : Codable {\n\n public init(from decoder: Decoder) throws {\n let container = try decoder.container(keyedBy: StringLiteralCodingKeys.self)\n self._name.wrappedValue = try container.decodeIfPresent(String.self, forKey: \"name\")\n self.picture_urls = try container.decodeProtoArray(String.self, firstOfKeys: \"pictureUrls\", \"picture_urls\")\n self._length_meters.wrappedValue = try container.decodeIfPresent(Double.self, firstOfKeys: \"lengthMeters\", \"length_meters\")\n self._mass_kilograms.wrappedValue = try container.decodeIfPresent(Double.self, firstOfKeys: \"massKilograms\", \"mass_kilograms\")\n self.period = try container.decodeIfPresent(Period.self, forKey: \"period\")\n }\n\n public func encode(to encoder: Encoder) throws {\n var container = encoder.container(keyedBy: StringLiteralCodingKeys.self)\n let preferCamelCase = encoder.protoKeyNameEncodingStrategy == .camelCase\n let includeDefaults = encoder.protoDefaultValuesEncodingStrategy == .include\n\n try container.encodeIfPresent(self.name, forKey: \"name\")\n if includeDefaults || !self.picture_urls.isEmpty {\n try container.encodeProtoArray(self.picture_urls, forKey: preferCamelCase ? \"pictureUrls\" : \"picture_urls\")\n }\n try container.encodeIfPresent(self.length_meters, forKey: preferCamelCase ? \"lengthMeters\" : \"length_meters\")\n try container.encodeIfPresent(self.mass_kilograms, forKey: preferCamelCase ? \"massKilograms\" : \"mass_kilograms\")\n try container.encodeIfPresent(self.period, forKey: \"period\")\n }\n\n}\n#endif\n
Creating and accessing proto models is easy:
let stegosaurus = Dinosaur {\n $0.name = \"Stegosaurus\"\n $0.period = .JURASSIC\n}\n\nprint(\"My favorite dinosaur existed in the \\(stegosaurus.period) period.\")\n
Here's how you can modify the object to add extra fields:
var stegosaurus = stegosaurus\nstegosaurus.picture_urls = [\"https://www.flickr.com/photos/tags/Stegosaurus/\"]\n\nprint(\"Here are some photos of \\(stegosaurus.name): \\(stegosaurus.picture_urls)\")\n
"},{"location":"#generating-code-with-wire","title":"Generating Code With Wire","text":"
Wire can read .proto files from the local file system and from within .jar files.
The compiler can optionally prune your schema to a subset of root types and their transitive dependencies. This is useful when sharing a schema between projects: a Java service and Android app may each use a subset of a larger shared schema.
For more info on how to get started, see Wire Compiler & Gradle Plugin.
If you don\u2019t use Gradle, the compiler also has a command line interface. Just substitute wire-compiler-VERSION-jar-with-dependencies.jar with the path to your jar. Download the latest precompiled jar.
% java -jar wire-compiler-VERSION-jar-with-dependencies.jar \\\n --proto_path=src/main/proto \\\n --java_out=out \\\n squareup/dinosaurs/dinosaur.proto \\\n squareup/geology/period.proto\nWriting com.squareup.dinosaurs.Dinosaur to out\nWriting com.squareup.geology.Period to out\n
Supplying the --android flag to the compiler causes Wire messages to implement Parcelable.
If you use Proguard, then you need to add keep rules. The simplest option is to tell Proguard not to touch the Wire runtime library and your generated protocol buffers (of course these simple rules will miss opportunities to shrink and optimize the code):
-keep class com.squareup.wire.** { *; }\n-keep class com.yourcompany.yourgeneratedcode.** { *; }\n
Groups - they are skipped when parsing binary input data
Wire supports custom options on messages and fields. Other custom options are ignored. Pass --excludes=google.protobuf.* to the compiler to omit options from the generated code.
expose the grpc url when converting Response to GrpcException (#2920 by Travis Johnson)
Support very long field names with builders (#2959)
New enumMode option added to Kotlin targets in order to generate enum types as sealed classes. Its value can be either enum_class (default value) or sealed_class. enum_class will generate enum types as Kotlin enum classes, which is the current behavior. sealed_class will generate enum types as Kotlin sealed classes, generated each constant of the enum type as data objects. On top of those constants, the sealed class will contain a Unrecognized data class which will contain the real decoded value for this enum if the runtime didn\u2019t have any constant matching it. This is the analogue feature of protoc generating a UNRECOGNIZED(-1) constant for enums on proto3. Note however that Wire doesn\u2019t limit this option to proto3 enums, this can be used for proto2 enums too.
Switching to generating sealed class for enums can break the call-site for your consumers. In order to allow gradual migration of enum generation from/to sealed classes, a Protobuf enum option has also been created. This, when set in the .proto file, takes precedence over the global enum mode.
import \"wire/extensions.proto\";\n\nenum Period {\n option (wire.enum_mode) = \"sealed_class\"; // or `enum_class`.\n CRETACEOUS = 1;\n JURASSIC = 2;\n TRIASSIC = 3;\n}\n
\u26a0 Reject unused prunes and roots by default (#2846) This behavior used to be opt-in, now it\u2019s opt-out. You can opt out with rejectUnusedRootsOrPrunes = false in your wire { } block.
\u26a0 Remove deprecated SchemaHandler#create method (#2851) Override the other method create(includes, excludes, exclusive, outDirectory, options): SchemaHandler instead if you were not already doing it.
\u26a0 Adding a project dependency via srcJar used to work but not anymore. Use srcProject(\":my-project\") instead.
Don\u2019t warn about an unused emitting rule, when that rule is \u2018*\u2019 (#2829)
The internal of our Wire Gradle plugin has been refactored where behavior changes should not be expected. If you see anything different, please let us know.
Allow custom options to be passed in WireCompiler (#2909)
Propagates Request timeout as grpc-timeout (#2840 by Francisco Rojas)
Don\u2019t override RealGrpcCall.timeout when it\u2019s manually set (#2893 by Jeff Gulbronson)
Publish the gRPC Dispatcher (#2872) A new helper class GrpcDispatcher for gRPC testing is available under com.squareup.wire:wire-grpc-mockwebserver. Note that it does not support streaming calls. If you want to contribute, please do!
\u26a0 Refactored how extensions are emitted and provides a new API to get/set extension fields. Due to the refactor above, Codable fields that are defined in extensions will now break as part of this change. All done by Dimitris Koutsogiorgas and Adam Lickel!
\u26a0 wire-grpc-server has been moved into its own repo: https://github.com/square/wire-grpc-server. If you were using it, you can see how migration is to happen by checking these instructions.
Generate Grpc SERVICE_NAME as const (#2773 by Marius Volkhart)
Use %N in KotlinGenerator to ensure names are escaped (#2784 by Egor Andreevich)
Add escapeKotlinKeywords parameter to Kotlin target (#2785 by Egor Andreevich)
You can now set escapeKotlinKeywords = true within our kotlin {} targets to escape Kotlin keywords with backticks rather than having them suffixed with an _.
Don\u2019t retransmit a PipeDuplexRequestBody (#2791)
We had crashes that occurred when OkHttp attempted to retry sending the request body of a gRPC streaming connection.
Breaking: Encoding and decoding of negative Int32s was broken in Swift and did not match protobuf spec. Negative Int32s are now correctly encoded as unsigned Int64s. Prior versions of Wire that have serialized a proto containing negative Int32 fields will not be correctly decoded using this version onwards.
Fix: Swift ProtoDefaulted was incorrectly applied in cross-module contexts
Fix: Message\u2019s Builder won\u2019t break compilation on multiplatform projects.
Fix: No hanging anymore on gRPC when receiving an unexpected response.
New: Opaque types. You can now specify types you want Wire to evaluate as being of type bytes. On code generation, the fields of such types will be using the platform equivalent of bytes, like okio.ByteString for the JVM. Use this if there\u2019s a dependency heavy type which you do not use. Note that scalar types cannot be opaqued.
New: Adds a closure into generate types allowing the creation of an instance via the Kotlin DSL.
Fix: Don\u2019t arbitrarily prune oneOf options.
Change: Swift Defaulted has been renamed CustomDefaulted
New: Swift ProtoDefaulted property wrapper and ProtoDefaultedValue protocol
Similar to `CustomDefaulted, this adds as projection of the protocol defined default value
This should not take up any additional storage
This is attached to optional scalar values and messages with entirely optional values
New: ProtoDefaulted and CustomDefaulted include setter support
This enables you to do something like Foo().$bar.$baz += 1
Change: Swift ProtoEnum types now have a raw value of Int32.
The runtime and generated code both need to be updated to reflect this.
New: Swift messages now have the form init(REQUIRED FIELDS, (inout Storage) -> Void)
New: Swift, the member-wise initializer has been removed by default. It can be re-enabled by defining WIRE_INCLUDE_MEMBERWISE_INITIALIZER; however, it will be removed in November 2024. See https://github.com/square/wire/pull/2561 for details
Fix: Correctly define sources folders vs. resources folders for Wire generated code.
Fix: Generated .proto are correctly added to the built artifact.
New: All options of KotlinTarget available on CLI.
Fix: JSON to Kotlin deserialization is now really bullet-proofed against Class.getDeclaredFields random ordering.
Fix: proto3 types (Duration, Struct, etc) are now supported when doing dynamic serialization.
Fix: GrpcStatus is now serializable which enables GrpcException serialization.
New: GrpcClient is now abstract. You can customize how network calls are implemented.
New: You can now pass an event listener to receive metric events.
New: New option for the Wire Gradle plugin. rejectUnusedRootsOrPrunes = true will fail the build if any roots or prunes are not used when refactoring the schema. This can help discover incorrect configurations early and avoid mis-expectations about the built schema.
New: OneOf\u2019s options are now loaded to the schema.
New: Wire will now fail if it detects a type name collision which can happen if a same file is loaded from different paths.
New: wire-schema-tests is now multiplatform.
New: SchemaHandler.Factory can now receive payload set within the Wire Gradle plugin. Implement the method fun create(includes, excludes, exclusive, outDirectory. options): SchemaHandler to receive it.
New: custom targets can now pass custom payloads to their SchemaHandler.Factory. The custom {} takes a map to its new field options.
Swift: Default values are now generated via a Defaulted property wrapper.
Swift: Fully-qualify Foundation.Data to prevent name collisions with messages named Data.
Move: Some types have been moved from wire-compiler to wire-run: WireRun, Target, DirectedAcyclicGraph, PartitionedSchema.
New: Add a dry run option. If enabled, the compiler will just emit the names of the source files that would be otherwise * generated to stdout. You can use the flag --dry_run with the Wire compiler or define the option with Gradle as the following:
wire {\n dryRun = true\n}\n
* Fix: Correctly set task dependencies on processResources if protoLibrary is set to true. * Fix: If a valid grpc-status header is present, raise a GrpcException rather than an IOException."},{"location":"changelog/#version-462","title":"Version 4.6.2","text":"
2023-05-11
Fix: Explicitly adds jvm variants of multiplatform artifacts into the BOM.
Fix: Produce Descriptors for messages without fields after pruning.
Fix: the version 4.5.6 had a breaking change which has been reverted in 4.6.0 without losing any functionality.
Update descriptor.proto from the 7dbe742 version of protocolbuffers/protobuf.
"},{"location":"changelog/#version-456-note-that-this-holds-a-breaking-change-update-directly-to-460-to-avoid-it","title":"Version 4.5.6 (Note that this holds a breaking change, update directly to 4.6.0 to avoid it.)","text":"
2023-04-25
Fix: JSON serialization is now bullet-proofed against Class.getDeclaredFields random ordering.
Perf: Add option wire.use_array to use primitive arrays for packed scalars. This should improve performances as it avoids autoboxing on the JVM. It will use the appropriate array type, for example repeated float would be represented as a FloatArray.
New: Check HTTP2 protocol is set for passed client to GrpcClient.
New: Add buildersOnly option for Java and Kotlin target, setting it to true will change the visibility of generate types\u2019 constructor to non-public.
Fix: Properly define api dependency for okio in wire-schema.
Fix: Sort input locations so they match on all platforms.
Fix: Avoid NPEs with kotlin 1.7.20 around source sets.
New: Custom schema handlers! Wire lets you now plug in your own logic to deal with the protobuf schema the way you want. Check our documentation for details. You can also check our recipe directory for examples. Note that this API obsoletes the CustomHandlerBeta type Wire had until now.
New: You can now easily create an in-memory protobuf schema with the new SchemaBuilder class. This lives in the new wire-schema-tests artifact. For usage examples, check the tests in custom handler recipes.
Breaking: the wire-profiles artifact has been removed and is now inlined in wire-schema.
Breaking: CoreLoader \u2018s isWireRuntimeProto methods are now static.
Breaking: SchemaLoader and related classes have been moved from wire-compiler to wire-schema.
New: Support packed and map fields when converting to/from JSON with Kotlin.
New: Support typesafe accessors and version catalogs in Wire plugin.
New: Generate annotations for repeated options.
New: Allow parsing of oneof options.
New: Support map fields in options.
New: Add macosArm64 support to the KMP projects supporting mac.
Fix: Properly deal with maps of scalar types, deserializing missing scala key/value into identity.
Fix: Fix a crash where ProtoMember was populated with the wrong data.
New: Publish a bill of materials (BOM) for Wire. Depend on this from Gradle or Maven to keep all of your Wire artifacts on the same version, even if they\u2019re declared via transitive dependencies. You can even omit versions when declaring other Wire dependencies.
dependencies {\n implementation(platform(\"com.squareup.wire:wire-bom:4.2.0\"))\n implementation(\"com.squareup.wire:wire-compiler\") // No version!\n implementation(\"com.squareup.wire:wire-gradle-plugin\") // No version!\n implementation(\"com.squareup.wire:wire-grpc-client\") // No version!\n // Etc.\n}\n
New: When using Wire JSON factories, you can now override the proto3 behavior of skipping default values when writing JSON. Set writeIdentityValues to true for either WireJsonAdapterFactory or WireTypeAdapterFactory to enable it.
Breaking: WireLogger methods has been refactored to remove platform dependencies and allow more precise callbacks. We might add new methods in the future for better logging still.
Removal: The dry-run option on WireCompiler has been removed.
Swift: WireCompiler podspec is now backup by a jar so consumers will not have to locally build it on pod install.
New: Add \u2018nameSuffix\u2019 parameter for configuring generated service-class names in Kotlin.
New: Define oneofName in @WireField.
New: Enable iosSimulatorArm64 for Kotlin multiplatform.
New: Expose the source .proto file at ProtoAdaper.sourceFile. This is null for built-in types and types generated prior to this release.
New: Generate Kotlin code whose members match the declaration order of the corresponding .proto files. In previous releases, generated members were sorted by kind (fields, oneofs), then by declaration order. With this update only declaration order is used. Note that this will change the encoded-bytes of these messages. This change is both forwards and backwards-compatible. Identical encoding of equal messages across Wire releases is typical but not guaranteed, and this is a rare release that changes that encoding. If you do cryptographic hashes on encoded proto messages, you will notice that the hashes are different in this release.
New: Option in SchemaLoader to exhaustively load imported files. By default we only load what\u2019s immediately necessary to generate code; this new option loads everything reachable into the schema.
New: Programmatic API to prune schemas. See Pruner in wire-schema.
New: SchemaLoader doesn\u2019t extend the Closeable interface anymore.
New: Support rpcRole = 'none' in the Gradle plugin to generate neither client nor server code.
New: Support for Android variants.
New: Support for glob syntax in srcJar includes.
New: Support for special float literals.
New: Swift support Timestamp and Duration.
New: The Wire plugin requires an output to be set. Before, it would generate Java code by default; it will now throw if there are no output defined.
New: The default value of emitAppliedOptions for our Java and Kotlin target is now set to true.
New: Wire should build and execute properly on Windows.
New: @WireRpc has a new sourceFile attribute.
New: GrpcClient.Builder.minMessageToCompress() configures which messages are compressed. This will completely disable compression if the size is Long.MAX_VALUE. We\u2019ve seen problems where some Golang gRPC servers don\u2019t support compression; setting this to MAX_VALUE is necessary to interop with them.
New: SchemaReflector is our initial implementation of the gRPC Server Reflection Protocol. Note that although we implement the business logic of gRPC reflection, we don\u2019t offer a gRPC server built into Wire.
New: wire-reflector bundles gRPC\u2019s reflection.proto which it is built upon.
New: wire-runtime exposes a com.squareup.wire.VERSION constant reflecting the project version.
New: change the Gradle plugin so that (unstable) custom handlers can be configured with instance instead of with a class name.
Fix: Be more aggressive about loading transitive files with SchemaLoader.loadExhaustively.
Fix: Bugs in JSON serialization of builder-less Kotlin types have been addressed.
Fix: Compile Kotlin/JS with both LEGACY and IR compilers.
Fix: Deep copy metadata on GrpcCall.clone().
Fix: Don\u2019t break task caching by using absolute paths in the Gradle plugin. Wire now uses project-relative paths in any attribute that is used as a cache key.
Fix: Don\u2019t crash encoding schemas when an option contains a repeated field, an enum, or a double.
Fix: Don\u2019t depend on moshi-kotlin in wire-moshi. This caused a transitive dependency on kotlin-reflect, which we neither needed nor wanted.
Fix: Don\u2019t generate invalid code when an enum constant is named name or ordinal.
Fix: Don\u2019t re-use the cache if protobuf inputs have changed.
Fix: Emitting proper protobuf format for option values defined as a list of enum constants.
Fix: Explicitly defined Wire gRPC server generation as experimental: the feature isn\u2019t complete.
Fix: Generate @Deprecated annotations on deprecated messages, fields, enums, and enum constants.
Fix: Handle out of order proto fields when initializing Kotlin constructors.
Fix: Handle writing/reading exceptions for duplex calls in Wire gRPC.
Fix: In Java, rename instances to avoid field and class name conflicts.
Fix: Locate files in the root package when importing.
Fix: Memory fixes found with Address Sanitizer in Swift.
Fix: Permit values other than 0 and 1 when decoding protobuf-encoded booleans. Previously we threw an IOException for other values; now all non-zero values are true.
Fix: Redact boxed OneOf fields.
Fix: Redacted Kotlin scalars now respect nullability.
Fix: Retain field order when emitting a schema as .proto files.
Fix: Reverse the topological sort of dependent files in SchemaReflector. We had problems with grpc-curl which expects the requested file to be listed first.
Fix: Support Kotlin-generated annotations on Java fields.
Fix: Support for serializing builder-less Kotlin generated classes to JSON.
Fix: Support reporting errors in CustomHandlerBeta.
Fix: Suppress deprecation warnings on generated enum\u2019s fromValue method in Kotlin.
Fix: Swift adapters will throw an error when encountering an unexpected ProtoReader.beginMessage() rather than calling fatalError().
Fix: Update the Wire Gradle plugin to clear the output directory before generating code. This prevents the need to do a clean build after removing a message type.
Fix: Update the Wire Gradle plugin to register generated .java sources with the Java compiler. Previously this was broken if the Kotlin plugin was installed.
Fix: Use Gradle\u2019s logging mechanism to reduce output when Wire generates code.
Fix: Use correct type when referencing a custom adapter in Kotlin generated code.
Fix: Use relative path sensitivity and file collection.
Fix: Validate enum constant uniqueness for the entire package.
Fix: Wire Gradle plugin tasks have been modernized with configuration caching support.
Fix: Wire will not generate respective built-in types for Java, Kotlin, and Swift generation. Those are usually the google types for which Wire will provide its own implementation.
Upgrade: Update KotlinPoet to 1.8.0.
Upgrade: OkHttp 4.9.3.
Upgrade: Okio 3.0.0. We now use Okio 3\u2019s FileSystem in SchemaLoader, which makes it easier to load .proto files from the classpath. This is binary-incompatible with the Okio 3.0 alpha releases.
New: srcProject(\":project-name\") makes it easier to depend on .proto files of other projects.
Fix: Don\u2019t require source that .proto directories exist at Gradle plugin configuration time. This was preventing Wire from using other tasks\u2019 outputs as its inputs.
Fix: The Wire Gradle plugin now supports Java only Android projects.
Fix: In the Wire Gradle plugin, sourcePath will now include only protos defined with include if the option is present. It used to include all existing .proto files even if include was used.
New: Full support Optional Int64 and UInt64 for JSONString in Swift.
New: Automatically add a dependency when a protoPath or protoSource depends on a project.
New: protoPath and protoSource dependencies are now not transitive by default.
New: New protoLibrary option for the Wire Gradle plugin. Configuring a project as a protoLibrary will cause the generated .jar file to include .proto sources.
New: Code generation for plain gRPC server. The Kotlin target now has a new grpcServerCompatible option which if set to true will generate gRPC server-compatible classes.
New: Introduce GrpcException.
New: Add GrpcMethod tag to the request.
New: Adds redacting support for Moshi JSON adapters.
New: Publish plugin marker for Gradle plugin.
Fix: Escape square brackets in Kotlin generated code documentation.
New: Proto3 support! This includes the new behaviors, the new types, and the JSON.
New: Swift support for proto2 schemas. The details are in our blog post.
New: Wire will now throw an error when:
two generated files end up overriding each other,
imports form a cycle,
packages form a cycle. This can be turned off with the flag permitPackageCycles,
an option within the source set cannot be resolved,
there are name duplications of members in a message, or of rpcs in a service,
a map is used as an extension.
New: Support for the json_name pseudo option.
New: The wire_package file option allows one to set the JVM package where classes generated from the concerned file will be placed. wire_package takes precedence over java_package.
New: Lists and maps in Kotlin generated code are now immutable.
New: Support UTF-8 with BOM in proto files.
New: wire.since and wire.until have been renamed with the prefix constant_ for EnumValueOptions.
New: Wire generates 1) annotations for options which 2) gets assigned to the generated code where appropriate. Both behavior can be turn on or off via the flags:
emitDeclaredOptions: True to emit types for options declared on messages, fields, etc. Default to true,
emitAppliedOptions: True to emit annotations for options applied on messages, fields, etc. Default to false.
Fix: Recursive map values.
Fix: Long expressions in equals and encodedSize functions.
New: onlyVersion option on the Wire Gradle plugin to target a unique version. By and large, service code that supports many clients would target ranges via sinceVersion and untilVersion, while client code would target a unique version via onlyVersion.
New: Support for optional fields in Proto3.
Fix: Restored the GrpcClient.create API to create implementations for gRPC interfaces.
New: wire.since and wire.until options on members and enum values. You can prune fields or constants using these two options. When generating code with the Wire Gradle plugin, define sinceVersion and/or untilVersion to scope the generated code.
New: Messages\u2019 toString method on Kotlin and Java now escape string values for easy parsing.
Fix: Link the entire descriptor.proto every time when building the Schema.
Fix: Properly handle members named after keywords of the target language for both Java and Kotlin.
Fix: Use the declared name for keys in JSON when emitting/reading keyword named members.
Fix: Generated Kotlin code is malformed for long identifiers.
Fix: Make the Wire Gradle plugin compatible with instant execution.
This release includes major non-backwards-compatible API changes to the wire-schema module. This will break tools that use Wire\u2019s schema modeling as a standalone library. We are making big changes to this component and we sacrificed API compatibility to accelerate these improvements.
New: proto { ... } target in the Wire Gradle plugin. Use this to perform basic source code transformations on collections of .proto files. We use it to prune large collections of protos to just the subset used by the application.
Fix: Support all forms of reserved extensions, such as extensions 1, 3 to 5, 7;.
Fix: Don\u2019t re-generate source files when their .proto files haven\u2019t changed.
New: includes, excludes, root, and prune give precedence to the most precise rule. Previously excludes always took precedence over includes, and prune always took precedence over root.
Fix: Generate non-instantiable class for enclosing types in Kotlin. These are emitted when a nested type is retained but its enclosing type is pruned.
Fix: Do not fail to build when the profile cannot find a dependency.
Fix: Use the correct adapter path for gRPC endpoints that customize the Java package.
Fix: Preserve documentation in generated services.
Fix: Fail to generate code if the source directory doesn\u2019t exist.
Fix: Make Kotlin consistent with Java for unknown enum constants. We now treat these as unknown fields rather than failing to decode the enclosing message.
Update: Total rewrite of the generated interfaces for clients:
Introduce two interfaces, GrpcCall for simple RPCs, and GrpcStreamingCall fox duplex ones. Both will provide blocking and suspending API, including a reference to the underlying OkHttp Call object and its timeout.
Starting with this version, wire-runtime is published as a multiplatform Kotlin artifact. While the JVM artifact is binary- and behavior-compatible with 3.0.0-alpha01, artifacts for other platforms may not work correctly at this point. The artifact name for the JVM artifact has been changed to wire-runtime-jvm: now, in order to depend on the multiplatform runtime, use the following Gradle dependency declaration:
api \"com.squareup.wire:wire-runtime:3.0.0-alpha02\"\n
and if you want to depend on the JVM artifact only, use the following declaration:
api \"com.squareup.wire:wire-runtime-jvm:3.0.0-alpha02\"\n
New: Generate RPCs as Single Abstract Methods.
New: Add \u201csingleMethod\u201d Gradle plugin configuration for services.
New: Add \u201cblockingServices\u201d Gradle plugin configuration for services.
New: Support packageless services code generation.
Wire 3 can generate Kotlin data classes. To enable this feature via the command line API, pass in the --kotlin_out parameter that should specify the output directory for the generated *.kt files. Given the following simple proto:
message Person {\n required string name = 1;\n required int32 id = 2;\n optional string email = 3;\n}\n
the generated Kotlin code will look like the following:
data class Person(\n @field:WireField(tag = 1, adapter = \"com.squareup.wire.ProtoAdapter#STRING\")\n val name: String,\n @field:WireField(tag = 2, adapter = \"com.squareup.wire.ProtoAdapter#INT32\")\n val id: Int,\n @field:WireField(tag = 3, adapter = \"com.squareup.wire.ProtoAdapter#STRING\")\n val email: String? = null,\n val unknownFields: ByteString = ByteString.EMPTY\n) : Message<Person, Person.Builder>(ADAPTER, unknownFields) {\n companion object {\n @JvmField\n val ADAPTER: ProtoAdapter<Person> = ... // code omitted for brevity\n
The copy() method of a data class replaces most usages of the builder. If your code relies on the Builder, you can enable full Builder generation by passing the --java_interop parameter to the compiler.
New: gRPC support
In addition to generating Kotlin code from proto messages, Wire can now generate code for gRPC endpoints. Here\u2019s an example schema:
service RouteGuide {\n // A simple RPC.\n //\n // Obtains the feature at a given position.\n //\n // A feature with an empty name is returned if there's no feature at the given\n // position.\n rpc GetFeature(Point) returns (Feature) {}\n}\n
The generated code will look like the following (message protos, referenced by the schema, are omitted):
All four gRPC modes are supported: the generated code uses suspendable functions to implement non-blocking asynchronous execution. In streaming modes, ReceiveChannel and SendChannel are used to listen to asynchronous data in a non-blocking fashion.
This feature works out of the box in Wire 3 compiler as long as the input file contains a gRPC schema.
New: Gradle plugin
Here\u2019s an example Gradle configuration:
apply plugin: 'com.squareup.wire'\n\nwire {\n // Keeps only 'Dinosaur#name' as the root of the object graph\n roots 'squareup.dinosaurs.Dinosaur#name'\n\n // Keeps all fields, except 'name', in 'Dinosaur'\n prunes 'squareup.dinosaurs.Dinosaur#name'\n\n // Both roots and prunes in an external file\n rules 'rules.txt'\n\n kotlin {\n javaInterop true\n out \"${buildDir}/generated/custom\"\n }\n}\n
The wire extension introduces the concept of compilation targets, such as kotlin and java, where each target has its own configuration properties. Multiple targets can be supplied, which benefits use cases such as migrating Java protos to Kotlin.
New: Decouple the option of using Android annotations for nullability from the option of having messages implement Parcelable.
New: Wire Moshi adapter for serializing proto JSON representation using the Moshi library.
New: Implement support for custom enum types.
New: Generate AndroidX nullability annotations instead of old support library annotations.
New: Import JSR 305 and use it to mark nullability of public API.
New: Allow inline multiline comments.
New: Generate an empty class when a nested message is retained but its parent was pruned.
New: Support rendering a ProtoFile to its schema.
New: Support hexadecimal numeric literals.
New: Allow custom types to be constrained with a \u2018with\u2019 clause.
New: Generate a constructor which takes in a Message.Builder instead of all fields separately.
New: Add location to the error message about unsupported group elements.
New: Permit single files to be used on the proto path.
Fix: Emit \u2018=\u2019 for syntax declaration.
Fix: Don\u2019t crash when a comment has a dollar sign.
Fix: Return subclass type instead of abstract parameterized type for newBuilder.
Fix: Validate enum namespace in file context are unique.
New: Support for map type in the schema, compiler, and runtime!
New: AndroidMessage base class consolidates everything required for supporting Android and will now be used for generating code with --android.
New: stream keyword in RPC definitions is now parsed and exposed in the schema.
Fix: Nested types which are retained no longer cause their enclosing type to be retained. Instead, non-instantiable empty types will be generated for pruned enclosing types.
Fix: Remove per-type Parcelable.Creator classes and instead use a single type which delegates to the message\u2019s ProtoAdapter.
Fix: Retain information on redacted fields even when options were pruned.
Fix: Do not generate code for handling null from list types (and now map types) which are guaranteed to never be null.
Empty lists of packed values were being encoded incorrectly. In Wire 2.0.x our message adapters incorrectly included empty lists for [packed=true] rather than omitting them. This is now fixed.
New: Message.encode() to concisely encode a message.
New: MessageAdapter.decode(ByteString) to decode a message from a byte string without an intermediate byte array.
New: Wire now includes a sample code generation for service interfaces.
New: ProtoAdapter.get overload which returns an adapter given an instance of a message.
New: @Nullable annotations are emitted for optional fields when using --android.
Fix: Remove the need for javac to generate synthetic accessor methods in the generated code. This results in smaller code size and less method references (for Android users).
Fix: Exclude unknown fields when encoding JSON and drop unknown fields when parsing JSON.
Fix: Ensure JSON encoding and decoding works in the default generation mode (not just --compact) by always adding @WireField metadata to message fields.
Fix: Update to JavaPoet 1.4 for more accurate generation of valid Java code.
Fix: Do not emit case statements for aliased enum constant values. The first constant for a value will be returned when deserializing.
Fix: Emit @Deprecated annotation on deprecated enum constants.
Fix: Correctly prune dependencies of excluded message, enum, or service members. Previously the dependencies of an excluded member were retained despite the member itself being omitted.
Wire 2 is a backwards-incompatible release. It makes breaking changes to the compiler, runtime, extensions, and generated code. These changes aren\u2019t made lightly as we\u2019ve endured the upgrade in our own projects! We believe the cost of migration is worth the benefits.
We\u2019ve created the wire-schema library that models .proto schema definitions. This is a capable library that packs several neat features. You can load a Schema from .proto files located on the local file system, a ZIP or JAR file, or any java.nio.FileSystem like Jimfs. You can prune this schema with includes or excludes, allowing you to reuse .proto definitions with minimal code. And you can decode data directly from a schema: no code generation is necessary!
We\u2019ve flattened extensions. Wire 2.0 combines the fields defined directly on messages with fields defined far away in extensions. In the generated code, extension fields look just like every other field! One limitation of this approach is that it\u2019s no longer possible to compile extensions separately from the messages they extend. For this reason we now recommend always generating all Wire code in a single step.
We\u2019ve rearranged the runtime. Types related to the protocol buffers format are now prefixed Proto and types related to our implementation are prefixed Wire. To encode and decode messages you must first get an adapter either from the ADAPTER constant or from ProtoAdapter.get(). You no longer need a Wire instance!
New ADAPTER constant on most messages gives access to encode & decode values. This replaces the encoding and decoding methods on Wire.
Guard against null lists. Code that passes null to builder methods expecting a List used to accept that; now Wire throws a NullPointerException. Similarly list elements must also be non-null.
New Message.newBuilder() API. This replaces the previous copy constructor on Builder.
New: Always use Wire\u2019s bundled descriptor.proto. Previously to define custom options you needed to import a potentially-inconsistent descriptor.
New: Emit all types when no .proto files are explicitly specified.
New: Generate code for encoding and decoding messages. The previous, reflection-based encoder and decoder are accessible with --compact.
New: ServiceFactory has been removed. To generate code for your services, load a schema with wire-schema and then use a library like JavaPoet to generate your own code. The JavaGenerator class can be used to look up Java names of message types.
New: Compiler will load all .proto files if none are explicitly specified.
New: Load .proto files from ZIP and JAR files.
New: The --android flag causes Wire messages to implement Parcelable.
New: Support multiple --proto_path arguments
New: The --named_files_only flag limits which .proto files yield .java files. This was the default in Wire 1.x.
New: The --no_options flag has been deleted. Use --excludes=google.protobuf.* instead.
New: Messages implement Serializable. The serialized form follows protobuf encoding, so renaming fields is safe as long as tags are consistent. (Renaming classes is unsafe, however). Note that extension fields are deserialized as unknown fields.
"},{"location":"code_of_conduct/","title":"Open Source Code of Conduct","text":"
At Square, we are committed to contributing to the open source community and simplifying the process of releasing and managing open source software. We\u2019ve seen incredible support and enthusiasm from thousands of people who have already contributed to our projects\u200a\u2014\u200aand we want to ensure our community continues to be truly open for everyone.
This code of conduct outlines our expectations for participants, as well as steps to reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all and expect our code of conduct to be honored.
Square\u2019s open source community strives to:
Be open: We invite anyone to participate in any aspect of our projects. Our community is open, and any responsibility can be carried by a contributor who demonstrates the required capacity and competence.
Be considerate: People use our work, and we depend on the work of others. Consider users and colleagues before taking action. For example, changes to code, infrastructure, policy, and documentation may negatively impact others.
Be respectful: We expect people to work together to resolve conflict, assume good intentions, and act with empathy. Do not turn disagreements into personal attacks.
Be collaborative: Collaboration reduces redundancy and improves the quality of our work. We strive for transparency within our open source community, and we work closely with upstream developers and others in the free software community to coordinate our efforts.
Be pragmatic: Questions are encouraged and should be asked early in the process to avoid problems later. Be thoughtful and considerate when seeking out the appropriate forum for your questions. Those who are asked should be responsive and helpful.
Step down considerately: Members of every project come and go. When somebody leaves or disengages from the project, they should make it known and take the proper steps to ensure that others can pick up where they left off.
This code is not exhaustive or complete. It serves to distill our common understanding of a collaborative, shared environment, and goals. We expect it to be followed in spirit as much as in the letter.
We encourage everyone to participate and are committed to building a community for all. Although we may not be able to satisfy everyone, we all agree that everyone is equal.
Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong.
Although this list cannot be exhaustive, we explicitly honor diversity in age, culture, ethnicity, gender identity or expression, language, national origin, political beliefs, profession, race, religion, sexual orientation, socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected characteristics above, including participants with disabilities.
If you experience or witness unacceptable behavior\u200a\u2014\u200aor have any other concerns\u200a\u2014\u200aplease report it by emailing codeofconduct@squareup.com. For more details, please see our Reporting Guidelines below.
Some of the ideas and wording for the statements and guidelines above were based on work by the Twitter, Ubuntu, GDC, and Django communities. We are thankful for their work.
If you experience or witness unacceptable behavior\u200a\u2014\u200aor have any other concerns\u200a\u2014\u200aplease report it by emailing codeofconduct@squareup.com. All reports will be handled with discretion.
In your report please include:
Your contact information.
Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please include them as well.
Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link.
Any additional information that may be helpful.
After filing a report, a representative from the Square Code of Conduct committee will contact you personally. The committee will then review the incident, follow up with any additional questions, and make a decision as to how to respond.
Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the Square Code of Conduct committee may take any action they deem appropriate, up to and including a permanent ban from all of Square spaces without warning.
Keeping the project small and stable limits our ability to accept new contributors. We are not seeking new committers at this time, but some small contributions are welcome.
If you\u2019ve found a security problem, please follow our bug bounty program.
If you\u2019ve found a bug, please contribute a failing test case so we can study and fix it.
Before code can be accepted all contributors must complete our Individual Contributor License Agreement (CLA).
Square recognizes the important contributions the security research community can make. We therefore encourage reporting security issues with the code contained in this repository.
If you believe you have discovered a security vulnerability, please follow the guidelines at https://bugcrowd.com/squareopensource
Wire has two key components: a compiler that generates source code at build time, and a runtime library that supports the generated code when your program executes. The compiler is very configurable; this guide explains its features and their use.
plugins {\n id 'application'\n id 'org.jetbrains.kotlin.jvm'\n id 'com.squareup.wire'\n}\n\nwire {\n kotlin {}\n}\n
The plugin will read the .proto schema definitions, validate them, link them, and generate Kotlin code. It uses KotlinPoet internally to generate compact and legible source files.
If sourcePath isn\u2019t set, Wire will look for .proto files in src/main/proto by default.
Wire will generate files in build/generated/source/wire. It\u2019ll also register this directory as a source directory for the project so the generated sources are compiled by the Kotlin compiler.
Replace kotlin with java to generate the Java sources instead.
"},{"location":"wire_compiler/#inputs-and-outputs","title":"Inputs and Outputs","text":"
Wire can pull source .proto schema definitions from a local directory, a local .jar file, or an external artifact specified with Maven coordinates.
Wire can emit multiple languages in the same build. Use includes to specify which types are emitted for a target language; subsequent languages will emit what\u2019s left over.
Note that sources are specified as file system paths (slash delimiter) and targets are specified as Proto type names (dot delimiter).
You may also specify targets with excludes. If you have both includes and excludes, excludes take precedence.
wire {\n ...\n\n kotlin {\n // Kotlin emits everything but sales and geo packages.\n excludes = ['com.example.sales.*', 'com.example.geo.*']\n }\n java {\n // Java gets those because they're left over.\n }\n}\n
Wire will print a warning if any name in includes or excludes is unused.
When configuring Wire you must use the package name from the .proto file\u2019s package declaration. The option java_package name is not used for Wire configuration.
"},{"location":"wire_compiler/#proto-path-for-libraries","title":"Proto Path for Libraries","text":"
Large projects may span multiple modules. To support this Wire has a \u2018proto path\u2019. The .proto schema files on this path are used for linking and validation, but they do not yield files in the generated output.
The proto path supports the same inputs as the source path: directories, .jar files, and Maven coordinates. Similarly, the proto path may be filtered with include.
The source path and proto path are linked together but only types on the source path are generated.
"},{"location":"wire_compiler/#dependencies-between-gradle-modules","title":"Dependencies between Gradle Modules","text":"
Wire provides support to define dependencies between modules within the same project.
A module can include its .proto files into the output resources. Use this when your .jar file can be used as a library for other proto or Wire projects. Note that only the .proto files used in the library will be included.
wire {\n protoLibrary = true\n}\n
Wire also creates two configurations, protoPath and protoSource you can use to define a dependency on another proto or Wire project.
dependencies {\n // The task `:common-protos:jar` will be added into the dependency\n // graph of this module for the Wire generating tasks.\n protoPath(project(':common-protos'))\n implementation(project(':common-protos'))\n}\n\nwire {\n kotlin {\n }\n}\n
Note that protoPath and protoSource dependencies are not transitive by default. If needed, you can change it manually.
For mobile projects it\u2019s easy to generate a lot of unnecessary code. For example, a .proto schema might support types for obsolete features.
General-purpose code-shrinking tools like R8 and ProGuard have difficulty shrinking Wire-generated sources because the encode() and decode() functions still use them. Instead, Wire offers its own code shrinker to eliminate unwanted declarations early.
Use prune to precisely eliminate an unwanted type or member. These will be eliminated along with all references to them.
Another way to prune obsolete fields is to assign them a version, then to generate your code against a version range or a unique version. The fields out of the version range will get pruned.
Members may be declared with wire.since and wire.until options; enum constant can use wire.constant_since and wire.constant_until. For example, these options declare a field age that was replaced with birth_date in version \u201c5.0\u201d:
import \"wire/extensions.proto\";\n\nmessage Singer {\n optional string name = 1;\n optional int32 age = 2 [(wire.until) = \"5.0\"];\n optional Date birth_date = 3 [(wire.since) = \"5.0\"];\n}\n
Client code should typically target a single version. In this example, clients will have the name and birth_date fields only.
wire {\n onlyVersion \"5.0\"\n}\n
Service code that supports many clients should support the union of versions of all supported clients. Such code will have name, as well as both the age and birth_date fields.
By default, .proto input files are not included in the generated .jar artifact. Use the protoLibrary option to include them:
wire {\n protoLibrary = true\n}\n
This is most useful when building .jar files for other wire tasks to use as dependencies. Note that only the true sources are included \u2013 proto messages that are pruned or not used are not included in the output artifact.
Here\u2019s an exhaustive Java configuration. Booleans are shown with their default behavior.
wire {\n java {\n // Proto types to include generated sources for. Types listed here will be\n // generated for this target and not for subsequent targets in the task.\n //\n // This list should contain package names (suffixed with `.*`) and type\n // names only. It should not contain member names.\n includes = ['com.example.pizza.*']\n\n // Proto types to excluded generated sources for. Types listed here will\n // not be generated for this target.\n //\n // This list should contain package names (suffixed with `.*`) and type\n // names only. It should not contain member names.\n excludes = ['com.example.sales.*']\n\n // True if types emitted for this target should not also be emitted for\n // other targets. Use this to cause multiple outputs to be emitted for the\n // same input type.\n exclusive = true\n\n // Directory to emit to.\n out \"${buildDir}/custom\"\n\n // True for emitted types to implement android.os.Parcelable.\n android = false\n\n // True to enable the androidx.annotation. Nullable annotation\n // where applicable.\n androidAnnotations = false\n\n // True to emit code that uses reflection for reading, writing, and toString\n // methods which are normally implemented with generated code.\n compact = false\n\n // True to turn visibility of all generated types' constructors\n // to non-public.\n buildersOnly = false\n\n // True to emit types for options declared on messages, fields, etc.\n emitDeclaredOptions = true\n\n // True to emit annotations for options applied on messages, fields, etc.\n emitAppliedOptions = true\n }\n}\n
Here\u2019s an exhaustive Kotlin configuration. Booleans and enums are shown with their default behavior.
wire {\n kotlin {\n // Proto types to include generated sources for. Types listed here will be\n // generated for this target and not for subsequent targets in the task.\n //\n // This list should contain package names (suffixed with `.*`) and type\n // names only. It should not contain member names.\n includes = ['com.example.pizza.*']\n\n // Proto types to excluded generated sources for. Types listed here will not\n // be generated for this target.\n //\n // This list should contain package names (suffixed with `.*`) and type\n // names only. It should not contain member names.\n excludes = ['com.example.sales.*']\n\n // True if types emitted for this target should not also be emitted for\n // other targets. Use this to cause multiple outputs to be emitted for the\n // same input type.\n exclusive = true\n\n // Directory to emit to.\n out \"${buildDir}/custom\"\n\n // True for emitted types to implement android.os.Parcelable.\n android = false\n\n // True for emitted types to implement APIs for easier migration from the\n // Java target.\n javaInterop = false\n\n // True to turn visibility of all generated types' constructors\n // to non-public.\n buildersOnly = false\n\n // True to emit types for options declared on messages, fields, etc.\n emitDeclaredOptions = true\n\n // True to emit annotations for options applied on messages, fields, etc.\n emitAppliedOptions = true\n\n // `suspending` to generate coroutines APIs that require a Kotlin\n // coroutines context.\n // `blocking` to generate blocking APIs callable by Java and Kotlin.\n rpcCallStyle = 'blocking'\n\n // `client` to generate interfaces best suited to sending outbound calls.\n // `server` to generate interfaces best suited to receiving inbound calls.\n // `none` to not generate services.\n rpcRole = 'server'\n\n // If set, the value will be appended to generated service type names. If\n // null, their rpcRole will be used as a suffix instead.\n nameSuffix = \"Suffix\"\n\n // True for emitted services to implement one interface per RPC.\n singleMethodServices = false\n\n // Set how many oneof choices are necessary for generated message classes to use the\n // `OneOf<Key<T>, T>` form rather than the default, where options are flattened into the\n // enclosing type.\n boxOneOfsMinSize = 5000\n\n // True to escape Kotlin keywords like `value` and `data` with backticks. Otherwise an\n // underscore underscore is added as a suffix, like `value_` and `data_`.\n escapeKotlinKeywords = false\n\n // Defines how an protobuf enum type is to be generated. See `com.squareup.wire.kotlin.EnumMode`\n enumMode = \"enum_class\"\n }\n}\n
Here\u2019s an exhaustive Proto configuration. You can use this target to generate a pruned proto schema, or to pretty-print one. Note that even with multiple outputs set, the proto target will always emit all types, all services, and all extensions of the schema.
wire {\n proto {\n // Directory to emit to.\n out \"${buildDir}/custom\"\n }\n}\n
With a custom schema handler, you can handle a proto schema in any way you want, including code generation or other side effects such as validation, logging, etc.
You\u2019ll need to first extend the SchemaHandler class, and then the SchemaHandler.Factory interface which is to return an instance of the former. See our recipes for different use cases\u2019 implementations.
Build that into an jar artifact and add that as a buildscript dependency to your Gradle project.
Next configure the Wire plugin to call your custom handler. Here\u2019s an exhaustive custom configuration. Booleans and enums are shown with their default behavior.
wire {\n custom {\n // The name of a Java class to generate code with. This class must:\n // * be in the buildscript dependencies for this Gradle project\n // * be a public class\n // * have a public no-arguments constructor\n // * implement the com.squareup.wire.schema.SchemaHandler.Factory interface\n schemaHandlerFactoryClass = \"com.example.MyCustomHandlerFactory\"\n\n // These options work the same as the java and kotlin targets above.\n includes = ['com.example.pizza.*']\n excludes = ['com.example.sales.*']\n exclusive = true\n out \"${buildDir}/custom\"\n\n // Custom payload which can be passed to the `SchemaHandler.Factory`.\n options = [a: \"one\", b: \"two\", c: \"three\"]\n }\n}\n
The easiest way to get started is to use CocoaPods.
# Add the Wire compiler so that it is downloaded and available.\n# CocoaPods will download the source and build the compiler directly,\n# so you'll need Java installed.\npod 'WireCompiler'\n\n# Add the Wire runtime to do the serializing/deserializing\npod 'Wire'\n
Then run pod install to get the dependencies and build the Wire compiler.
Swift Package Manager is also supported for linking the Wire runtime.
"},{"location":"wire_compiler/#build-your-protos","title":"Build Your Protos","text":"
The Wire compiler uses SwiftPoet to generate Swift code. The resulting objects automatically conform to Equatable, Codable and Sendable.
Assuming you\u2019ve used CocoaPods to download the Wire compiler, to compile your protos into Swift files:
java -jar ./Pods/WireCompiler/compiler.jar \\\n \"--proto_path=<directory containing .proto files>\" \\\n \"--swift_out=<directory where the generated .swift files go>\" \\\n \"--experimental-module-manifest=<path to manifest yaml file>\"\n
Swift introduced a new challenge that didn\u2019t exist with Kotlin and Java: modules. Kotlin and Java both use fully-qualified package names, but Swift modules are defined by their compilation unit, and thus namespaces aren\u2019t declared at the type or file level. This meant that we needed to build a new packaging system for Swift that could deal with Swift module namespacing and imports.
We decided that the easiest way for a caller to define modules was to make those definitions handled directly by Wire. A single manifest file defines the modules, their names, their dependencies, and the content roots and prunes mentioned above.
In this example manifest the DarkSide and LightSide modules would depend on and import the CommonProtos module:
The Wire compiler will generate interfaces for your service RPCs defined in your protobuf schema; under the condition that the target is set to Kotlin.
You can configure how your services are generated via the Gradle plugin:
wire {\n // Kotlin target will generate code for services.\n kotlin {\n // `client` to generate interfaces best suited to sending outbound calls.\n // `server` to generate interfaces best suited to receiving inbound calls.\n rpcRole = 'server'\n // Server only\n // `suspending` to generate coroutines APIs that require a Kotlin coroutines context.\n // `blocking` to generate blocking APIs callable by Java and Kotlin.\n rpcCallStyle = 'suspending'\n // Server only\n // True for emitted services to generate one interface per RPC.\n singleMethodServices = false\n }\n}\n
The generated code varies depending on your RPC role, namely client or server. We\u2019ll use the following schema to demonstrate how they differ:
"},{"location":"wire_grpc/#grpc-for-clients","title":"gRPC for Clients","text":"
For the schema RouteGuide, when rpcRole is client, the Wire compiler will generate the following interface:
interface RouteGuideClient : Service {\n fun GetFeature(): GrpcCall<Point, Feature>\n\n fun ListFeatures(): GrpcStreamingCall<Rectangle, Feature>\n\n fun RecordRoute(): GrpcStreamingCall<Point, RouteSummary>\n\n fun RouteChat(): GrpcStreamingCall<RouteNote, RouteNote>\n}\n
For streaming APIs, we return a GrpcStreamingCall, and a GrpcCall otherwise. With these objects, the caller can communicate with the server. Both blocking and suspending APIs are provided.
To help you instantiate your service, we provide a small runtime, namely GrpcClient:
val grpcClient = GrpcClient.Builder()\n .client(OkHttpClient.Builder().protocols(listOf(Protocol.H2_PRIOR_KNOWLEDGE)).build())\n .baseUrl(serverUrl)\n .build()\nval routeGuideClient = grpcClient.create(RouteGuideClient::class)\n
"},{"location":"wire_grpc/#grpc-for-servers","title":"gRPC for Servers","text":""},{"location":"wire_grpc/#blocking-apis","title":"Blocking APIs","text":"
the Wire compiler will generate the following interface for the server to implement:
interface RouteGuideBlockingServer : Service {\n fun GetFeature(request: Point): Feature\n\n fun ListFeatures(request: Rectangle, response: MessageSink<Feature>)\n\n fun RecordRoute(request: MessageSource<Point>): RouteSummary\n\n fun RouteChat(request: MessageSource<RouteNote>, response: MessageSink<RouteNote>)\n}\n
For streaming connections, the server can use Wire\u2019s blocking APIs: MessageSource and MessageSink."},{"location":"wire_grpc/#suspending-apis","title":"Suspending APIs","text":"
the Wire compiler will generate the following interface for the server to implement:
interface RouteGuideServer : Service {\n suspend fun GetFeature(request: Point): Feature\n\n fun ListFeatures(request: Rectangle, response: SendChannel<Feature>)\n\n fun RecordRoute(request: ReceiveChannel<Point>): RouteSummary\n\n fun RouteChat(request: ReceiveChannel<RouteNote>, response: SendChannel<RouteNote>)\n}\n
The server can use Kotlin coroutines\u2019 suspend and Channels mechanisms to execute suspending network calls."},{"location":"wire_grpc/#implementing-client-interfaces","title":"Implementing Client Interfaces","text":"
Wire has helper functions to make it easier to implement its client interfaces. This can be particularly useful for testing. It supports both streaming and non-streaming APIs in Kotlin:
The client interface may also be implemented in Java. Wire only offers a non-streaming helper function. The GrpcStreamingCall above uses coroutines which is Kotlin-only.
public class FakeRouteGuideClient implements RouteGuideClient {\n @Override public GrpcCall<Point, Feature> GetFeature() {\n return GrpcCalls.grpcCall(new Function1<Point, Feature>() {\n @Override public Feature invoke(Point request) {\n return new Feature.Builder()\n .name(\"test\")\n .location(request)\n .build();\n }\n });\n }\n\n ...\n}\n
These similarly interact nicely with Java lambdas.
The modules wire-grpc-server and wire-grpc-server-generator have been extracted out of Wire 5. They now live as a standalone repository square/wire-grpc-server/.
grpcServerCompatible does not exist anymore. You are to pass the new GrpcServerSchemaHandler to Wire in a custom block.
After
wire {\n custom {\n // Be sure that `server-generator` is on the classpath for Gradle to resolve\n // `GrpcServerSchemaHandler`.\n schemaHandlerFactory = com.squareup.wire.kotlin.grpcserver.GrpcServerSchemaHandler.Factory()\n options = mapOf(\n // Defaults to `true` if absent. Any other value than `true` is considered false.\n \"singleMethodServices\" to \"false\",\n // Defaults to `suspending` if absent. Any other value than `suspending` is considered\n // non-suspending.\n \"rpcCallStyle\" to \"suspending\",\n )\n // We set the custom block exclusivity to false so that the next `kotlin {}` block can also\n // generate the protobuf Messages.\n exclusive = false\n }\n\n kotlin {\n rpcRole = \"server\"\n singleMethodServices = false\n rpcCallStyle = \"suspending\"\n }\n}\n
For any problem with the migration, please ask on wire-grpc-server.
Moshi support is part of the wire-moshi-adapter module. It has to be added to the project dependencies in order to plug the WireJsonAdapterFactory into Moshi.
The Maven coordinates are: com.squareup.wire:wire-moshi-adapter:<version>
Moshi support is part of the wire-gson-support module. It has to be added to the project dependencies in order to plug the WireTypeAdapterFactory into Gson.
The Maven coordinates are: com.squareup.wire:wire-gson-support:<version>
Wire is interoperable with protoc for all proto3 messages. The JSON representation of proto2 is unspecified. JSON representations of proto2 messages from Wire and protoc are not interoperable. Note that by default Protoc throws an error for unknown fields. Wire will ignore them.
"},{"location":"wire_vs_protoc/","title":"Wire versus Protoc","text":""},{"location":"wire_vs_protoc/#non-primitive-types","title":"Non-Primitive Types","text":"
Protoc generates literal equivalents for all the Proto3 new types like empty, struct, etc. Wire tries to reuse existing types in the corresponding language when possible. The only new type Wire brings is AnyMessage for the google.protobuf.Any proto type.
The Any type wraps an arbitrary protobuf message by holding a field to identify its type and another field for storing the serialized representation of the wrapped message. Wire comes with its own AnyMessage type to represent google.protobuf.Any.
class AnyMessage(\n val typeUrl: String,\n val value: okio.ByteString\n)\n
It comes with a few methods to wrap or unwrap the embedded message.
// Wire\nval anyMessage: AnyMessage = AnyMessage.pack(person)\nval person: Person = anyMessage.unpack(Person.ADAPTER)\n\n// Protoc\nval any: Any = Any.pack(foo)\nval person: Person = any.unpack(Person.class)\n
Both google.protobuf.Duration and google.protobuf.Timestamp types will be generated by using their JVM equivalent: java.time.Duration and java.time.Instant. For non-JVM platforms, we provide two new Wire types with the same APIs:
class com.squareup.wire.Duration {\n fun getSeconds(): Long\n fun getNano(): Int\n}\nfun durationOfSeconds(seconds: Long, nano: Long): Duration\n\nclass com.squareup.wire.Instant {\n fun getEpochSecond(): Long\n fun getNano(): Int\n}\nfun ofEpochSecond(epochSecond: Long, nano: Long): Instant\n
google.protobuf.Struct is meant mainly to represent JSON objects in code. Instead of building new types, Wire reuses Java/Kotlin native types to represent all Struct types.
Google Protobuf Type Wire\u2019s Java Equivalent Wire\u2019s Kotlin Equivalent StructMap<String, ?>Map<String, ?>?ListValueList<?>List<?>?ValueObjectAny?NullValueVoidNothing?
One difference worth noting between Protoc and Wire is that Protoc can make the difference between an absent value, and a null value, Wire doesn\u2019t. Wire will always write nulls in JSON objects except at the root of it.
Wire didn\u2019t create new types for wrappers either, each wrapper will be represented by a nullable version of the primitive type it defines. For instance google.protobuf.FloatValue will be represented in Java by the float boxed type @Nullable Float, in Kotlin by Float?.
While Proto2 didn\u2019t, Proto3 defines Protobuf serialization over JSON. Wire and Protoc are interoperable but their API are quite different. Wire offers JSON serialization over Moshi or Gson. Protoc brings its own JsonFormatter. Beware that Protoc throws an error for unknown fields, you need to configure it to opt-out of this behavior!