Best way to represent expandable data packet object?

16 views
Skip to first unread message

Chuanwise Rafter

unread,
Sep 7, 2024, 1:27:15 PM9/7/24
to jackson-user
I defined an protocol which can be extended by users. For example, packet can be added with additional field `namespace:add` like `{ "type": "request", ..., "namespace:add": "extended field here" }`.

I'm developing its SDK, to allow developers get expanded fields easily, I choose `Map<String, Any?>`-like class to represent raw packet data:

```kotlin
interface Data {
    val origin: MutableMap<String, Any?>
}

object DataSerializer : JsonSerializer<Data>() {
    override fun serialize(data: Data, generator: JsonGenerator, provider: SerializerProvider) {
        generator.writeObject(data.origin)
    }
}

abstract class AbstractData(
    origin: MutableMap<String, Any?>
) : Data {
    @Transient
    final override var origin: MutableMap<String, Any?> = origin
        private set

    override fun toString(): String = "${javaClass.simpleName}(${origin.entries.joinToString(", ") { "${it.key}=${it.value}" }})"
}
```

Then we delegate fields:

```kotlin
interface CauseData {
    val cause: CauseData?
}

abstract class PacketData(
    origin: MutableMap<String, Any?>
): AbstractData(origin), CauseData {

    val id: String by origin
    val type: String by origin
    override val cause: CauseData? by origin
}

class RequestPacketData(
    origin: MutableMap<String, Any?>
) : PacketData(origin) {

    val action: String by origin
    val argument: Any? by origin
    val subject: SubjectData? by origin
    val mode: String by origin
}

class ResponsePacketData(
    origin: MutableMap<String, Any?>
) : PacketData(origin) {

    val state: String by origin
    val request: String by origin
    val data: Any? by origin
}
```

As we seen, **all** fields are stored in `origin`. `XxxData` class is just a tool to access and modify fields. With the support of Kotlin extended-field, developers can easily add some new fields, which is so gracefuly.

But I have trouble in use Jackson to deserialize them. I need to read value as map, then convert some values in the map to `XxxData` if present. This process is recursive, and I don't know how to use Jackson to implements it easily.

What is the best way to represent expandable data packet object in Kotlin gracefully?

Tatu Saloranta

unread,
Sep 10, 2024, 6:59:09 PM9/10/24
to jackso...@googlegroups.com
In general adding custom (de)serializers can be quite some work, and
especially challenging for Bean (POJO) (de)serializers.
So ideally this is avoided.

In this particular case have you considered the use of @JsonAnyGetter
/ @JsonAnySetter?
They allow handling of sort of "Any" properties?

-+ Tatu +-
Reply all
Reply to author
Forward
0 new messages