<lambda>null1package 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