Last active
June 5, 2024 09:08
-
-
Save pdvrieze/0eb34ab2f914383a4d98cfc414272ac7 to your computer and use it in GitHub Desktop.
Example code for a delegating format.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2024. | |
* | |
* This file is part of xmlutil. | |
* | |
* This file is licenced to you under the Apache License, Version 2.0 (the | |
* "License"); you may not use this file except in compliance | |
* with the License. You should have received a copy of the license with the source distribution. | |
* Alternatively, you may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, | |
* software distributed under the License is distributed on an | |
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
* KIND, either express or implied. See the License for the | |
* specific language governing permissions and limitations | |
* under the License. | |
*/ | |
package nl.adaptivity.serialutil | |
import kotlinx.serialization.DeserializationStrategy | |
import kotlinx.serialization.ExperimentalSerializationApi | |
import kotlinx.serialization.SerializationStrategy | |
import kotlinx.serialization.StringFormat | |
import kotlinx.serialization.descriptors.SerialDescriptor | |
import kotlinx.serialization.encoding.CompositeDecoder | |
import kotlinx.serialization.encoding.CompositeEncoder | |
import kotlinx.serialization.encoding.Decoder | |
import kotlinx.serialization.encoding.Encoder | |
import kotlinx.serialization.modules.SerializersModule | |
abstract class DelegatingStringFormat(private val delegateFormat: StringFormat) : StringFormat { | |
abstract fun <T> determineEffectiveSerializer(serializer: SerializationStrategy<T>): SerializationStrategy<T> | |
abstract fun <T> determineEffectiveDeserializer(deserializer: DeserializationStrategy<T>): DeserializationStrategy<T> | |
override fun <T> encodeToString(serializer: SerializationStrategy<T>, value: T): String { | |
return delegateFormat.encodeToString(WrappingSerializationStrategy(serializer), value) | |
} | |
override fun <T> decodeFromString(deserializer: DeserializationStrategy<T>, string: String): T { | |
return decodeFromString(WrappingDeserializationStrategy(deserializer), string) | |
} | |
private inner class WrappingSerializationStrategy<T>(val delegate: SerializationStrategy<T>) : SerializationStrategy<T> { | |
override val descriptor: SerialDescriptor | |
get() = delegate.descriptor | |
override fun serialize(encoder: Encoder, value: T) { | |
val wrappedEncoder: Encoder = WrappedEncoder(encoder) | |
delegate.serialize(wrappedEncoder, value) | |
} | |
} | |
private inner class WrappingDeserializationStrategy<T>(val delegate: DeserializationStrategy<T>) : DeserializationStrategy<T> { | |
override val descriptor: SerialDescriptor | |
get() = delegate.descriptor | |
override fun deserialize(decoder: Decoder): T { | |
val wrappedDecoder: Decoder = WrappedDecoder(decoder) | |
return delegate.deserialize(wrappedDecoder) | |
} | |
} | |
private inner class WrappedEncoder(val encoder: Encoder): Encoder { | |
override fun <T> encodeSerializableValue(serializer: SerializationStrategy<T>, value: T) { | |
val effectiveSerializer = determineEffectiveSerializer(serializer) | |
encoder.encodeSerializableValue(effectiveSerializer, value) | |
} | |
@ExperimentalSerializationApi | |
override fun <T : Any> encodeNullableSerializableValue(serializer: SerializationStrategy<T>, value: T?) { | |
val effectiveSerializer = determineEffectiveSerializer(serializer) | |
encoder.encodeNullableSerializableValue(effectiveSerializer, value) | |
} | |
override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder { | |
// Make sure to retain the "wrapping" | |
return WrappedCompositeEncoder(encoder.beginStructure(descriptor)) | |
} | |
override fun beginCollection(descriptor: SerialDescriptor, collectionSize: Int): CompositeEncoder { | |
// Overridden to ensure beginCollection on the delegate is called | |
// Make sure to retain the "wrapping" | |
return WrappedCompositeEncoder(encoder.beginCollection(descriptor, collectionSize)) | |
} | |
override val serializersModule: SerializersModule get() = encoder.serializersModule | |
override fun encodeBoolean(value: Boolean) = encoder.encodeBoolean(value) | |
override fun encodeByte(value: Byte) = encoder.encodeByte(value) | |
override fun encodeChar(value: Char) = encoder.encodeChar(value) | |
override fun encodeDouble(value: Double) = encoder.encodeDouble(value) | |
override fun encodeEnum(enumDescriptor: SerialDescriptor, index: Int) = encoder.encodeEnum(enumDescriptor, index) | |
override fun encodeFloat(value: Float) = encoder.encodeFloat(value) | |
override fun encodeInline(descriptor: SerialDescriptor): Encoder = encoder.encodeInline(descriptor) | |
override fun encodeInt(value: Int) = encoder.encodeInt(value) | |
override fun encodeLong(value: Long) = encoder.encodeLong(value) | |
override fun encodeShort(value: Short) = encoder.encodeShort(value) | |
override fun encodeString(value: String) = encoder.encodeString(value) | |
@ExperimentalSerializationApi | |
override fun encodeNotNullMark() = encoder.encodeNotNullMark() | |
@ExperimentalSerializationApi | |
override fun encodeNull() = encoder.encodeNull() | |
} | |
private inner class WrappedCompositeEncoder(val encoder: CompositeEncoder): CompositeEncoder { | |
@ExperimentalSerializationApi | |
override fun <T : Any> encodeNullableSerializableElement( | |
descriptor: SerialDescriptor, | |
index: Int, | |
serializer: SerializationStrategy<T>, | |
value: T? | |
) { | |
val effectiveSerializer = determineEffectiveSerializer(serializer) | |
encoder.encodeNullableSerializableElement(descriptor, index, effectiveSerializer, value) | |
} | |
override fun <T> encodeSerializableElement( | |
descriptor: SerialDescriptor, | |
index: Int, | |
serializer: SerializationStrategy<T>, | |
value: T | |
) { | |
val effectiveSerializer = determineEffectiveSerializer(serializer) | |
encoder.encodeSerializableElement(descriptor, index, effectiveSerializer, value) | |
} | |
override fun encodeInlineElement(descriptor: SerialDescriptor, index: Int): Encoder { | |
return WrappedEncoder(encoder.encodeInlineElement(descriptor, index)) | |
} | |
override val serializersModule: SerializersModule get() = encoder.serializersModule | |
@ExperimentalSerializationApi | |
override fun shouldEncodeElementDefault(descriptor: SerialDescriptor, index: Int): Boolean { | |
return encoder.shouldEncodeElementDefault(descriptor, index) | |
} | |
override fun encodeBooleanElement(descriptor: SerialDescriptor, index: Int, value: Boolean) { | |
encoder.encodeBooleanElement(descriptor, index, value) | |
} | |
override fun encodeByteElement(descriptor: SerialDescriptor, index: Int, value: Byte) { | |
encoder.encodeByteElement(descriptor, index, value) | |
} | |
override fun encodeCharElement(descriptor: SerialDescriptor, index: Int, value: Char) { | |
encoder.encodeCharElement(descriptor, index, value) | |
} | |
override fun encodeDoubleElement(descriptor: SerialDescriptor, index: Int, value: Double) { | |
encoder.encodeDoubleElement(descriptor, index, value) | |
} | |
override fun encodeFloatElement(descriptor: SerialDescriptor, index: Int, value: Float) { | |
encoder.encodeFloatElement(descriptor, index, value) | |
} | |
override fun encodeIntElement(descriptor: SerialDescriptor, index: Int, value: Int) { | |
encoder.encodeIntElement(descriptor, index, value) | |
} | |
override fun encodeLongElement(descriptor: SerialDescriptor, index: Int, value: Long) { | |
encoder.encodeLongElement(descriptor, index, value) | |
} | |
override fun encodeShortElement(descriptor: SerialDescriptor, index: Int, value: Short) { | |
encoder.encodeShortElement(descriptor, index, value) | |
} | |
override fun encodeStringElement(descriptor: SerialDescriptor, index: Int, value: String) { | |
encoder.encodeStringElement(descriptor, index, value) | |
} | |
override fun endStructure(descriptor: SerialDescriptor) { | |
encoder.endStructure(descriptor) | |
} | |
} | |
private inner class WrappedDecoder(val decoder: Decoder) : Decoder { | |
override fun beginStructure(descriptor: SerialDescriptor): CompositeDecoder { | |
return WrappedCompositeDecoder(beginStructure(descriptor)) | |
} | |
@ExperimentalSerializationApi | |
override fun <T : Any> decodeNullableSerializableValue(deserializer: DeserializationStrategy<T?>): T? { | |
val effectiveDeserializer = determineEffectiveDeserializer(deserializer) | |
return super.decodeNullableSerializableValue(effectiveDeserializer) | |
} | |
override fun <T> decodeSerializableValue(deserializer: DeserializationStrategy<T>): T { | |
val effectiveDeserializer = determineEffectiveDeserializer(deserializer) | |
return super.decodeSerializableValue(effectiveDeserializer) | |
} | |
override val serializersModule: SerializersModule get() = decoder.serializersModule | |
override fun decodeBoolean(): Boolean = decoder.decodeBoolean() | |
override fun decodeByte(): Byte =decoder.decodeByte() | |
override fun decodeChar(): Char =decoder.decodeChar() | |
override fun decodeDouble(): Double =decoder.decodeDouble() | |
override fun decodeEnum(enumDescriptor: SerialDescriptor): Int =decoder.decodeEnum(enumDescriptor) | |
override fun decodeFloat(): Float =decoder.decodeFloat() | |
override fun decodeInline(descriptor: SerialDescriptor): Decoder =decoder.decodeInline(descriptor) | |
override fun decodeInt(): Int =decoder.decodeInt() | |
override fun decodeLong(): Long =decoder.decodeLong() | |
override fun decodeShort(): Short =decoder.decodeShort() | |
override fun decodeString(): String =decoder.decodeString() | |
@ExperimentalSerializationApi | |
override fun decodeNotNullMark(): Boolean =decoder.decodeNotNullMark() | |
@ExperimentalSerializationApi | |
override fun decodeNull(): Nothing? =decoder.decodeNull() | |
} | |
private inner class WrappedCompositeDecoder(val decoder: CompositeDecoder): CompositeDecoder { | |
@ExperimentalSerializationApi | |
override fun <T : Any> decodeNullableSerializableElement( | |
descriptor: SerialDescriptor, | |
index: Int, | |
deserializer: DeserializationStrategy<T?>, | |
previousValue: T? | |
): T? { | |
val effectiveDeserializer = determineEffectiveDeserializer(deserializer) | |
return decoder.decodeNullableSerializableElement(descriptor, index, effectiveDeserializer, previousValue) | |
} | |
override fun <T> decodeSerializableElement( | |
descriptor: SerialDescriptor, | |
index: Int, | |
deserializer: DeserializationStrategy<T>, | |
previousValue: T? | |
): T { | |
val effectiveDeserializer = determineEffectiveDeserializer(deserializer) | |
return decoder.decodeSerializableElement(descriptor, index, effectiveDeserializer, previousValue) | |
} | |
override val serializersModule: SerializersModule get() = decoder.serializersModule | |
override fun decodeCollectionSize(descriptor: SerialDescriptor): Int { | |
return decoder.decodeCollectionSize(descriptor) | |
} | |
@ExperimentalSerializationApi | |
override fun decodeSequentially(): Boolean { | |
return decoder.decodeSequentially() | |
} | |
override fun decodeBooleanElement(descriptor: SerialDescriptor, index: Int): Boolean { | |
return decoder.decodeBooleanElement(descriptor, index) | |
} | |
override fun decodeByteElement(descriptor: SerialDescriptor, index: Int): Byte { | |
return decoder.decodeByteElement(descriptor, index) | |
} | |
override fun decodeCharElement(descriptor: SerialDescriptor, index: Int): Char { | |
return decoder.decodeCharElement(descriptor, index) | |
} | |
override fun decodeDoubleElement(descriptor: SerialDescriptor, index: Int): Double { | |
return decoder.decodeDoubleElement(descriptor, index) | |
} | |
override fun decodeElementIndex(descriptor: SerialDescriptor): Int { | |
return decoder.decodeElementIndex(descriptor) | |
} | |
override fun decodeFloatElement(descriptor: SerialDescriptor, index: Int): Float { | |
return decoder.decodeFloatElement(descriptor, index) | |
} | |
override fun decodeInlineElement(descriptor: SerialDescriptor, index: Int): Decoder { | |
return WrappedDecoder(decoder.decodeInlineElement(descriptor, index)) | |
} | |
override fun decodeIntElement(descriptor: SerialDescriptor, index: Int): Int { | |
return decoder.decodeIntElement(descriptor, index) | |
} | |
override fun decodeLongElement(descriptor: SerialDescriptor, index: Int): Long { | |
return decoder.decodeLongElement(descriptor, index) | |
} | |
override fun decodeShortElement(descriptor: SerialDescriptor, index: Int): Short { | |
return decoder.decodeShortElement(descriptor, index) | |
} | |
override fun decodeStringElement(descriptor: SerialDescriptor, index: Int): String { | |
return decoder.decodeStringElement(descriptor, index) | |
} | |
override fun endStructure(descriptor: SerialDescriptor) { | |
return decoder.endStructure(descriptor) | |
} | |
} | |
} |
Also, is decodeInlineElement
in WrappedCompositeDecoder
not wrapped intentionally? The one in WrappedCompositeEncoder
is wrapped.
Note: I have created a more flexible (and much shorter) version of this gist.
@Laxystem I intentionally didn't use delegates as they have some design issues. As to decodeInlineElement, that was an oversight.
I intentionally didn't use delegates as they have some design issues.
May I ask what design issues?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I assume you haven't used interface delegates because you forgot about them?