
org.http4k.format.ConfigurableJacksonCsv.kt Maven / Gradle / Ivy
package org.http4k.format
import com.fasterxml.jackson.dataformat.csv.CsvMapper
import com.fasterxml.jackson.dataformat.csv.CsvSchema
import org.http4k.asString
import org.http4k.core.Body
import org.http4k.core.ContentType
import org.http4k.core.HttpMessage
import org.http4k.core.with
import org.http4k.lens.BiDiBodyLensSpec
import org.http4k.lens.BiDiMapping
import org.http4k.lens.ContentNegotiation
import org.http4k.lens.Meta
import org.http4k.lens.ParamMeta.ObjectParam
import org.http4k.lens.httpBodyRoot
import java.io.StringWriter
import kotlin.reflect.KClass
open class ConfigurableJacksonCsv(val mapper: CsvMapper, val defaultContentType: ContentType = ContentType.TEXT_CSV) {
inline fun defaultSchema(): CsvSchema = mapper.schemaFor(T::class.java).withHeader()
fun writerFor(type: KClass, schema: CsvSchema): (List) -> String = { body: List ->
StringWriter().use { stringWriter ->
mapper.writerFor(type.java).with(schema).writeValues(stringWriter).use {
it.writeAll(body)
}
stringWriter
}.toString()
}
fun readerFor(type: KClass, schema: CsvSchema): (String) -> List {
val reader = mapper.readerFor(type.java).with(schema)
return { body: String ->
reader.readValues(body).readAll()
}
}
inline fun writeCsv(input: List, schema: CsvSchema = defaultSchema()): String {
val writer = writerFor(T::class, schema)
return writer(input)
}
inline fun readCsv(input: String, schema: CsvSchema = defaultSchema()): List {
val reader = readerFor(T::class, schema)
return reader(input)
}
/**
* Convenience function to write the object as CSV to the message body and set the content type.
*/
inline fun R.csv(t: List): R = with(Body.auto().toLens() of t)
/**
* Convenience function to read an object as CSV from the message body.
*/
inline fun HttpMessage.csv(): List = Body.auto().toLens()(this)
inline fun asBiDiMapping(schema: CsvSchema = defaultSchema()) =
BiDiMapping>(readerFor(T::class, schema), writerFor(T::class, schema))
inline fun Body.Companion.auto(
description: String? = null,
contentNegotiation: ContentNegotiation = ContentNegotiation.None
) = autoBody(description, contentNegotiation)
inline fun autoBody(
description: String? = null,
contentNegotiation: ContentNegotiation = ContentNegotiation.None,
contentType: ContentType = defaultContentType,
schema: CsvSchema = defaultSchema()
): BiDiBodyLensSpec> {
val reader = readerFor(T::class, schema)
val writer = writerFor(T::class, schema)
return httpBodyRoot(
listOf(Meta(true, "body", ObjectParam, "body", description, emptyMap())),
contentType,
contentNegotiation
)
.map({ it.payload.asString() }, { Body(it) })
.map(reader, writer)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy