How do we flatten a JSON with nested elements into...
# serialization
b
How do we flatten a JSON with nested elements into a single class? E.g. I’ve to following OSM data that I need to have in just one class, without creating a subclass for `tags`:
Copy code
{
  "type": "node",
  "id": 66917229,
  "lat": 52.5167295,
  "lon": 13.3797732,
  "tags": {
    "addr:city": "Berlin",
    "addr:housenumber": "4a",
    "addr:postcode": "10117",
    "addr:street": "Pariser Platz",
    "amenity": "cafe",
    "brand": "Starbucks",
    "name": "Starbucks",
    "website": "<https://www.starbucks.de/store-locator/store/2099/pariser-platz-pariser-platz-4-a-berlin-be-10117-de>",
    "wheelchair": "yes",
    "wifi": "free"
  }
}
I am using custom Serializer but I’m a bit lost on how to unwrap the nested values in the
deserialize
function for the nested tags element. Any help is highly appreciated.
r
Is there a reason you can't make a class for the nested elements and have it as a parameter? Generally I've found it's easier to change the shape of your Kotlin classes than do transforms on the JSON. If you need a certain interface in your code you can use secondary constructors or pull out an interface and use delegation. If you really need to use the deserializaer, I think you'd want to use encode/decodeStructure, see https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/serializers.md#hand-written-composite-serializer Another option is going from string to JsonElement, transforming the json objects, and then going from JsonElement to your classes
b
Is there a reason you can’t make a class for the nested elements and have it as a parameter?
It works as a nested class but I wanted to keep it on a single level to keep it a bit cleaner. I could try with a custom Serializer with a
SerialDescriptor
but I’m not sure how to represent the nested
tags
structure. Is there an example that I could follow?
Copy code
override val descriptor: SerialDescriptor =
        buildClassSerialDescriptor("element") {
        	element<String>("type")
        	element<String>("id")
        	
            // How to represent tags?
            element<String>("tags")

            element<String>("addr:housenumber")            
        }
r
I don't think there's support for it in the descriptor. However, I don't think there needs to be. You'd just need a second descriptor for the nested data, and to use
decodeStructure
and the other decode methods with it inside the section for decoding tags
Another possibly better option is to make
tags
a
Map<String, String>
if everything's a string, or
Map<String, JsonElement>
or just a
JsonObject
. All of those would be deserialized correctly as far as I know. You could then just delegate to the map for your properties (i.e.
val brand by tags
if it's a
Map<String, String>
.
b
That’s cool, but me being a noob, I’m not so well versed in Kotlin (yet). Do we have an example code somewhere that has this in action?
v
As your format is JSON, you could also use a JSON transformation instead of a custom serializer: https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/json.md#json-transformations
b
Ok, let me try the JSON transforms. Else I’ll just live with a nested class for now
r
For delegation, https://kotlinlang.org/docs/reference/delegated-properties.html covers it pretty well. I don't know of any full examples off the top of my head. https://kotlinlang.org/docs/reference/delegation.html covers class delegation
1025 Views