Kotlin Duration Adapter fails to be generated with codegen
andretmarques opened this issue · 0 comments
andretmarques commented
When integrating custom adapters and annotations with kotlin.time.Duration, the expected behavior is for the adapter to accurately convert JSON's long values into Kotlin's Duration type. However, I've observed that the deserialization process doesn't work as expected. Instead of obtaining a Duration object, the output remains as a Long type. This issue seems to occur during the deserialization process, indicating a potential problem in the handling of Kotlin's Duration type.
Here is the adapter and annotations created:
@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class DurationMillis
@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class DurationSeconds
@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class DurationMinutes
object DurationJsonAdapter {
@ToJson
fun millisToJson(@DurationMillis duration: Duration): Long = duration.inWholeMilliseconds
@FromJson
@DurationMillis
fun millisFromJson(value: Long): Duration = value.milliseconds
@ToJson
fun secondsToJson(@DurationSeconds duration: Duration): Long = duration.inWholeSeconds
@FromJson
@DurationSeconds
fun secondsFromJson(value: Long): Duration = value.seconds
@ToJson
fun minutesToJson(@DurationMinutes duration: Duration): Long = duration.inWholeMinutes
@FromJson
@DurationMinutes
fun minutesFromJson(value: Long): Duration = value.minutes
}
with some tests included:
class DurationJsonAdapterTest {
@JsonClass(generateAdapter = true)
data class DurationTypes(
@Json(name = "durationMillis") @DurationMillis val durationMillis: Duration,
@Json(name = "durationSeconds") @DurationSeconds val durationSeconds: Duration,
@Json(name = "durationMinutes") @DurationMinutes val durationMinutes: Duration,
)
private val moshi = Moshi.Builder()
.add(DurationJsonAdapter)
.build()
@OptIn(ExperimentalStdlibApi::class)
@Test
fun fromJson() {
val adapter = moshi.adapter<DurationTypes>()
val json = """{"durationMillis": 120000, "durationSeconds": 120, "durationMinutes": 2}"""
val javanDuration = adapter.fromJson(json)
assertEquals(2.minutes, javanDuration?.durationMillis)
assertEquals(2.minutes, javanDuration?.durationSeconds)
assertEquals(2.minutes, javanDuration?.durationMinutes)
}
@OptIn(ExperimentalStdlibApi::class)
@Test
fun toJson() {
val adapter: JsonAdapter<DurationTypes> = moshi.adapter<DurationTypes>()
val javanDuration = DurationTypes(2.minutes, 2.minutes, 2.minutes)
val json = adapter.toJson(javanDuration)
assertEquals("""{"durationMillis":120000, "durationSeconds":120, "durationMinutes":2}""", json)
}
}
With Java Duration (java.time.Duration
) works perfectly well
class JavaDurationJsonAdapterTest {
@JsonClass(generateAdapter = true)
data class DurationTypes(
@Json(name = "durationMillis") @JavaDurationMillis val durationMillis: JavaDuration,
@Json(name = "durationSeconds") @JavaDurationSeconds val durationSeconds: JavaDuration,
@Json(name = "durationMinutes") @JavaDurationMinutes val durationMinutes: JavaDuration,
)
private val moshi = Moshi.Builder()
.add(JavaDurationJsonAdapter)
.build()
@OptIn(ExperimentalStdlibApi::class)
@Test
fun fromJson() {
val adapter = moshi.adapter<DurationTypes>()
val json = """{"durationMillis": 120000, "durationSeconds": 120, "durationMinutes": 2}"""
val javanDuration = adapter.fromJson(json)
assertEquals(JavaDuration.ofMinutes(2), javanDuration?.durationMillis)
assertEquals(JavaDuration.ofMinutes(2), javanDuration?.durationSeconds)
assertEquals(JavaDuration.ofMinutes(2), javanDuration?.durationMinutes)
}
@OptIn(ExperimentalStdlibApi::class)
@Test
fun toJson() {
val adapter: JsonAdapter<DurationTypes> = moshi.adapter<DurationTypes>()
val javanDuration = DurationTypes(JavaDuration.ofMinutes(2), JavaDuration.ofMinutes(2), JavaDuration.ofMinutes(2))
val json = adapter.toJson(javanDuration)
assertEquals("""{"durationMillis":120000,"durationSeconds":120,"durationMinutes":2}""", json)
}
}
@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class JavaDurationMillis
@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class JavaDurationSeconds
@Retention(AnnotationRetention.RUNTIME)
@JsonQualifier
annotation class JavaDurationMinutes
object JavaDurationJsonAdapter {
@ToJson
fun millisToJson(@JavaDurationMillis duration: JavaDuration): Long = duration.toMillis()
@FromJson
@JavaDurationMillis
fun millisFromJson(value: Long): JavaDuration = JavaDuration.ofMillis(value)
@ToJson
fun secondsToJson(@JavaDurationSeconds duration: JavaDuration): Long = duration.toSeconds()
@FromJson
@JavaDurationSeconds
fun secondsFromJson(value: Long): JavaDuration = JavaDuration.ofSeconds(value)
@ToJson
fun minutesToJson(@JavaDurationMinutes duration: JavaDuration): Long = duration.toMinutes()
@FromJson
@JavaDurationMinutes
fun minutesFromJson(value: Long): JavaDuration = JavaDuration.ofMinutes(value)
}