Object is a List of Type X or Type X


#1

Hi everyone,
I’m parsing a Json into my data class using Jackson and the Json is quite complex.
There is the possibility that the Item “p” in the Json is a List of pItems or it is just a pItem, depending on the amount of pItems that result from my request.

Right now I solved the parsing like this :

val mapper = jacksonObjectMapper().apply {
    propertyNamingStrategy = PropertyNamingStrategy.LOWER_CAMEL_CASE
    setSerializationInclusion(JsonInclude.Include.NON_NULL)
    convert(PObjectSeal::class,      { PObjectSeal.fromJson(it) },      { it.toJson() }, true)
}

sealed class PObjectSeal {
    class PObjectArrayValue(val value: List<PObject>) : PObjectSeal()
    class PObjectValue(val value: PObject)            : PObjectSeal()

    fun toJson(): String = mapper.writeValueAsString(when (this) {
        is PObjectArrayValue -> this.value
        is PObjectValue      -> this.value
    })

    companion object {
        fun fromJson(jn: JsonNode): PObjectSeal = when (jn) {
            is ArrayNode  -> PObjectArrayValue(mapper.treeToValue(jn))
            is ObjectNode -> PObjectValue(mapper.treeToValue(jn))
            else          -> throw IllegalArgumentException()
        }
    }
}

data class PObject(
    @get:JsonProperty("content")@field:JsonProperty("content")
    val content: ContentSeal? = null,

    @get:JsonProperty("Name")@field:JsonProperty("Name")
    val name: String? = null,

    @get:JsonProperty("Class")@field:JsonProperty("Class")
    val pClass: String? = null
)

But now I facing the issue/inconvenience of using the Object in my Program.

if (eachFoundLine.p is PObjectSeal.PObjectArrayValue) {
   eachFoundLine.p.value.foreach { ... }
} else if (eachFoundLine.p is PObjectSeal.PObjectValue) {
   eachFoundLine.p.value ....
}

In each case I do the same thing with the data, on one I do it on every Item and on the other one just on one.

This is just so inconvenient since this can be encapsulated, as you can see with the ContentSeal, which would be the same case.

How would you guys solve this ?
Is there a better way of accessing/determining the data.

Thank you for your help !


#2

You could define a function like the following (you can probably come up with a better name than foreach)

fun PObjectSeal.foreach(action: (PObject) -> Unit) = when(this) {
  is PObjectArrayValue -> value.foreach(action)
  is PObjectValue      -> action(value)
}

Now you can simply write:

eachFoundLine.p.foreach { /* do something */ }

#3

Add an inline modifier :slight_smile: