Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ubertob.kondor.json

import com.ubertob.kondor.json.array.JSet
import com.ubertob.kondor.json.jsonnode.NodePathRoot
import com.ubertob.kondor.outcome.Failure
import com.ubertob.kondor.randomList
Expand Down Expand Up @@ -146,4 +147,4 @@ class JDataClassTest {
PersonRefl.testParserAndRender(100) { randomPerson() }

}
}
}
2 changes: 1 addition & 1 deletion kondor-core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -105,4 +105,4 @@ signing {

tasks.withType<Javadoc> {
(options as StandardJavadocDocletOptions).addBooleanOption("html5", true)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.ubertob.kondor.json

import com.ubertob.kondor.json.array.JList
import com.ubertob.kondor.json.array.JSet
import com.ubertob.kondor.json.jsonnode.JsonNodeObject
import java.math.BigDecimal
import java.math.BigInteger
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.ubertob.kondor.json.array

import com.ubertob.kondor.json.*
import com.ubertob.kondor.json.JsonStyle.Companion.appendArrayValues

class JAnyAsArray<T : Any, PT : Any, IterT : Iterable<T>>(
override val converter: JConverter<T>,
override val cons: (IterT) -> PT,
override val binder: PT.() -> IterT,
) : JArrayRepresentable<PT, T, IterT>() {

override fun appendValue(app: CharWriter, style: JsonStyle, offset: Int, value: PT): CharWriter {
return app.appendArrayValues(style, offset, value.binder(), converter::appendValue)
}

@Suppress("UNCHECKED_CAST")
override fun convertToAny(from: Iterable<T?>): PT = cons(from.filterNotNull() as IterT)
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.ubertob.kondor.json.array

import com.ubertob.kondor.json.*
import com.ubertob.kondor.json.jsonnode.*

abstract class JArray<T : Any, IterT : Iterable<T?>> : JArrayRepresentable<IterT, T, IterT>() {
override val _nodeType = ArrayNode

override val cons: (IterT) -> IterT = { it }
override val binder: IterT.() -> IterT = { this }
override fun convertToAny(from: Iterable<T?>) = convertToCollection(from)

abstract fun convertToCollection(from: Iterable<T?>): IterT
}


data class JList<T : Any>(override val converter: JConverter<T>) : JArray<T, List<T>>() {
override fun convertToCollection(from: Iterable<T?>): List<T> = from.filterNotNull()
}

data class JNullableList<T : Any>(override val converter: JConverter<T>) : JArray<T, List<T?>>() {

override val jsonStyle = JsonStyle.singleLineWithNulls
override fun convertToCollection(from: Iterable<T?>): List<T?> = from.toList()
override val _nodeType = ArrayNode
}

data class JSet<T : Any>(override val converter: JConverter<T>) : JArray<T, Set<T>>() {
override fun convertToCollection(from: Iterable<T?>): Set<T> = from.filterNotNull().toSet()
override val _nodeType = ArrayNode
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package com.ubertob.kondor.json.array

import com.ubertob.kondor.json.*
import com.ubertob.kondor.json.JsonStyle.Companion.appendArrayValues
import com.ubertob.kondor.json.jsonnode.*
import com.ubertob.kondor.json.parser.KondorSeparator
import com.ubertob.kondor.json.parser.TokensStream
import com.ubertob.kondor.json.parser.parseArray
import com.ubertob.kondor.json.parser.surrounded
import com.ubertob.kondor.json.schema.arraySchema
import com.ubertob.kondor.outcome.Outcome
import com.ubertob.kondor.outcome.traverseIndexed

abstract class JArrayRepresentable<T: Any, IT : Any, IterIT : Iterable<IT?>> : JArrayConverter<T> {
override val _nodeType = ArrayNode

abstract val converter: JConverter<IT>
abstract val cons : (IterIT) -> T
abstract val binder: T.() -> IterIT

abstract fun convertToAny(from: Iterable<IT?>): T

override fun fromJsonNode(node: JsonNodeArray, path: NodePath): Outcome<JsonError, T> =
mapFromArray(node) { i, e -> converter.fromJsonNodeBase(e, NodePathSegment("[$i]", path)) }
.transform { convertToAny(it) }

override fun toJsonNode(value: T): JsonNodeArray =
mapToJson(value.binder()) { converter.toJsonNode(it) }

override fun appendValue(app: CharWriter, style: JsonStyle, offset: Int, value: T): CharWriter =
app.appendArrayValues(style, offset, value.binder(), converter::appendValue)

private fun mapFromArray(
node: JsonNodeArray,
f: (Int, JsonNode) -> JsonOutcome<IT?>
): JsonOutcome<Iterable<IT?>> = node.elements
.traverseIndexed(f)

private fun <T : Any> mapToJson(objs: Iterable<T?>, f: (T) -> JsonNode): JsonNodeArray =
JsonNodeArray(objs.map { if (it == null) JsonNodeNull else f(it) })

@Suppress("UNCHECKED_CAST")
override fun fromTokens(tokens: TokensStream, path: NodePath): JsonOutcome<T> =
surrounded(
KondorSeparator.OpeningBracket,
{ t, p -> parseArray(t, p, converter::fromTokens).transform { cons(it as IterIT) } },
KondorSeparator.ClosingBracket
)(tokens, path)

override fun schema(): JsonNodeObject = arraySchema(converter)
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
package com.ubertob.kondor.json
package com.ubertob.kondor.json.array

import com.ubertob.kondor.json.*
import com.ubertob.kondor.json.JsonStyle.Companion.appendArrayValues
import com.ubertob.kondor.json.jsonnode.*
import com.ubertob.kondor.json.parser.KondorSeparator.ClosingBracket
import com.ubertob.kondor.json.parser.KondorSeparator.OpeningBracket
import com.ubertob.kondor.json.parser.TokensStream
import com.ubertob.kondor.json.parser.parseArray
import com.ubertob.kondor.json.parser.surrounded
import com.ubertob.kondor.json.schema.arraySchema
import com.ubertob.kondor.outcome.Outcome
import com.ubertob.kondor.outcome.traverseIndexed
import com.ubertob.kondor.outcome.asSuccess
import com.ubertob.kondor.outcome.bindFailure
import com.ubertob.kondor.outcome.foldOutcomeIndexed

interface JArray<T : Any, IterT : Iterable<T?>> : JArrayConverter<IterT> {
/**
* Array converter that ignorer failures in its sub converter
*/
class JListIgnoreFailures<T : Any, IterT : Iterable<T?>>(val converter: JConverter<T>) : JArrayConverter<IterT> {
override val _nodeType: NodeKind<JsonNodeArray> = ArrayNode

val converter: JConverter<T>

fun convertToCollection(from: Iterable<T?>): IterT
@Suppress("UNCHECKED_CAST")
fun convertToCollection(from: Iterable<T?>): IterT = from.filterNotNull() as IterT

override fun fromJsonNode(node: JsonNodeArray, path: NodePath): Outcome<JsonError, IterT> =
mapFromArray(node) { i, e -> converter.fromJsonNodeBase(e, NodePathSegment("[$i]", path)) }
Expand All @@ -36,9 +41,9 @@ interface JArray<T : Any, IterT : Iterable<T?>> : JArrayConverter<IterT> {
node: JsonNodeArray,
f: (Int, JsonNode) -> JsonOutcome<T?>
): JsonOutcome<Iterable<T?>> = node.elements
.traverseIndexed(f)

override fun schema(): JsonNodeObject = arraySchema(converter)
.foldOutcomeIndexed(mutableListOf()) { index, acc, e ->
f(index, e).transform { acc.add(it); acc }.bindFailure { acc.asSuccess() }
}

override fun appendValue(app: CharWriter, style: JsonStyle, offset: Int, value: IterT): CharWriter =
app.appendArrayValues(style, offset, value, converter::appendValue)
Expand All @@ -50,23 +55,4 @@ interface JArray<T : Any, IterT : Iterable<T?>> : JArrayConverter<IterT> {
{ t, p -> parseArray(t, p, converter::fromTokens).transform { it as IterT } },
ClosingBracket
)(tokens, path)

}


data class JList<T : Any>(override val converter: JConverter<T>) : JArray<T, List<T>> {
override fun convertToCollection(from: Iterable<T?>): List<T> = from.filterNotNull().toList()
override val _nodeType = ArrayNode
}

data class JNullableList<T : Any>(override val converter: JConverter<T>) : JArray<T, List<T?>> {

override val jsonStyle = JsonStyle.singleLineWithNulls
override fun convertToCollection(from: Iterable<T?>): List<T?> = from.toList()
override val _nodeType = ArrayNode
}

data class JSet<T : Any>(override val converter: JConverter<T>) : JArray<T, Set<T>> {
override fun convertToCollection(from: Iterable<T?>): Set<T> = from.filterNotNull().toSet()
override val _nodeType = ArrayNode
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package com.ubertob.kondor.json
import com.ubertob.kondor.*
import com.ubertob.kondor.json.JsonStyle.Companion.prettyWithNulls
import com.ubertob.kondor.json.TitleType.Companion.fromLabel
import com.ubertob.kondor.json.array.JArray
import com.ubertob.kondor.json.array.JList
import com.ubertob.kondor.json.datetime.num
import com.ubertob.kondor.json.datetime.str
import com.ubertob.kondor.json.jsonnode.*
Expand Down Expand Up @@ -337,7 +339,7 @@ class Products : ArrayList<Product>() {
}

//custom collection
object JProducts : JArray<Product, Products> {
object JProducts : JArray<Product, Products>() {
override val converter = JProduct

override fun convertToCollection(from: Iterable<Product?>) =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.ubertob.kondor.json

import com.ubertob.kondor.json.JsonStyle.Companion.pretty
import com.ubertob.kondor.json.array.JList
import com.ubertob.kondor.json.jsonnode.NodePathRoot
import com.ubertob.kondor.lowercase
import com.ubertob.kondor.randomList
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.ubertob.kondor.json

import com.ubertob.kondor.json.array.JList
import com.ubertob.kondor.json.array.JSet
import com.ubertob.kondor.json.jsonnode.NodePathRoot
import com.ubertob.kondor.randomList
import com.ubertob.kondor.randomString
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import com.ubertob.kondor.json.JsonStyle.Companion.compact
import com.ubertob.kondor.json.JsonStyle.Companion.compactWithNulls
import com.ubertob.kondor.json.JsonStyle.Companion.pretty
import com.ubertob.kondor.json.JsonStyle.Companion.prettyWithNulls
import com.ubertob.kondor.json.array.JList
import com.ubertob.kondor.json.array.JNullableList
import com.ubertob.kondor.json.jsonnode.*
import com.ubertob.kondortools.expectSuccess
import org.junit.jupiter.api.Test
Expand Down Expand Up @@ -314,7 +316,7 @@ class JsonRenderTest {
expectThat(jsonString).isEqualTo(expected)
}
}

@Test
fun `pretty render array with nested objects and arrays`() {
repeat(5) {
Expand Down Expand Up @@ -344,7 +346,7 @@ class JsonRenderTest {
))
))
))

val jsonString = tree.render(pretty)

val expected = """[
Expand Down Expand Up @@ -373,11 +375,11 @@ class JsonRenderTest {
| ]
| }
|]""".trimMargin()

expectThat(jsonString).isEqualTo(expected)
}
}

@Test
fun `pretty render object with nested objects and arrays`() {
repeat(5) {
Expand Down Expand Up @@ -407,7 +409,7 @@ class JsonRenderTest {
))
))
))

val jsonString = tree.render(pretty)

val expected = """{
Expand Down Expand Up @@ -436,7 +438,7 @@ class JsonRenderTest {
| ]
| }
|}""".trimMargin()

expectThat(jsonString).isEqualTo(expected)
}
}
Expand Down Expand Up @@ -534,4 +536,4 @@ class JsonRenderTest {
|}""".trimMargin()
)
}
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.ubertob.kondor.json

import com.ubertob.kondor.json.array.JList
import com.ubertob.kondor.json.jsonnode.JsonNodeObject
import com.ubertob.kondor.json.jsonnode.parseJsonNode
import com.ubertob.kondortools.expectFailure
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import com.ubertob.kondor.json.JInt
import com.ubertob.kondor.json.array.JAnyAsArray
import com.ubertob.kondortools.expectSuccess
import org.junit.jupiter.api.Test
import strikt.api.expectThat
import strikt.assertions.isEqualTo

class JAnyAsArrayTest {
@Test
fun `encodes an object that may be represented as an array`() {
val a = Arrayable(listOf(1, 2, 3))
val json = JArrayable.toJson(a)

expectThat(json).isEqualTo("[1, 2, 3]")
expectThat(JArrayable.fromJson(json).expectSuccess()).isEqualTo(a)
}
}

private data class Arrayable(val list: List<Int>)

private val JArrayable = JAnyAsArray(JInt, ::Arrayable, Arrayable::list)
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package com.ubertob.kondor.json.array

import com.ubertob.kondor.json.JInt
import com.ubertob.kondor.json.jsonnode.JsonNodeArray
import com.ubertob.kondor.json.jsonnode.JsonNodeNumber
import com.ubertob.kondor.json.jsonnode.JsonNodeString
import com.ubertob.kondortools.expectSuccess
import strikt.api.expectThat
import strikt.assertions.isEqualTo
import org.junit.jupiter.api.Test

class JListIgnoreFailuresTest {
val aMixedBagJsonNode = JsonNodeArray(
listOf(
JsonNodeNumber(1),
JsonNodeNumber(2),
JsonNodeString("two-and-a-half"),
JsonNodeNumber(3)
)
)

val anUnmixedBag = listOf(1,2,3)

val converter = JListIgnoreFailures(JInt)

@Test
fun `ignores failures in the collection type conversion`() {
val deserialized = converter.fromJsonNodeBase(aMixedBagJsonNode).expectSuccess()
expectThat(deserialized).isEqualTo(anUnmixedBag)
}

@Test
fun `still serializes normally`() {
val json = converter.toJson(anUnmixedBag)
val deserialized = converter.fromJson(json).expectSuccess()

expectThat(deserialized).isEqualTo(anUnmixedBag)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.ubertob.kondor.loadTests
import com.ubertob.kondor.all
import com.ubertob.kondor.chronoAndLog
import com.ubertob.kondor.json.*
import com.ubertob.kondor.json.array.JList
import com.ubertob.kondor.json.jsonnode.ArrayNode
import com.ubertob.kondor.json.jsonnode.NodePathRoot
import com.ubertob.kondor.json.jsonnode.onRoot
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.ubertob.kondor.json.jmh

import com.ubertob.kondor.json.*
import com.ubertob.kondor.json.array.JList
import com.ubertob.kondor.json.jsonnode.JsonNodeObject


Expand All @@ -26,4 +27,4 @@ object JDemoClass : JAny<DemoClass>() {
val jDemoClasses = JList(JDemoClass)

val demoClassNdProducer = toNdJson(JDemoClass)
val demoClassNdConsumer = fromNdJsonToList(JDemoClass)
val demoClassNdConsumer = fromNdJsonToList(JDemoClass)