Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provide @EncodeDefault annotation for fields #1190

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions core/commonMain/src/kotlinx/serialization/Annotations.kt
Original file line number Diff line number Diff line change
Expand Up @@ -224,3 +224,23 @@ public annotation class ExperimentalSerializationApi
@Target(AnnotationTarget.CLASS, AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION, AnnotationTarget.TYPEALIAS)
@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
public annotation class InternalSerializationApi

public enum class EncodeDefaultMode {
/**
* Serializers will call [kotlinx.serialization.encoding.CompositeEncoder.shouldEncodeElementDefault] to detect whether default values should be encoded.
*/
DEFAULT,

/**
* Serializers will always encode values even if they are equal to the default values.
*/
ALWAYS,

/**
*Serializers will always omit values if they are equal to the default values.
*/
NEVER
}

@Target(AnnotationTarget.PROPERTY)
public annotation class EncodeDefault(public val mode: EncodeDefaultMode)
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package kotlinx.serialization.features

import kotlinx.serialization.*
import kotlinx.serialization.descriptors.SerialDescriptor
import kotlinx.serialization.encoding.AbstractEncoder
import kotlinx.serialization.encoding.CompositeEncoder
import kotlinx.serialization.modules.EmptySerializersModule
import kotlinx.serialization.modules.SerializersModule
import kotlin.test.Test
import kotlin.test.assertEquals

class EncodeDefaultModeTest {
private class EncodedFieldDetector(private val sb: StringBuilder, private val encodeDefaults: Boolean = false) : AbstractEncoder() {
override val serializersModule: SerializersModule = EmptySerializersModule
private var first = false
override fun beginStructure(descriptor: SerialDescriptor): CompositeEncoder {
first = true
sb.append('{')
return this
}

override fun endStructure(descriptor: SerialDescriptor) {
first = false
sb.append('}')
}

@ExperimentalSerializationApi
override fun shouldEncodeElementDefault(descriptor: SerialDescriptor, index: Int): Boolean = encodeDefaults
override fun encodeElement(descriptor: SerialDescriptor, index: Int): Boolean {
if (first) {
first = false
} else {
sb.append(", ")
}
sb.append(descriptor.getElementName(index))
return true
}

override fun encodeNull() {}
override fun encodeValue(value: Any) {}
override fun encodeString(value: String) {}
override fun encodeChar(value: Char) {}

companion object {
fun <T> encodeToString(serializer: SerializationStrategy<T>, value: T, encodeDefaults: Boolean = false): String {
val sb = StringBuilder()
val out = EncodedFieldDetector(sb, encodeDefaults)
out.encodeSerializableValue(serializer, value)
return sb.toString()
}
}
}

@Serializable
private data class TestModel(
@EncodeDefault(EncodeDefaultMode.DEFAULT)
val default: Int = 0,
@EncodeDefault(EncodeDefaultMode.ALWAYS)
val always: Int = 1,
@EncodeDefault(EncodeDefaultMode.NEVER)
val never: Int = 2
)

@Test
fun testEncodeDefaultMode() {
assertEquals("{default, always}",
EncodedFieldDetector.encodeToString(TestModel.serializer(), TestModel(), encodeDefaults = true))
assertEquals("{always}",
EncodedFieldDetector.encodeToString(TestModel.serializer(), TestModel(), encodeDefaults = false))
assertEquals("{always, never}",
EncodedFieldDetector.encodeToString(TestModel.serializer(), TestModel(0, 2, 3), encodeDefaults = false))
assertEquals("{default, always, never}",
EncodedFieldDetector.encodeToString(TestModel.serializer(), TestModel(0, 2, 3), encodeDefaults = true))
}
}