Skip to content

Commit bfbe6a9

Browse files
authored
Cbor: check if inline value classes is marked as @ByteString (#2466)
Fixes #2187
1 parent 7d4bb2a commit bfbe6a9

File tree

4 files changed

+78
-1
lines changed

4 files changed

+78
-1
lines changed

formats/cbor/commonMain/src/kotlinx/serialization/cbor/internal/Encoding.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ internal open class CborWriter(private val cbor: Cbor, protected val encoder: Cb
7070
if (encodeByteArrayAsByteString && serializer.descriptor == ByteArraySerializer().descriptor) {
7171
encoder.encodeByteString(value as ByteArray)
7272
} else {
73+
encodeByteArrayAsByteString = encodeByteArrayAsByteString || serializer.descriptor.isInlineByteString()
74+
7375
super.encodeSerializableValue(serializer, value)
7476
}
7577
}
@@ -278,6 +280,7 @@ internal open class CborReader(private val cbor: Cbor, protected val decoder: Cb
278280
@Suppress("UNCHECKED_CAST")
279281
decoder.nextByteString() as T
280282
} else {
283+
decodeByteArrayAsByteString = decodeByteArrayAsByteString || deserializer.descriptor.isInlineByteString()
281284
super.decodeSerializableValue(deserializer)
282285
}
283286
}
@@ -636,6 +639,11 @@ private fun SerialDescriptor.isByteString(index: Int): Boolean {
636639
return getElementAnnotations(index).find { it is ByteString } != null
637640
}
638641

642+
private fun SerialDescriptor.isInlineByteString(): Boolean {
643+
// inline item classes should only have 1 item
644+
return isInline && isByteString(0)
645+
}
646+
639647

640648
private val normalizeBaseBits = SINGLE_PRECISION_NORMALIZE_BASE.toBits()
641649

formats/cbor/commonTest/src/kotlinx/serialization/cbor/CborReaderTest.kt

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -633,6 +633,34 @@ class CborReaderTest {
633633
)
634634
}
635635

636+
@Test
637+
fun testReadValueClassWithByteString() {
638+
assertContentEquals(
639+
expected = byteArrayOf(0x11, 0x22, 0x33),
640+
actual = Cbor.decodeFromHexString<ValueClassWithByteString>("43112233").x
641+
)
642+
}
643+
644+
@Test
645+
fun testReadValueClassCustomByteString() {
646+
assertEquals(
647+
expected = ValueClassWithCustomByteString(CustomByteString(0x11, 0x22, 0x33)),
648+
actual = Cbor.decodeFromHexString("43112233")
649+
)
650+
}
651+
652+
@Test
653+
fun testReadValueClassWithUnlabeledByteString() {
654+
assertContentEquals(
655+
expected = byteArrayOf(
656+
0x11,
657+
0x22,
658+
0x33
659+
),
660+
actual = Cbor.decodeFromHexString<ValueClassWithUnlabeledByteString>("43112233").x.x
661+
)
662+
}
663+
636664
@Test
637665
fun testIgnoresTagsOnStrings() {
638666
/*

formats/cbor/commonTest/src/kotlinx/serialization/cbor/CborWriterTest.kt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,4 +122,28 @@ class CbrWriterTest {
122122
actual = Cbor.encodeToHexString(TypeWithNullableCustomByteString(null))
123123
)
124124
}
125+
126+
@Test
127+
fun testWriteValueClassWithByteString() {
128+
assertEquals(
129+
expected = "43112233",
130+
actual = Cbor.encodeToHexString(ValueClassWithByteString(byteArrayOf(0x11, 0x22, 0x33)))
131+
)
132+
}
133+
134+
@Test
135+
fun testWriteValueClassCustomByteString() {
136+
assertEquals(
137+
expected = "43112233",
138+
actual = Cbor.encodeToHexString(ValueClassWithCustomByteString(CustomByteString(0x11, 0x22, 0x33)))
139+
)
140+
}
141+
142+
@Test
143+
fun testWriteValueClassWithUnlabeledByteString() {
144+
assertEquals(
145+
expected = "43112233",
146+
actual = Cbor.encodeToHexString(ValueClassWithUnlabeledByteString(ValueClassWithUnlabeledByteString.Inner(byteArrayOf(0x11, 0x22, 0x33))))
147+
)
148+
}
125149
}

formats/cbor/commonTest/src/kotlinx/serialization/cbor/SampleClasses.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import kotlinx.serialization.*
88
import kotlinx.serialization.builtins.*
99
import kotlinx.serialization.descriptors.*
1010
import kotlinx.serialization.encoding.*
11+
import kotlin.jvm.*
1112

1213
@Serializable
1314
data class Simple(val a: String)
@@ -110,4 +111,20 @@ class CustomByteStringSerializer : KSerializer<CustomByteString> {
110111
data class TypeWithCustomByteString(@ByteString val x: CustomByteString)
111112

112113
@Serializable
113-
data class TypeWithNullableCustomByteString(@ByteString val x: CustomByteString?)
114+
data class TypeWithNullableCustomByteString(@ByteString val x: CustomByteString?)
115+
116+
@JvmInline
117+
@Serializable
118+
value class ValueClassWithByteString(@ByteString val x: ByteArray)
119+
120+
@JvmInline
121+
@Serializable
122+
value class ValueClassWithCustomByteString(@ByteString val x: CustomByteString)
123+
124+
@JvmInline
125+
@Serializable
126+
value class ValueClassWithUnlabeledByteString(@ByteString val x: Inner) {
127+
@JvmInline
128+
@Serializable
129+
value class Inner(val x: ByteArray)
130+
}

0 commit comments

Comments
 (0)