All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.lancom.openapi.jackson.Wrapper.kt Maven / Gradle / Ivy

Go to download

This open-source project provides an OpenAPI 3.0 Parser implemented in Kotlin, utilizing immutable data classes

There is a newer version: 2.1.1
Show newest version
package de.lancom.openapi.jackson

import com.fasterxml.jackson.databind.JsonNode
import com.fasterxml.jackson.databind.node.ObjectNode
import de.lancom.openapi.entity.Entity
import de.lancom.openapi.entity.Extension
import de.lancom.openapi.entity.RawExtension
import de.lancom.openapi.entity.TagGroupsExtension
import de.lancom.openapi.field.Field
import de.lancom.openapi.field.getFields
import de.lancom.openapi.refs.Instance
import de.lancom.openapi.refs.Reference
import de.lancom.openapi.refs.ReferenceOrInstance
import de.lancom.openapi.refs.Referenceable
import de.lancom.openapi.tools.jsonMapper

data class Wrapper(
    val jsonNodeField: Field,
) {
    val field: Field by lazy {
        jsonNodeField.mapField(::Wrapper)
    }

    val mapField: Field> by lazy {
        jsonNodeField.map { jsonNode ->
            jsonNode.fields().iterator().asSequence().toList().associate { (k, v) ->
                k to Wrapper(v)
            }
        }
    }

    val listField: Field> by lazy {
        jsonNodeField.map { jsonNode ->
            jsonNode.elements().iterator().asSequence().toList().map(Field.Companion::invoke).map(::Wrapper)
        }
    }

    val jsonNodeFieldOrUnsetIfEmpty: Field by lazy {
        jsonNodeField.takeUnlessField { jsonNode ->
            jsonNode is ObjectNode && jsonNode.isEmpty
        }
    }

    operator fun get(fieldName: String): Wrapper {
        val wrapperField = mapField.flatMap { map: Map ->
            Field.unsetIfNull(map[fieldName])
        }
        return wrapperField.getOrElse {
            UNSET
        }
    }

    fun  getMap(
        mapper: Wrapper.() -> Field,
    ): Field> {
        return getMap({ key -> key }, mapper)
    }

    fun  getMap(
        keyMapper: (String) -> K,
        valueMapper: Wrapper.() -> Field,
    ): Field> {
        return mapField.map { map: Map ->
            map.map { (key, wrapper) ->
                keyMapper(key) to valueMapper(wrapper)
            }.toMap().getFields()
        }
    }

    fun  getList(
        mapper: Wrapper.() -> Field,
    ): Field> {
        return listField.map { list: List ->
            list.map { wrapper ->
                wrapper.mapper()
            }.getFields()
        }
    }

    fun  getSingle(
        mapper: Wrapper.() -> Field,
    ): Field {
        return mapField.flatMap {
            this.mapper()
        }
    }

    fun  getUnlessEmpty(
        mapper: Wrapper.() -> Field>,
    ): Field> {
        return mapField.flatMap {
            this.mapper().flatMap { map: Map ->
                Field.takeUnlessEmpty(map)
            }
        }
    }

    fun  getSet(
        mapper: Wrapper.() -> Field,
    ): Field> {
        return getList(mapper).map(List::toSet)
    }

    private fun  getNull(): Field {
        return jsonNodeField.flatMap { jsonNode ->
            if (jsonNode.isNull) {
                Field(null)
            } else {
                Field.unset()
            }
        }
    }

    fun > getNullOrElseUnsetIfEmptyCollection(fallback: Wrapper.() -> Field): Field {
        return getNullOrElse {
            fallback().flatMap { collection ->
                Field.unsetIfNull(collection.takeUnlessEmpty())
            }
        }
    }

    fun  getNullOrElseUnsetIfEmptyMap(fallback: Wrapper.() -> Field>): Field?> {
        return getNullOrElse {
            fallback().flatMap { collection ->
                Field.unsetIfNull(collection.takeUnlessEmpty())
            }
        }
    }

    fun  getNullOrElse(fallback: Wrapper.() -> Field): Field {
        return getNull().orElse {
            @Suppress("UNCHECKED_CAST")
            getElse(fallback) as Field
        }
    }

    fun  getElse(fallback: Wrapper.() -> Field): Field {
        return jsonNodeField.flatMap {
            this.fallback()
        }
    }

    fun  getEntity(
        transform: Wrapper.() -> E,
    ): Field {
        return mapField.map {
            transform(this)
        }
    }

    fun  getReference(): Field> {
        return mapField.flatMap { mapped ->
            if (mapped.size == 1) {
                this["\$ref"].getString().map { ref ->
                    Reference(ref)
                }
            } else {
                Field.unset()
            }
        }
    }

    fun  getReferenceOrEntity(
        transform: Wrapper.() -> R
    ): Field> {
        return getReference().map { ref: ReferenceOrInstance ->
            ref
        }.orElse {
            getEntity(transform).map { entity: R ->
                Instance(entity)
            }
        }
    }

    fun getBoolean(): Field {
        return jsonNodeField.map(JsonNode::booleanValueOrError)
    }

    fun getString(): Field {
        return jsonNodeField.map { jsonNode ->
            when {
                // parse boolean as string...
                jsonNode.isBoolean ->
                    jsonNode.booleanValue().toString()

                // parse number as string...
                jsonNode.isNumber ->
                    jsonNode.numberValue().toString()

                else ->
                    jsonNode.textValueOrError()
            }
        }
    }

    fun getNumber(): Field {
        return jsonNodeField.map(JsonNode::numberValueOrError)
    }

    fun getInt(): Field {
        return getNumber().map { number: Number ->
            number.toInt()
        }
    }

    inline fun > getEnum(
        noinline transform: (String) -> E,
    ): Field {
        return getString().map(transform)
    }

    fun getExtensions(): Field> {
        return mapField.flatMap { mapped ->
            val extensions = mapped.filter { (name, _) ->
                name.startsWith("x-")
            }.map { (name, wrapper) ->
                wrapper.jsonNodeField.map { value ->
                    val extension = when {
                        // TODO hardcoded :(
                        name == "x-tagGroups" ->
                            TagGroupsExtension.parseWrapper(wrapper)

                        value.isNull ->
                            null

                        value.isNumber || value.isTextual || value.isBoolean || value.isArray || value.isObject ->
                            RawExtension(Field(value))

                        else ->
                            throw NotImplementedError()
                    }
                    name to extension
                }
            }

            Field.unsetIfNull(
                extensions
                    .getFields()
                    .toMap()
                    .takeUnlessEmpty()
            )
        }
    }

    companion object {
        operator fun invoke(jsonNode: JsonNode): Wrapper {
            return Wrapper(Field(jsonNode))
        }

        val UNSET: Wrapper = Wrapper(Field.unset())

        fun parseJsonString(json: String): Wrapper {
            val tree = jsonMapper.readTree(json)
            return Wrapper(tree)
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy