Skip to content

Commit 462dabb

Browse files
committed
Support repeated entries in byte arrays
1 parent 47ff61c commit 462dabb

6 files changed

Lines changed: 125 additions & 1 deletion

File tree

wire-java-generator/src/main/java/com/squareup/wire/java/JavaGenerator.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,14 @@ public boolean isEnum(ProtoType type) {
588588
return schema.getType(type) instanceof EnumType;
589589
}
590590

591+
private boolean isSingularMessageField(Field field) {
592+
return !field.isPacked()
593+
&& !field.isRepeated()
594+
&& !field.getType().isMap()
595+
&& schema.getType(field.getType()) instanceof MessageType
596+
&& profile.getAdapter(field.getType()) == null;
597+
}
598+
591599
EnumConstant enumDefault(ProtoType type) {
592600
EnumType wireEnum = (EnumType) schema.getType(type);
593601
return wireEnum.getConstants().get(0);
@@ -1338,6 +1346,34 @@ private MethodSpec messageAdapterDecode(
13381346
}
13391347
result.addStatement("break");
13401348
result.endControlFlow(); // case
1349+
} else if (isSingularMessageField(field)) {
1350+
// Repeated tags are to be merged.
1351+
String fieldName = nameAllocator.get(field);
1352+
CodeBlock adapter = singleAdapterFor(field, nameAllocator);
1353+
TypeName fieldTypeName = fieldType(field);
1354+
result.beginControlFlow("case $L:", fieldTag);
1355+
result.addStatement("$T value_ = $L.decode(reader)", fieldTypeName, adapter);
1356+
if (useBuilder) {
1357+
result.addStatement(
1358+
"builder.$L(builder.$L != null ? $L.decode($L.encode(builder.$L) + $L.encode(value_)) : value_)",
1359+
fieldName,
1360+
fieldName,
1361+
adapter,
1362+
adapter,
1363+
fieldName,
1364+
adapter);
1365+
} else {
1366+
result.addStatement(
1367+
"$N = $N != null ? $L.decode($L.encode($N) + $L.encode(value_)) : value_",
1368+
fieldName,
1369+
fieldName,
1370+
adapter,
1371+
adapter,
1372+
fieldName,
1373+
adapter);
1374+
}
1375+
result.addStatement("break");
1376+
result.endControlFlow(); // case
13411377
} else {
13421378
result.addCode(
13431379
"case $L: $L; break;\n", fieldTag, decodeAndAssign(field, nameAllocator, useBuilder));

wire-java-generator/src/test/java/com/squareup/wire/java/JavaGeneratorTest.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,11 @@ public void generateAbstractAdapter() throws Exception {
285285
+ " long token = reader.beginMessage();\n"
286286
+ " for (int tag; (tag = reader.nextTag()) != -1;) {\n"
287287
+ " switch (tag) {\n"
288-
+ " case 1: field = Foo.ADAPTER.decode(reader); break;\n"
288+
+ " case 1: {\n"
289+
+ " Foo value_ = Foo.ADAPTER.decode(reader);\n"
290+
+ " field = field != null ? Foo.ADAPTER.decode(Foo.ADAPTER.encode(field) + Foo.ADAPTER.encode(value_)) : value_;\n"
291+
+ " break;\n"
292+
+ " }\n"
289293
+ " case 2: bars.putAll(barsAdapter().decode(reader)); break;\n"
290294
+ " case 3: numbers.add(ProtoAdapter.INT32.decode(reader)); break;\n"
291295
+ " case 4: {\n"

wire-kotlin-generator/src/main/java/com/squareup/wire/kotlin/KotlinGenerator.kt

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1959,6 +1959,38 @@ class KotlinGenerator private constructor(
19591959
add(decodeAndAssign(protoReaderType, field, fieldName, adapterName))
19601960
endControlFlow()
19611961
}
1962+
!field.isRepeated && !field.isMap && field.type!!.isMessage && profile.getAdapter(field.type!!) == null -> {
1963+
// Repeated tags are to be merged.
1964+
val decodedVarName = nameAllocator.newName("decoded")
1965+
beginControlFlow("%L ->", field.tag)
1966+
addStatement("val %N = %L.decode(reader)", decodedVarName, adapterName)
1967+
if (buildersOnly) {
1968+
addStatement(
1969+
"builder.%N(if (builder.%N != null) %L.decode(%L.encode(builder.%N!!) + %L.encode(%N)) else %N)",
1970+
fieldName,
1971+
fieldName,
1972+
adapterName,
1973+
adapterName,
1974+
fieldName,
1975+
adapterName,
1976+
decodedVarName,
1977+
decodedVarName,
1978+
)
1979+
} else {
1980+
addStatement(
1981+
"%N = if (%N != null) %L.decode(%L.encode(%N!!) + %L.encode(%N)) else %N",
1982+
fieldName,
1983+
fieldName,
1984+
adapterName,
1985+
adapterName,
1986+
fieldName,
1987+
adapterName,
1988+
decodedVarName,
1989+
decodedVarName,
1990+
)
1991+
}
1992+
endControlFlow()
1993+
}
19621994
else -> {
19631995
addStatement(
19641996
"%L -> %L",

wire-protoc-compatibility-tests/src/main/proto/squareup/proto2/java/interop/interop_test.proto

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,11 @@ message InteropBoxOneOf {
5555
sint32 f = 6;
5656
}
5757
}
58+
59+
message SubInteropRepeatedUint {
60+
repeated uint32 repeated_values = 1 [packed = true];
61+
}
62+
63+
message InteropRepeatedUint {
64+
optional SubInteropRepeatedUint sub_message = 1;
65+
}

wire-protoc-compatibility-tests/src/main/proto/squareup/proto2/kotlin/interop/interop_test.proto

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,3 +55,12 @@ message InteropBoxOneOf {
5555
sint32 f = 6;
5656
}
5757
}
58+
59+
message SubInteropRepeatedUint {
60+
repeated uint32 repeated_values = 1 [packed = true];
61+
}
62+
63+
message InteropRepeatedUint {
64+
optional SubInteropRepeatedUint sub_message = 1;
65+
}
66+

wire-protoc-compatibility-tests/src/test/java/com/squareup/wire/Proto2WireProtocCompatibilityTests.kt

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ import okio.ByteString.Companion.decodeHex
2727
import org.junit.Test
2828
import squareup.proto2.java.empty.EmptyLength as EmptyLengthJ
2929
import squareup.proto2.java.interop.InteropMessage as InteropMessageJ
30+
import squareup.proto2.java.interop.InteropRepeatedUint as InteropRepeatedUintJ2
31+
import squareup.proto2.java.interop.InteropTest.InteropRepeatedUint as InteropRepeatedUintP2
32+
import squareup.proto2.java.interop.InteropTest.SubInteropRepeatedUint as SubInteropRepeatedUintP2
33+
import squareup.proto2.java.interop.SubInteropRepeatedUint as SubInteropRepeatedUintJ2
3034
import squareup.proto2.java.interop.type.EnumProto2 as EnumProto2J
3135
import squareup.proto2.java.interop.type.MessageProto2 as MessageProto2J
3236
import squareup.proto2.kotlin.MapTypes
@@ -49,10 +53,12 @@ import squareup.proto2.kotlin.interop.InteropMessageOuterClass.extRepProto2Enum
4953
import squareup.proto2.kotlin.interop.InteropMessageOuterClass.extRepProto2Message
5054
import squareup.proto2.kotlin.interop.InteropMessageOuterClass.extRepProto3Enum
5155
import squareup.proto2.kotlin.interop.InteropMessageOuterClass.extRepProto3Message
56+
import squareup.proto2.kotlin.interop.InteropRepeatedUint as InteropRepeatedUintK2
5257
import squareup.proto2.kotlin.interop.Quilt
5358
import squareup.proto2.kotlin.interop.QuiltColor
5459
import squareup.proto2.kotlin.interop.QuiltContainer
5560
import squareup.proto2.kotlin.interop.RepeatedEnum
61+
import squareup.proto2.kotlin.interop.SubInteropRepeatedUint as SubInteropRepeatedUintK2
5662
import squareup.proto2.kotlin.interop.type.EnumProto2 as EnumProto2K
5763
import squareup.proto2.kotlin.interop.type.InteropTypes.EnumProto2
5864
import squareup.proto2.kotlin.interop.type.InteropTypes.MessageProto2
@@ -183,6 +189,35 @@ class Proto2WireProtocCompatibilityTests {
183189
assertThat(mapTypeWire.map_string_string[""]).isEqualTo("ed")
184190
}
185191

192+
@Test fun decodingRepeatedEntries() {
193+
// ── 1 ┐
194+
// ├─ 1: 1
195+
// ╰- 1: 1
196+
val byteArray = byteArrayOf(10, 3, 10, 1, 1, 10, 3, 10, 1, 1)
197+
assertThat(InteropRepeatedUintP2.parseFrom(byteArray))
198+
.isEqualTo(
199+
InteropRepeatedUintP2.newBuilder()
200+
.setSubMessage(
201+
SubInteropRepeatedUintP2.newBuilder().addAllRepeatedValues(listOf(1, 1)).build(),
202+
)
203+
.build(),
204+
)
205+
assertThat(InteropRepeatedUintJ2.ADAPTER.decode(byteArray)).isEqualTo(
206+
InteropRepeatedUintJ2.Builder()
207+
.sub_message(
208+
SubInteropRepeatedUintJ2.Builder().repeated_values(listOf(1, 1)).build(),
209+
)
210+
.build(),
211+
)
212+
assertThat(InteropRepeatedUintK2.ADAPTER.decode(byteArray)).isEqualTo(
213+
InteropRepeatedUintK2.Builder()
214+
.sub_message(
215+
SubInteropRepeatedUintK2.Builder().repeated_values(listOf(1, 1)).build(),
216+
)
217+
.build(),
218+
)
219+
}
220+
186221
/**
187222
* The TS-proto library encodes enums differently from Wire or Protoc. Protoc is fine with this,
188223
* but it causes Wire to crash. The fix is to make Wire accept this format also.

0 commit comments

Comments
 (0)