https://kotlinlang.org logo
#serialization
Title
# serialization
a

Anuta Vlad Sv

01/30/2023, 2:13 PM
Hello! I am trying to deserialize a json element that ca be a single object or an empty array when no address returned. "Address":{"firstName":"firstNameValue"} or "Address":[] What I did this was to use
JsonTransformingSerializer.transformDeserialize()
and return a null JsonElement if the element is an array. And since the
JsonTransformingSerializer
does not currently support nullable types I created a
NullableJsonTransformingSerializer
. I was wondering if there is another way to deserialize the Address, and not use the transformDeserialize().
```@Serializable
data class Project(
@Serializable(with = UnwrappingJsonListSerializer::class)
val address: Address?
)
@Serializable
data class Address(val firstName: String)
object UnwrappingJsonListSerializer :
NullableJsonTransformingSerializer<Address>(Address.serializer()) {
override fun nullableTransformDeserialize(element: JsonElement): JsonElement? {
return if (element is JsonArray) null
else element
}
}```
a

Adam S

01/30/2023, 2:26 PM
I think that
JsonTransformingSerializer
supports decoding as null - but you have to return the
JsonNull
object, instead of a literal
null
could you try this?
a

Anuta Vlad Sv

01/30/2023, 2:39 PM
Thank you @Adam S for your suggestion! Looks like is throwing an exception
Exception in thread "main" kotlinx.serialization.json.internal.JsonDecodingException: Expected class kotlinx.serialization.json.JsonObject as the serialized body of com.stockx.stockx.sell.checkout.ui.Address, but had class kotlinx.serialization.json.JsonNull
so I tried specifying the serializer as nullable but I get a compile error
I was wondering if there is another way to deserialize the Address, and not use the transformDeserialize()
a

Adam S

01/30/2023, 3:02 PM
hmm, yeah so you were right,
JsonTransformingSerializer
isn’t suitable. What you could do is decode
address
to
JsonElement
, and in code convert it to
Address
if it’s a
JsonObject
Copy code
@Serializable
data class Project(
  @SerialName("address")
  private val _address: JsonElement
) {
  val address: Address? get() = when (_address) {
    is JsonObject -> Json.decodeFromJsonElement(_address)
    else          -> null
  }
}
I like this way, because there’s no custom serializer - it’s just plain Kotlin code. It’s a little weird and verbose though, and the automatic
toString()
doesn’t look correct You could automate it a little by creating a value class that will wrap the logic. Value classes are nice because they’re ‘transparent’ in terms of the actual content, but you can still use them to inject logic into Kotlinx Serialization
Copy code
@Serializable
data class Project(
  private val address: AddressWrapper
)

@Serializable
data class Address(val firstName: String)

@JvmInline
@Serializable
value class AddressWrapper(private val value: JsonElement) {
  val address: Address? get() = when (value) {
    is JsonObject -> Json.decodeFromJsonElement(value)
    else          -> null
  }

  override fun toString() = address.toString()
}
a

Anuta Vlad Sv

01/30/2023, 4:08 PM
This is cool! 🤩 Agree that is more transparent and it's great that no custom serializer is needed. Thanks a lot for your help, I really appreciate it!
a

Adam S

01/30/2023, 4:11 PM
my pleasure!
207 Views