syntax = "proto3";
message Message {
string a = 1;
optional string b = 2;
}
Slide 13
Slide 13 text
syntax = "proto2";
message MyMessage {
required string a = 1;
optional string b = 2;
}
class MyMessage(
val a: String,
val b: String? = null
) : Message() {}
→
Slide 14
Slide 14 text
syntax = "proto3";
message MyMessage {
string a = 1;
optional string b = 2;
}
class MyMessage(
val a: String = "",
val b: String? = null
) : Message() {}
→
Slide 15
Slide 15 text
New Types
Slide 16
Slide 16 text
Any → com.squareup.wire.AnyMessage
Duration → java.time.Duration
Timestamp → java.time.Instant
Struct → map
Wrappers → Boxed types for primitives (String?)
Empty → kotlin.Unit
New Types
google.protobuf.
~ Generic placeholder
~ same as java.time.Duration
~ same as java.time.Instant
~ JSON Object
~ JSON representation of primitive types + nullability
~ For parameter-less RPCs
Slide 17
Slide 17 text
message Request {
// Only set when it is a Bitcoin request.
optional BitcoinData bitcoin_data = 1;
// Only set when it is a Stock request.
optional StockData stock_data = 2;
}
Slide 18
Slide 18 text
message Request {
// Only set when it is a Bitcoin request.
optional BitcoinData bitcoin_data = 1;
// Only set when it is a Stock request.
optional StockData stock_data = 2;
}
message Request {
// Will be either BitcoinData or StockData.
optional google.protobuf.Any request_data = 1;
}
↓
Slide 19
Slide 19 text
Any → com.squareup.wire.AnyMessage
Duration → java.time.Duration
Timestamp → java.time.Instant
Struct → map
Wrappers → Boxed types for primitives (String?)
Empty → kotlin.Unit
New Types
google.protobuf.
val response: EndpointResponse
if (isResponseStale(...)) {
fetch()
}
private fun isResponseStale(validUntil: Instant): Boolean
Slide 23
Slide 23 text
val protocResponse: Message.EndpointResponse
if (isResponseStale(...)) {
fetch()
}
private fun isResponseStale(validUntil: Instant): Boolean
Protoc
Slide 24
Slide 24 text
val millis = System.currentTimeMillis()
val protocResponse: Message.EndpointResponse
if (isResponseStale(...)) {
fetch()
}
private fun isResponseStale(validUntil: Instant): Boolean
Protoc
Slide 25
Slide 25 text
val millis = System.currentTimeMillis()
val protocResponse = Message.EndpointResponse.newBuilder()
.setValidUntil(
Timestamp...
)
.build()
if (isResponseStale(...)) {
fetch()
}
private fun isResponseStale(validUntil: Instant): Boolean
Protoc
Slide 26
Slide 26 text
val millis = System.currentTimeMillis()
val protocResponse = Message.EndpointResponse.newBuilder()
.setValidUntil(
Timestamp.newBuilder()
.setSeconds(millis / 1000)
.setNanos(((millis % 1000) * 1000000).toInt())
.build()
)
.build()
if (isResponseStale(...)) {
fetch()
}
private fun isResponseStale(validUntil: Instant): Boolean
Protoc
Slide 27
Slide 27 text
val millis = System.currentTimeMillis()
val protocResponse = Message.EndpointResponse.newBuilder().build()
if (isResponseStale(...)) {
fetch()
}
private fun isResponseStale(validUntil: Instant): Boolean
Protoc
Slide 28
Slide 28 text
val millis = System.currentTimeMillis()
val protocResponse = Message.EndpointResponse.newBuilder().build()
if (isResponseStale(
Instant.ofEpochSecond(
protocResponse.validUntil.seconds,
protocResponse.validUntil.nanos.toLong()
)
)) {
fetch()
}
private fun isResponseStale(validUntil: Instant): Boolean
Protoc
Slide 29
Slide 29 text
Wire
val wireResponse: EndpointResponse
if (isResponseStale(...)) {
fetch()
}
private fun isResponseStale(validUntil: Instant): Boolean
Slide 30
Slide 30 text
Wire
val millis = System.currentTimeMillis()
val wireResponse: EndpointResponse
if (isResponseStale(...)) {
fetch()
}
private fun isResponseStale(validUntil: Instant): Boolean
Slide 31
Slide 31 text
Wire
val millis = System.currentTimeMillis()
val wireResponse = EndpointResponse(Instant.ofEpochMilli(millis))
if (isResponseStale(...)) {
fetch()
}
private fun isResponseStale(validUntil: Instant): Boolean
Slide 32
Slide 32 text
Wire
val millis = System.currentTimeMillis()
val wireResponse = EndpointResponse(Instant.ofEpochMilli(millis))
if (isResponseStale(wireResponse.valid_until!!)) {
fetch()
}
private fun isResponseStale(validUntil: Instant): Boolean
Slide 33
Slide 33 text
JSON
Slide 34
Slide 34 text
Why JSON?
Slide 35
Slide 35 text
JSON
• Proto2 : Wire 㲗 Protoc communication is dangerous.
• Proto3 : All good.
Slide 36
Slide 36 text
Proto2 㲗 Proto3
Compatibility
Slide 37
Slide 37 text
Proto2 㲗 Proto3 Compatibility
• Cannot reference proto2 enums in proto3 message.
• Because of identity-if-absent.
• Anything else is good.
// emitDeclaredOptions = true
@Retention(AnnotationRetention.RUNTIME)
@Target(AnnotationTarget.CLASS)
public annotation class DocumentationUrlOption(
public val value: String
)
// emitAppliedOptions = true
@DocumentationUrlOption("https://en.wikipedia.org/wiki/Octagon")
public class Octagon(
...
) : Message(ADAPTER, unknownFields) {}
Slide 45
Slide 45 text
Wire Gradle Plugin
Slide 46
Slide 46 text
Schema
.proto
Elements
Java Kotlin Proto
Schema
Swift
Parse
Link
Prune
Generate
Slide 47
Slide 47 text
Schema
.proto
Elements
Java Kotlin Proto
Schema
Swift
Parse
Link
Prune
Generate
wire {
sourcePath {
srcDir 'src/main/protos'
}
sourcePath {
srcJar 'lib/pizza-protos.jar'
}
protoPath {
srcJar 'com.example.pizza:pizza-protos:1.0.0'
}
...
}
Slide 48
Slide 48 text
Schema
.proto
Elements
Java Kotlin Proto
Schema
Swift
Parse
Link
Prune
Generate
wire {
sourcePath {
srcDir 'src/main/protos'
include 'com/example/pizza/pizza_delivery.proto'
include 'com/example/pizza/pizza.proto'
}
}
Slide 49
Slide 49 text
Schema
.proto
Elements
Java Kotlin Proto
Schema
Swift
Parse
Link
Prune
Generate
wire {
sourcePath {
srcDir 'src/main/protos'
include 'com/example/pizza/pizza_delivery.proto'
include 'com/example/pizza/pizza.proto'
}
}
Slide 50
Slide 50 text
Schema
.proto
Elements
Java Kotlin Proto
Schema
Swift
Parse
Link
Prune
Generate
wire {
sourcePath {
srcDir 'src/main/protos'
include 'com/example/pizza/pizza_delivery.proto'
include 'com/example/pizza/pizza.proto'
}
}
Slide 51
Slide 51 text
Schema
.proto
Elements
Java Kotlin Proto
Schema
Swift
Parse
Link
Prune
Generate
wire {
protoPath {
srcJar 'com.squareup.protos:all-protos'
}
sourcePath {
srcDir 'src/main/protos'
include 'com/example/pizza/pizza_delivery.proto'
include 'com/example/pizza/pizza.proto'
}
}
Slide 52
Slide 52 text
No content
Slide 53
Slide 53 text
No content
Slide 54
Slide 54 text
No content
Slide 55
Slide 55 text
No content
Slide 56
Slide 56 text
Schema
.proto
Elements
Java Kotlin Proto
Schema
Swift
Parse
Link
Prune
Generate
wire {
root 'com.example.store.Store'
}
Slide 57
Slide 57 text
wire {
root 'com.example.store.Store'
}
Slide 58
Slide 58 text
wire {
root 'com.example.store.Store'
}
Slide 59
Slide 59 text
Schema
.proto
Elements
Java Kotlin Proto
Schema
Swift
Parse
Link
Prune
Generate
wire {
prune 'com.example.store.Store'
prune 'com.example.geo.Country'
}
Schema
.proto
Elements
Java Kotlin Proto
Schema
Swift
Parse
Link
Prune
Generate
wire {
kotlin {
includes = ['com.example.pizza.*']
excludes = ['com.example.sales.*']
exclusive = false
out "${buildDir}/custom"
}
}