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

org.http4k.format.adapters.kt Maven / Gradle / Ivy

There is a newer version: 5.35.1.0
Show newest version
package org.http4k.format

import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.JsonReader
import com.squareup.moshi.JsonWriter
import com.squareup.moshi.Moshi
import com.squareup.moshi.Types
import dev.forkhandles.values.AbstractValue
import org.http4k.events.Event
import java.lang.reflect.Type
import kotlin.reflect.KClass

/**
 * Convenience class to create Moshi Adapter Factory
 */
open class SimpleMoshiAdapterFactory(vararg typesToAdapters: Pair JsonAdapter<*>>) :
    JsonAdapter.Factory {
    private val mappings = typesToAdapters.toMap()

    override fun create(type: Type, annotations: Set, moshi: Moshi) =
        mappings[Types.getRawType(type).typeName]?.let { it(moshi) }
}

/**
 * Convenience function to create Moshi Adapter.
 */
inline fun , reified K> adapter(noinline fn: (Moshi) -> T) = K::class.java.name to fn

/**
 * Convenience function to create Moshi Adapter Factory for a simple Moshi Adapter
 */
inline fun  JsonAdapter.asFactory() = SimpleMoshiAdapterFactory(K::class.java.name to { this })

/**
 * Convenience function to add a custom adapter.
 */
inline fun , reified K> Moshi.Builder.addTyped(fn: T): Moshi.Builder =
    add(K::class.java, fn)

/**
 * This adapter factory will capture ALL instances of a particular superclass/interface.
 */
abstract class IsAnInstanceOfAdapter(
    private val clazz: KClass,
    private val resolveAdapter: Moshi.(KClass) -> JsonAdapter = { adapter(it.java) }
) : JsonAdapter.Factory {
    override fun create(type: Type, annotations: Set, moshi: Moshi) =
        with(Types.getRawType(type)) {
            when {
                isA(clazz.java) -> moshi.resolveAdapter(clazz)
                else -> null
            }
        }

    private fun Class<*>?.isA(testCase: Class<*>): Boolean =
        this?.let { testCase != this && testCase.isAssignableFrom(this) } ?: false
}

/**
 * These adapters are the edge case adapters for dealing with Moshi
 */
object ThrowableAdapter : IsAnInstanceOfAdapter(Throwable::class)

object MapAdapter : IsAnInstanceOfAdapter>(Map::class)

object ListAdapter : IsAnInstanceOfAdapter>(List::class)

object SetAdapter : IsAnInstanceOfAdapter>(Set::class)

object EventAdapter : JsonAdapter.Factory {
    override fun create(p0: Type, p1: MutableSet, p2: Moshi) =
        if (p0.typeName == Event::class.java.typeName) p2.adapter(Any::class.java) else null
}

object ProhibitUnknownValuesAdapter : JsonAdapter.Factory {
    override fun create(type: Type, annotations: Set, moshi: Moshi) =
        when {
            (type as? Class<*>)?.superclass == AbstractValue::class.java -> throw UnmappedValue(type)
            else -> null
        }
}

object MoshiNodeAdapter : JsonAdapter.Factory {
    override fun create(type: Type, annotations: Set, moshi: Moshi) =
        with(Types.getRawType(type)) {
            when {
                isA(MoshiNode::class.java) -> object : JsonAdapter() {
                    override fun fromJson(p0: JsonReader) = MoshiNode.wrap(p0.readJsonValue())

                    override fun toJson(p0: JsonWriter, p1: MoshiNode?) {
                        p1?.let { moshi.adapter(Any::class.java).toJson(p0, it.unwrap()) }
                    }
                }

                else -> null
            }
        }

    private fun Class<*>?.isA(testCase: Class<*>): Boolean =
        this?.let { testCase != this && testCase.isAssignableFrom(this) } ?: false
}

class UnmappedValue(type: Type) : Exception("unmapped type $type")




© 2015 - 2024 Weber Informatics LLC | Privacy Policy