org.http4k.format.ConfigurableMoshi.kt Maven / Gradle / Ivy
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.kotlin.reflect.KotlinJsonAdapterFactory
import okio.buffer
import okio.source
import org.http4k.core.Body
import org.http4k.core.ContentType
import org.http4k.core.ContentType.Companion.APPLICATION_JSON
import org.http4k.lens.BiDiBodyLensSpec
import org.http4k.lens.BiDiMapping
import org.http4k.lens.BiDiWsMessageLensSpec
import org.http4k.lens.ContentNegotiation
import org.http4k.lens.ContentNegotiation.Companion.None
import org.http4k.lens.string
import org.http4k.websocket.WsMessage
import java.io.InputStream
import java.math.BigDecimal
import java.math.BigInteger
import kotlin.reflect.KClass
open class ConfigurableMoshi(
builder: Moshi.Builder,
val defaultContentType: ContentType = APPLICATION_JSON
) : AutoMarshalling() {
private val moshi: Moshi = builder.build()
override fun asFormatString(input: Any): String = moshi.adapter(input.javaClass).toJson(input)
fun asJsonString(t: T, c: KClass): String = moshi.adapter(c.java).toJson(t)
override fun asA(input: String, target: KClass): T = moshi.adapter(target.java).fromJson(input)!!
override fun asA(input: InputStream, target: KClass): T = moshi.adapter(target.java).fromJson(
input.source().buffer()
)!!
inline fun Body.Companion.auto(
description: String? = null,
contentNegotiation: ContentNegotiation = None,
contentType: ContentType = defaultContentType
): BiDiBodyLensSpec =
autoBody(description, contentNegotiation, contentType)
inline fun autoBody(
description: String? = null,
contentNegotiation: ContentNegotiation = None,
contentType: ContentType = defaultContentType
): BiDiBodyLensSpec =
Body.string(contentType, description, contentNegotiation).map({ asA(it, T::class) }, {
asFormatString(it)
})
inline fun WsMessage.Companion.auto(): BiDiWsMessageLensSpec =
WsMessage.string().map({ it.asA(T::class) }, { asFormatString(it) })
}
fun Moshi.Builder.asConfigurable() = object : AutoMappingConfiguration {
override fun int(mapping: BiDiMapping) = adapter(mapping, { value(it) }, { nextInt() })
override fun long(mapping: BiDiMapping) =
adapter(mapping, { value(it) }, { nextLong() })
override fun double(mapping: BiDiMapping) =
adapter(mapping, { value(it) }, { nextDouble() })
override fun bigInteger(mapping: BiDiMapping) =
adapter(mapping, { value(it) }, { nextLong().toBigInteger() })
override fun bigDecimal(mapping: BiDiMapping) =
adapter(mapping, { value(it) }, { nextDouble().toBigDecimal() })
override fun boolean(mapping: BiDiMapping) =
adapter(mapping, { value(it) }, { nextBoolean() })
override fun text(mapping: BiDiMapping) =
adapter(mapping, { value(it) }, { nextString() })
private fun adapter(
mapping: BiDiMapping,
write: JsonWriter.(IN) -> Unit,
read: JsonReader.() -> IN
) =
apply {
add(mapping.clazz, object : JsonAdapter() {
override fun fromJson(reader: JsonReader) = mapping.invoke(reader.read())
override fun toJson(writer: JsonWriter, value: OUT?) {
value?.let { writer.write(mapping(it)) } ?: writer.nullValue()
}
}.nullSafe())
}
// add the Kotlin adapter last, as it will hjiack our custom mappings otherwise
override fun done() =
[email protected](KotlinJsonAdapterFactory()).add(Unit::class.java, UnitAdapter)
}
private object UnitAdapter : JsonAdapter() {
override fun fromJson(reader: JsonReader) {
reader.readJsonValue(); Unit
}
override fun toJson(writer: JsonWriter, value: Unit?) {
value?.let { writer.beginObject().endObject() } ?: writer.nullValue()
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy