Skip to content

Commit

Permalink
adding Jackson implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
daviddenton committed Jan 5, 2024
1 parent 827e356 commit dabe374
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 50 deletions.
51 changes: 29 additions & 22 deletions data4k/src/main/kotlin/dev/forkhandles/data/DataContainer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,34 @@ abstract class DataContainer<CONTENT>(
private val getFn: (CONTENT, String) -> Any?,
private val setFn: (CONTENT, String, Any?) -> Unit
) {
/** Required **/

//
// CORE FUNCTIONS - these are the only ones that should call the defined mappings
//

fun <OUT : Any?, NEXT> field(mapInFn: (OUT) -> NEXT, mapOutFn: (NEXT) -> OUT?) =
fun <OUT : Any?, NEXT> required(mapInFn: (OUT) -> NEXT, mapOutFn: (NEXT) -> OUT?) =
property<NEXT, OUT, OUT>(mapInFn, mapOutFn)

fun <OUT : DataContainer<CONTENT>?> obj(mapInFn: (CONTENT) -> OUT, mapOutFn: (OUT) -> CONTENT?) =
fun <OUT : Any> required() = required<OUT, OUT>({ it }, { it })

fun <OUT, NEXT> required(mapInFn: (OUT) -> NEXT) = required(mapInFn) { error("no outbound mapping defined") }

fun <IN : Any, OUT : Value<IN>> required(factory: ValueFactory<OUT, IN>) =
required(factory::of) { it.value }

/** Optional **/

fun <OUT, NEXT : Any> optional(mapInFn: (OUT) -> NEXT) =
required<OUT, NEXT>(mapInFn) { error("no outbound mapping defined") }

fun <OUT, NEXT : Any> optional(mapInFn: (OUT) -> NEXT, mapOutFn: (NEXT) -> OUT?) =
required<OUT, NEXT?>(mapInFn) { it?.let(mapOutFn) }

fun <OUT> optional() = required<OUT, OUT?>({ it }, { it })

fun <IN : Any, OUT : Value<IN>> optional(factory: ValueFactory<OUT, IN>): DataProperty<DataContainer<CONTENT>, OUT?> =
required(factory::of) { it?.value }

/** Other **/

fun <OUT : DataContainer<CONTENT>> obj(mapInFn: (CONTENT) -> OUT, mapOutFn: (OUT) -> CONTENT?) =
property<OUT, CONTENT, CONTENT>(mapInFn, mapOutFn)

fun <OUT, IN> list(mapInFn: (IN) -> OUT, mapOutFn: (OUT) -> IN?) =
Expand All @@ -32,36 +51,24 @@ abstract class DataContainer<CONTENT>(
// "PRE MAPPED" FUNCTIONS
//

fun <OUT> field() = field<OUT, OUT>({ it }, { it })

fun <OUT> list() = list<OUT, OUT>({ it }, { it })

fun <OUT, NEXT> field(mapInFn: (OUT) -> NEXT) = field(mapInFn) { error("no outbound mapping defined") }

fun <IN, OUT> list(mapInFn: (IN) -> OUT) =
list(mapInFn) { error("no outbound mapping defined") }

@JvmName("listDataContainer")
fun <OUT : DataContainer<CONTENT>?> list(mapInFn: (CONTENT) -> OUT) =
list(mapInFn) { it?.data }

fun <OUT : DataContainer<CONTENT>?> obj(mapInFn: (CONTENT) -> OUT) =
obj(mapInFn) { it?.data }

//
// VALUES4K functions
//
fun <OUT : DataContainer<CONTENT>> obj(mapInFn: (CONTENT) -> OUT) =
obj(mapInFn) { it.data }

fun <IN : Any, OUT : Value<IN>> field(factory: ValueFactory<OUT, IN>) =
field(factory::of) { it.value }
fun <OUT : DataContainer<CONTENT>> optionalObj(mapInFn: (CONTENT) -> OUT): DataProperty<DataContainer<CONTENT>, OUT?> =
property<OUT?, CONTENT, CONTENT>(mapInFn) { it?.data }

fun <IN : Any, OUT : Value<IN>> list(factory: ValueFactory<OUT, IN>) =
list(factory::of) { it.value }

//
// UTILITY FUNCTIONS - for comparisons etc
//

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ interface MainClassFields<T : SubClassFields> {
var valueField: MyType

var optionalField: String?
var optionalMappedField: Int?
val optionalValueField: MyType?
var optionalObjectField: T?
val optionalListField: List<String>?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,31 +8,32 @@ import java.math.BigDecimal
class JacksonDataContainerTest : DataContainerContract<JacksonDataContainerTest.SubNodeBacked>() {

class SubNodeBacked(node: JsonNode) : JacksonDataContainer(node), SubClassFields {
override var stringField by field<String>()
override var noSuchField by field<String>()
override var stringField by required<String>()
override var noSuchField by required<String>()
}

class NodeBacked(node: JsonNode) : JacksonDataContainer(node), MainClassFields<SubNodeBacked> {
override var stringField by field<String>()
override var optionalField by field<String?>()
override var booleanField by field<Boolean>()
override var intField by field<Int>()
override var longField by field<Long>()
override var doubleField by field<Double>()
override var decimalField by field<BigDecimal>()
override var notAStringField by field<String>()
override var stringField by required<String>()
override var optionalField by optional<String>()
override var optionalMappedField by optional(String::toInt, Int::toString)
override var booleanField by required<Boolean>()
override var intField by required<Int>()
override var longField by required<Long>()
override var doubleField by required<Double>()
override var decimalField by required<BigDecimal>()
override var notAStringField by required<String>()
override var listSubClassField by list(::SubNodeBacked)
override var listField by list<String>()
override var listIntsField by list<Int>()
override var listValueField by list(MyType)
override val listMapped by list(Int::toString)
override var objectField by obj(::SubNodeBacked)
override var valueField by field(MyType)
override var mappedField by field(String::toInt, Int::toString)
override var valueField by required(MyType)
override var mappedField by required(String::toInt, Int::toString)

override val optionalListField: List<String>? by list()
override var optionalObjectField by obj<SubNodeBacked?>(::SubNodeBacked)
override val optionalValueField: MyType? by field(MyType)
override var optionalObjectField by optionalObj(::SubNodeBacked)
override var optionalValueField by optional(MyType)
}

override fun container(input: Map<String, Any?>) = NodeBacked(ObjectMapper().valueToTree(input))
Expand Down
29 changes: 15 additions & 14 deletions data4k/src/test/kotlin/dev/forkhandles/lens/MapDataContainerTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@ import java.math.BigDecimal
class MapDataContainerTest : DataContainerContract<MapDataContainerTest.SubMap>() {

class SubMap(propertySet: Map<String, Any?>) : MapDataContainer(propertySet), SubClassFields {
override var stringField by field<String>()
override var noSuchField by field<String>()
override var stringField by required<String>()
override var noSuchField by required<String>()
}

class MapBacked(map: Map<String, Any?>) : MapDataContainer(map), MainClassFields<SubMap> {
override var stringField by field<String>()
override var booleanField by field<Boolean>()
override var intField by field<Int>()
override var longField by field<Long>()
override var doubleField by field<Double>()
override var decimalField by field<BigDecimal>()
override var notAStringField by field<String>()
override var stringField by required<String>()
override var booleanField by required<Boolean>()
override var intField by required<Int>()
override var longField by required<Long>()
override var doubleField by required<Double>()
override var decimalField by required<BigDecimal>()
override var notAStringField by required<String>()

override var mappedField by field(String::toInt, Int::toString)
override var mappedField by required(String::toInt, Int::toString)
override var optionalMappedField by optional(String::toInt, Int::toString)

override var listField by list<String>()
override var listValueField by list(MyType)
Expand All @@ -29,12 +30,12 @@ class MapDataContainerTest : DataContainerContract<MapDataContainerTest.SubMap>(

override var objectField by obj(::SubMap)

override var valueField by field(MyType)
override var valueField by required(MyType)

override var optionalField by field<String?>()
override var optionalField by optional<String>()
override val optionalListField: List<String>? by list()
override var optionalObjectField by obj<SubMap?>(::SubMap)
override val optionalValueField: MyType? by field(MyType)
override var optionalObjectField by optionalObj(::SubMap)
override var optionalValueField by optional(MyType)
}

override fun container(input: Map<String, Any?>) = MapBacked(input)
Expand Down

0 comments on commit dabe374

Please sign in to comment.