Skip to content

Commit 7b085df

Browse files
authored
Add shortValueClassHeaderName config (#29)
* Add value class test * Rename test `EnumClass` * Add `shortValueClassHeaderName` config * Update README * Update API * Update CHANGELOG Closes #16
1 parent a2d697e commit 7b085df

File tree

16 files changed

+359
-52
lines changed

16 files changed

+359
-52
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Added
11+
12+
- Config `shortValueClassHeaderName` for short value class header name.
13+
- Kotlin Multiplatform support.
14+
15+
### Changed
16+
17+
- Some API changes for Kotlin Multiplatform support.
18+
1019
## [2.1.1] - 2025-10-01
1120

1221
### Changed

README.md

Lines changed: 17 additions & 16 deletions
Large diffs are not rendered by default.

library/api/library.api

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ public final class kotlinx/serialization/csv/config/CsvBuilder {
6060
public final fun getQuoteMode ()Lkotlinx/serialization/csv/config/QuoteMode;
6161
public final fun getRecordSeparator ()Ljava/lang/String;
6262
public final fun getSerializersModule ()Lkotlinx/serialization/modules/SerializersModule;
63+
public final fun getShortValueClassHeaderName ()Z
6364
public final fun setDelimiter (C)V
6465
public final fun setEscapeChar (Ljava/lang/Character;)V
6566
public final fun setHasHeaderRecord (Z)V
@@ -72,17 +73,19 @@ public final class kotlinx/serialization/csv/config/CsvBuilder {
7273
public final fun setQuoteMode (Lkotlinx/serialization/csv/config/QuoteMode;)V
7374
public final fun setRecordSeparator (Ljava/lang/String;)V
7475
public final fun setSerializersModule (Lkotlinx/serialization/modules/SerializersModule;)V
76+
public final fun setShortValueClassHeaderName (Z)V
7577
}
7678

7779
public final class kotlinx/serialization/csv/config/CsvConfig {
7880
public static final field Companion Lkotlinx/serialization/csv/config/CsvConfig$Companion;
7981
public fun <init> ()V
80-
public fun <init> (CLjava/lang/String;CLkotlinx/serialization/csv/config/QuoteMode;Ljava/lang/Character;Ljava/lang/String;ZZCZZLkotlinx/serialization/modules/SerializersModule;)V
81-
public synthetic fun <init> (CLjava/lang/String;CLkotlinx/serialization/csv/config/QuoteMode;Ljava/lang/Character;Ljava/lang/String;ZZCZZLkotlinx/serialization/modules/SerializersModule;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
82+
public fun <init> (CLjava/lang/String;CLkotlinx/serialization/csv/config/QuoteMode;Ljava/lang/Character;Ljava/lang/String;ZZCZZZLkotlinx/serialization/modules/SerializersModule;)V
83+
public synthetic fun <init> (CLjava/lang/String;CLkotlinx/serialization/csv/config/QuoteMode;Ljava/lang/Character;Ljava/lang/String;ZZCZZZLkotlinx/serialization/modules/SerializersModule;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
8284
public final fun component1 ()C
8385
public final fun component10 ()Z
8486
public final fun component11 ()Z
85-
public final fun component12 ()Lkotlinx/serialization/modules/SerializersModule;
87+
public final fun component12 ()Z
88+
public final fun component13 ()Lkotlinx/serialization/modules/SerializersModule;
8689
public final fun component2 ()Ljava/lang/String;
8790
public final fun component3 ()C
8891
public final fun component4 ()Lkotlinx/serialization/csv/config/QuoteMode;
@@ -91,8 +94,8 @@ public final class kotlinx/serialization/csv/config/CsvConfig {
9194
public final fun component7 ()Z
9295
public final fun component8 ()Z
9396
public final fun component9 ()C
94-
public final fun copy (CLjava/lang/String;CLkotlinx/serialization/csv/config/QuoteMode;Ljava/lang/Character;Ljava/lang/String;ZZCZZLkotlinx/serialization/modules/SerializersModule;)Lkotlinx/serialization/csv/config/CsvConfig;
95-
public static synthetic fun copy$default (Lkotlinx/serialization/csv/config/CsvConfig;CLjava/lang/String;CLkotlinx/serialization/csv/config/QuoteMode;Ljava/lang/Character;Ljava/lang/String;ZZCZZLkotlinx/serialization/modules/SerializersModule;ILjava/lang/Object;)Lkotlinx/serialization/csv/config/CsvConfig;
97+
public final fun copy (CLjava/lang/String;CLkotlinx/serialization/csv/config/QuoteMode;Ljava/lang/Character;Ljava/lang/String;ZZCZZZLkotlinx/serialization/modules/SerializersModule;)Lkotlinx/serialization/csv/config/CsvConfig;
98+
public static synthetic fun copy$default (Lkotlinx/serialization/csv/config/CsvConfig;CLjava/lang/String;CLkotlinx/serialization/csv/config/QuoteMode;Ljava/lang/Character;Ljava/lang/String;ZZCZZZLkotlinx/serialization/modules/SerializersModule;ILjava/lang/Object;)Lkotlinx/serialization/csv/config/CsvConfig;
9699
public fun equals (Ljava/lang/Object;)Z
97100
public final fun getDelimiter ()C
98101
public final fun getEscapeChar ()Ljava/lang/Character;
@@ -106,6 +109,7 @@ public final class kotlinx/serialization/csv/config/CsvConfig {
106109
public final fun getQuoteMode ()Lkotlinx/serialization/csv/config/QuoteMode;
107110
public final fun getRecordSeparator ()Ljava/lang/String;
108111
public final fun getSerializersModule ()Lkotlinx/serialization/modules/SerializersModule;
112+
public final fun getShortValueClassHeaderName ()Z
109113
public fun hashCode ()I
110114
public fun toString ()Ljava/lang/String;
111115
}

library/api/library.klib.api

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,13 @@ final class kotlinx.serialization.csv.config/CsvBuilder { // kotlinx.serializati
8282
final var serializersModule // kotlinx.serialization.csv.config/CsvBuilder.serializersModule|{}serializersModule[0]
8383
final fun <get-serializersModule>(): kotlinx.serialization.modules/SerializersModule // kotlinx.serialization.csv.config/CsvBuilder.serializersModule.<get-serializersModule>|<get-serializersModule>(){}[0]
8484
final fun <set-serializersModule>(kotlinx.serialization.modules/SerializersModule) // kotlinx.serialization.csv.config/CsvBuilder.serializersModule.<set-serializersModule>|<set-serializersModule>(kotlinx.serialization.modules.SerializersModule){}[0]
85+
final var shortValueClassHeaderName // kotlinx.serialization.csv.config/CsvBuilder.shortValueClassHeaderName|{}shortValueClassHeaderName[0]
86+
final fun <get-shortValueClassHeaderName>(): kotlin/Boolean // kotlinx.serialization.csv.config/CsvBuilder.shortValueClassHeaderName.<get-shortValueClassHeaderName>|<get-shortValueClassHeaderName>(){}[0]
87+
final fun <set-shortValueClassHeaderName>(kotlin/Boolean) // kotlinx.serialization.csv.config/CsvBuilder.shortValueClassHeaderName.<set-shortValueClassHeaderName>|<set-shortValueClassHeaderName>(kotlin.Boolean){}[0]
8588
}
8689

8790
final class kotlinx.serialization.csv.config/CsvConfig { // kotlinx.serialization.csv.config/CsvConfig|null[0]
88-
constructor <init>(kotlin/Char = ..., kotlin/String = ..., kotlin/Char = ..., kotlinx.serialization.csv.config/QuoteMode = ..., kotlin/Char? = ..., kotlin/String = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlin/Char = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlinx.serialization.modules/SerializersModule = ...) // kotlinx.serialization.csv.config/CsvConfig.<init>|<init>(kotlin.Char;kotlin.String;kotlin.Char;kotlinx.serialization.csv.config.QuoteMode;kotlin.Char?;kotlin.String;kotlin.Boolean;kotlin.Boolean;kotlin.Char;kotlin.Boolean;kotlin.Boolean;kotlinx.serialization.modules.SerializersModule){}[0]
91+
constructor <init>(kotlin/Char = ..., kotlin/String = ..., kotlin/Char = ..., kotlinx.serialization.csv.config/QuoteMode = ..., kotlin/Char? = ..., kotlin/String = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlin/Char = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlinx.serialization.modules/SerializersModule = ...) // kotlinx.serialization.csv.config/CsvConfig.<init>|<init>(kotlin.Char;kotlin.String;kotlin.Char;kotlinx.serialization.csv.config.QuoteMode;kotlin.Char?;kotlin.String;kotlin.Boolean;kotlin.Boolean;kotlin.Char;kotlin.Boolean;kotlin.Boolean;kotlin.Boolean;kotlinx.serialization.modules.SerializersModule){}[0]
8992

9093
final val delimiter // kotlinx.serialization.csv.config/CsvConfig.delimiter|{}delimiter[0]
9194
final fun <get-delimiter>(): kotlin/Char // kotlinx.serialization.csv.config/CsvConfig.delimiter.<get-delimiter>|<get-delimiter>(){}[0]
@@ -111,11 +114,14 @@ final class kotlinx.serialization.csv.config/CsvConfig { // kotlinx.serializatio
111114
final fun <get-recordSeparator>(): kotlin/String // kotlinx.serialization.csv.config/CsvConfig.recordSeparator.<get-recordSeparator>|<get-recordSeparator>(){}[0]
112115
final val serializersModule // kotlinx.serialization.csv.config/CsvConfig.serializersModule|{}serializersModule[0]
113116
final fun <get-serializersModule>(): kotlinx.serialization.modules/SerializersModule // kotlinx.serialization.csv.config/CsvConfig.serializersModule.<get-serializersModule>|<get-serializersModule>(){}[0]
117+
final val shortValueClassHeaderName // kotlinx.serialization.csv.config/CsvConfig.shortValueClassHeaderName|{}shortValueClassHeaderName[0]
118+
final fun <get-shortValueClassHeaderName>(): kotlin/Boolean // kotlinx.serialization.csv.config/CsvConfig.shortValueClassHeaderName.<get-shortValueClassHeaderName>|<get-shortValueClassHeaderName>(){}[0]
114119

115120
final fun component1(): kotlin/Char // kotlinx.serialization.csv.config/CsvConfig.component1|component1(){}[0]
116121
final fun component10(): kotlin/Boolean // kotlinx.serialization.csv.config/CsvConfig.component10|component10(){}[0]
117122
final fun component11(): kotlin/Boolean // kotlinx.serialization.csv.config/CsvConfig.component11|component11(){}[0]
118-
final fun component12(): kotlinx.serialization.modules/SerializersModule // kotlinx.serialization.csv.config/CsvConfig.component12|component12(){}[0]
123+
final fun component12(): kotlin/Boolean // kotlinx.serialization.csv.config/CsvConfig.component12|component12(){}[0]
124+
final fun component13(): kotlinx.serialization.modules/SerializersModule // kotlinx.serialization.csv.config/CsvConfig.component13|component13(){}[0]
119125
final fun component2(): kotlin/String // kotlinx.serialization.csv.config/CsvConfig.component2|component2(){}[0]
120126
final fun component3(): kotlin/Char // kotlinx.serialization.csv.config/CsvConfig.component3|component3(){}[0]
121127
final fun component4(): kotlinx.serialization.csv.config/QuoteMode // kotlinx.serialization.csv.config/CsvConfig.component4|component4(){}[0]
@@ -124,7 +130,7 @@ final class kotlinx.serialization.csv.config/CsvConfig { // kotlinx.serializatio
124130
final fun component7(): kotlin/Boolean // kotlinx.serialization.csv.config/CsvConfig.component7|component7(){}[0]
125131
final fun component8(): kotlin/Boolean // kotlinx.serialization.csv.config/CsvConfig.component8|component8(){}[0]
126132
final fun component9(): kotlin/Char // kotlinx.serialization.csv.config/CsvConfig.component9|component9(){}[0]
127-
final fun copy(kotlin/Char = ..., kotlin/String = ..., kotlin/Char = ..., kotlinx.serialization.csv.config/QuoteMode = ..., kotlin/Char? = ..., kotlin/String = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlin/Char = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlinx.serialization.modules/SerializersModule = ...): kotlinx.serialization.csv.config/CsvConfig // kotlinx.serialization.csv.config/CsvConfig.copy|copy(kotlin.Char;kotlin.String;kotlin.Char;kotlinx.serialization.csv.config.QuoteMode;kotlin.Char?;kotlin.String;kotlin.Boolean;kotlin.Boolean;kotlin.Char;kotlin.Boolean;kotlin.Boolean;kotlinx.serialization.modules.SerializersModule){}[0]
133+
final fun copy(kotlin/Char = ..., kotlin/String = ..., kotlin/Char = ..., kotlinx.serialization.csv.config/QuoteMode = ..., kotlin/Char? = ..., kotlin/String = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlin/Char = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlin/Boolean = ..., kotlinx.serialization.modules/SerializersModule = ...): kotlinx.serialization.csv.config/CsvConfig // kotlinx.serialization.csv.config/CsvConfig.copy|copy(kotlin.Char;kotlin.String;kotlin.Char;kotlinx.serialization.csv.config.QuoteMode;kotlin.Char?;kotlin.String;kotlin.Boolean;kotlin.Boolean;kotlin.Char;kotlin.Boolean;kotlin.Boolean;kotlin.Boolean;kotlinx.serialization.modules.SerializersModule){}[0]
128134
final fun equals(kotlin/Any?): kotlin/Boolean // kotlinx.serialization.csv.config/CsvConfig.equals|equals(kotlin.Any?){}[0]
129135
final fun hashCode(): kotlin/Int // kotlinx.serialization.csv.config/CsvConfig.hashCode|hashCode(){}[0]
130136
final fun toString(): kotlin/String // kotlinx.serialization.csv.config/CsvConfig.toString|toString(){}[0]

library/src/commonMain/kotlin/kotlinx/serialization/csv/config/CsvBuilder.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,11 @@ public class CsvBuilder internal constructor(
6262
*/
6363
public var hasTrailingDelimiter: Boolean = config.hasTrailingDelimiter
6464

65+
/**
66+
* Use short value class header name (default: `false`).
67+
*/
68+
public var shortValueClassHeaderName: Boolean = config.shortValueClassHeaderName
69+
6570
/**
6671
* Module with contextual and polymorphic serializers to be used in the resulting [Csv] instance.
6772
*/
@@ -111,6 +116,7 @@ public class CsvBuilder internal constructor(
111116
headerSeparator = headerSeparator,
112117
ignoreUnknownColumns = ignoreUnknownColumns,
113118
hasTrailingDelimiter = hasTrailingDelimiter,
119+
shortValueClassHeaderName = shortValueClassHeaderName,
114120
serializersModule = serializersModule,
115121
)
116122
}

library/src/commonMain/kotlin/kotlinx/serialization/csv/config/CsvConfig.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import kotlinx.serialization.modules.SerializersModule
1717
* @param headerSeparator Character that is used to separate hierarchical header names (default: `.`).
1818
* @param ignoreUnknownColumns Ignore unknown columns when `hasHeaderRecord` is enabled (default: `false`).
1919
* @param hasTrailingDelimiter If records end with a trailing [delimiter] (default: `false`).
20+
* @param shortValueClassHeaderName Use short value class header name (default: `false`).
2021
*/
2122
public data class CsvConfig(
2223
val delimiter: Char = ',',
@@ -30,6 +31,7 @@ public data class CsvConfig(
3031
val headerSeparator: Char = '.',
3132
val ignoreUnknownColumns: Boolean = false,
3233
val hasTrailingDelimiter: Boolean = false,
34+
val shortValueClassHeaderName: Boolean = false,
3335
val serializersModule: SerializersModule = EmptySerializersModule(),
3436
) {
3537

library/src/commonMain/kotlin/kotlinx/serialization/csv/decode/CsvDecoder.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,20 @@ internal abstract class CsvDecoder(
102102
}
103103
}
104104

105+
protected fun readPrimitiveHeaders(name: String) {
106+
if (config.hasHeaderRecord && headers == null) {
107+
val header = reader.readColumn()
108+
if (header != name && header != "Null") {
109+
error("Invalid header '$header' expected '$name.")
110+
}
111+
this.headers = Headers().apply {
112+
set(0, 0)
113+
}
114+
115+
readTrailingDelimiter()
116+
}
117+
}
118+
105119
private fun readHeaders(descriptor: SerialDescriptor, prefix: String): Headers {
106120
val headers = Headers()
107121
var position = 0

library/src/commonMain/kotlin/kotlinx/serialization/csv/decode/RootCsvDecoder.kt

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import kotlinx.serialization.descriptors.SerialDescriptor
66
import kotlinx.serialization.descriptors.StructureKind
77
import kotlinx.serialization.encoding.CompositeDecoder
88
import kotlinx.serialization.encoding.CompositeDecoder.Companion.DECODE_DONE
9+
import kotlinx.serialization.encoding.Decoder
910

1011
/**
1112
* Initial entry point for decoding.
@@ -43,6 +44,66 @@ internal class RootCsvDecoder(
4344
readTrailingDelimiter()
4445
}
4546

47+
override fun decodeByte(): Byte {
48+
readPrimitiveHeaders("Byte")
49+
return super.decodeByte()
50+
}
51+
52+
override fun decodeShort(): Short {
53+
readPrimitiveHeaders("Short")
54+
return super.decodeShort()
55+
}
56+
57+
override fun decodeInt(): Int {
58+
readPrimitiveHeaders("Int")
59+
return decodeColumn().toInt()
60+
}
61+
62+
override fun decodeLong(): Long {
63+
readPrimitiveHeaders("Long")
64+
return super.decodeLong()
65+
}
66+
67+
override fun decodeFloat(): Float {
68+
readPrimitiveHeaders("Float")
69+
return super.decodeFloat()
70+
}
71+
72+
override fun decodeDouble(): Double {
73+
readPrimitiveHeaders("Double")
74+
return super.decodeDouble()
75+
}
76+
77+
override fun decodeBoolean(): Boolean {
78+
readPrimitiveHeaders("Boolean")
79+
return super.decodeBoolean()
80+
}
81+
82+
override fun decodeChar(): Char {
83+
readPrimitiveHeaders("Char")
84+
return super.decodeChar()
85+
}
86+
87+
override fun decodeString(): String {
88+
readPrimitiveHeaders("String")
89+
return super.decodeString()
90+
}
91+
92+
override fun decodeNull(): Nothing? {
93+
readPrimitiveHeaders("Null")
94+
return super.decodeNull()
95+
}
96+
97+
override fun decodeEnum(enumDescriptor: SerialDescriptor): Int {
98+
readPrimitiveHeaders(enumDescriptor.serialName)
99+
return super.decodeEnum(enumDescriptor)
100+
}
101+
102+
override fun decodeInline(descriptor: SerialDescriptor): Decoder {
103+
readHeaders(descriptor)
104+
return super.decodeInline(descriptor)
105+
}
106+
46107
override fun decodeColumn(): String {
47108
val value = super.decodeColumn()
48109
position++

library/src/commonMain/kotlin/kotlinx/serialization/csv/encode/CsvEncoder.kt

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ internal abstract class CsvEncoder(
4545
StructureKind.CLASS,
4646
-> SimpleCsvEncoder(csv, writer, this)
4747

48-
StructureKind.OBJECT ->
49-
ObjectCsvEncoder(csv, writer, this)
48+
StructureKind.OBJECT,
49+
-> ObjectCsvEncoder(csv, writer, this)
5050

5151
PolymorphicKind.SEALED,
5252
-> SealedCsvEncoder(csv, writer, this, descriptor)
@@ -109,9 +109,19 @@ internal abstract class CsvEncoder(
109109
}
110110

111111
protected fun printHeaderRecord(descriptor: SerialDescriptor) {
112-
writer.beginRecord()
113-
printHeader("", descriptor)
114-
writer.endRecord()
112+
if (config.hasHeaderRecord && writer.isFirstRecord) {
113+
writer.beginRecord()
114+
printHeader("", descriptor)
115+
writer.endRecord()
116+
}
117+
}
118+
119+
protected fun printPrimitiveHeaderRecord(name: String) {
120+
if (config.hasHeaderRecord && writer.isFirstRecord) {
121+
writer.beginRecord()
122+
writer.printColumn(name)
123+
writer.endRecord()
124+
}
115125
}
116126

117127
private fun printHeader(prefix: String, descriptor: SerialDescriptor) {
@@ -137,6 +147,9 @@ internal abstract class CsvEncoder(
137147
childDesc.kind is SerialKind.ENUM ->
138148
writer.printColumn(name)
139149

150+
childDesc.isInline && config.shortValueClassHeaderName ->
151+
writer.printColumn(name)
152+
140153
childDesc.kind is PolymorphicKind.SEALED -> {
141154
writer.printColumn(name)
142155
val headerSeparator = config.headerSeparator

library/src/commonMain/kotlin/kotlinx/serialization/csv/encode/RecordListCsvEncoder.kt

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ internal class RecordListCsvEncoder(
1818
descriptor: SerialDescriptor,
1919
): CompositeEncoder {
2020
// For complex records: Begin a new record and end it in [endChildStructure]
21-
if (config.hasHeaderRecord && writer.isFirstRecord) {
22-
printHeaderRecord(descriptor)
23-
}
21+
printHeaderRecord(descriptor)
2422
writer.beginRecord()
2523
return super.beginStructure(descriptor)
2624
}

0 commit comments

Comments
 (0)