• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download

<lambda>null1 package kotlinx.serialization.json
2 
3 import kotlinx.serialization.*
4 import kotlinx.serialization.Serializable
5 import kotlinx.serialization.descriptors.*
6 import kotlinx.serialization.encoding.*
7 import kotlinx.serialization.test.assertFailsWithMessage
8 import org.junit.Test
9 import java.io.*
10 import java.util.*
11 import kotlin.random.Random
12 import kotlin.test.*
13 
14 
15 @Serializable(with = LargeBase64StringSerializer::class)
16 data class LargeBinaryData(val binaryData: ByteArray) {
17     override fun equals(other: Any?): Boolean {
18         if (this === other) return true
19         if (javaClass != other?.javaClass) return false
20 
21         other as LargeBinaryData
22 
23         if (!binaryData.contentEquals(other.binaryData)) return false
24 
25         return true
26     }
27 
28     override fun hashCode(): Int {
29         return binaryData.contentHashCode()
30     }
31 }
32 
33 @Serializable
34 data class ClassWithBinaryDataField(val binaryField: LargeBinaryData)
35 
36 object LargeBase64StringSerializer : KSerializer<LargeBinaryData> {
37     private val b64Decoder: Base64.Decoder = Base64.getDecoder()
38     override val descriptor: SerialDescriptor = PrimitiveSerialDescriptor("LargeStringContent", PrimitiveKind.STRING)
39 
deserializenull40     override fun deserialize(decoder: Decoder): LargeBinaryData {
41         require(decoder is ChunkedDecoder) { "Only chunked decoder supported" }
42 
43         var reminder = ""
44         val decodedBytes = ByteArrayOutputStream().use { bos ->
45             decoder.decodeStringChunked {
46                 val actualChunk = reminder + it
47                 val reminderLength = actualChunk.length % 4
48                 val alignedLength = actualChunk.length - reminderLength
49                 val alignedChunk = actualChunk.take(alignedLength)
50                 reminder = actualChunk.takeLast(reminderLength)
51                 bos.write(b64Decoder.decode(alignedChunk))
52             }
53             bos.toByteArray()
54         }
55 
56         return LargeBinaryData(decodedBytes)
57     }
58 
serializenull59     override fun serialize(encoder: Encoder, value: LargeBinaryData) {
60         encoder.encodeString(Base64.getEncoder().encodeToString(value.binaryData))
61     }
62 }
63 
64 class JsonChunkedBase64DecoderTest : JsonTestBase() {
65 
66     @Test
decodeBase64Stringnull67     fun decodeBase64String() {
68         val sourceObject =
69             ClassWithBinaryDataField(LargeBinaryData(Random.nextBytes(16 * 1024))) // After encoding to Base64 will be larger than 16k (JsonLexer#BATCH_SIZE)
70         val serializedObject = Json.encodeToString(sourceObject)
71 
72         JsonTestingMode.values().forEach { mode ->
73             if (mode == JsonTestingMode.TREE) {
74                 assertFailsWithMessage<IllegalArgumentException>(
75                     "Only chunked decoder supported", "Shouldn't decode JSON in TREE mode"
76                 ) {
77                     Json.decodeFromString<ClassWithBinaryDataField>(serializedObject, mode)
78                 }
79             } else {
80                 val deserializedObject = Json.decodeFromString<ClassWithBinaryDataField>(serializedObject, mode)
81                 assertEquals(sourceObject.binaryField, deserializedObject.binaryField)
82             }
83         }
84     }
85 }
86