Skip to content

Commit

Permalink
allow codecs to decode null values
Browse files Browse the repository at this point in the history
  • Loading branch information
fluidsonic committed Apr 3, 2019
1 parent b91b3ac commit 757c98d
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 38 deletions.
59 changes: 29 additions & 30 deletions coding/sources/JSONCodingParser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ package com.github.fluidsonic.fluid.json
import java.io.Reader


interface JSONCodingParser : JSONParser {
interface JSONCodingParser<out Context : JSONCodingContext> : JSONParser {

fun createDecoder(source: JSONReader): JSONDecoder<Context>


override fun parseList(source: JSONReader, withTermination: Boolean) =
parseValueOfType<List<*>>(source, withTermination = withTermination)
Expand All @@ -13,7 +16,12 @@ interface JSONCodingParser : JSONParser {
parseValueOfType<Map<String, *>>(source, withTermination = withTermination)


fun <Value : Any> parseValueOfTypeOrNull(source: JSONReader, valueType: JSONCodingType<Value>, withTermination: Boolean = true): Value?
fun <Value : Any> parseValueOfType(source: JSONReader, valueType: JSONCodingType<Value>, withTermination: Boolean = true) =
createDecoder(source).withTermination(withTermination) { readValueOfType(valueType) }


fun <Value : Any> parseValueOfTypeOrNull(source: JSONReader, valueType: JSONCodingType<Value>, withTermination: Boolean = true) =
createDecoder(source).withTermination(withTermination) { readValueOfTypeOrNull(valueType) }


override fun parseValueOrNull(source: JSONReader, withTermination: Boolean) =
Expand Down Expand Up @@ -42,7 +50,7 @@ interface JSONCodingParser : JSONParser {

interface BuilderForDecoding<Context : JSONCodingContext> {

fun decodingWith(factory: (source: JSONReader, context: Context) -> JSONDecoder<Context>): Builder
fun decodingWith(factory: (source: JSONReader, context: Context) -> JSONDecoder<Context>): Builder<Context>


fun decodingWith(
Expand Down Expand Up @@ -77,16 +85,16 @@ interface JSONCodingParser : JSONParser {
}


interface Builder {
interface Builder<out Context : JSONCodingContext> {

fun build(): JSONCodingParser
fun build(): JSONCodingParser<Context>
}


private class BuilderImpl<out Context : JSONCodingContext>(
private val context: Context,
private val decoderFactory: (source: JSONReader, context: Context) -> JSONDecoder<Context>
) : Builder {
) : Builder<Context> {

override fun build() =
StandardCodingParser(
Expand All @@ -98,7 +106,7 @@ interface JSONCodingParser : JSONParser {
}


fun JSONCodingParser.parseValue(source: JSONReader, withTermination: Boolean = true) =
fun JSONCodingParser<*>.parseValue(source: JSONReader, withTermination: Boolean = true) =
parseValueOrNull(source, withTermination = withTermination)
?: throw JSONException.Schema(
message = "Unexpected null value at top-level",
Expand All @@ -107,66 +115,57 @@ fun JSONCodingParser.parseValue(source: JSONReader, withTermination: Boolean = t
)


fun JSONCodingParser.parseValue(source: Reader, withTermination: Boolean = true) =
fun JSONCodingParser<*>.parseValue(source: Reader, withTermination: Boolean = true) =
parseValue(JSONReader.build(source), withTermination = withTermination)


fun JSONCodingParser.parseValue(source: String) =
fun JSONCodingParser<*>.parseValue(source: String) =
parseValue(JSONReader.build(source))


inline fun <reified Value : Any> JSONCodingParser.parseValueOfType(source: JSONReader, withTermination: Boolean = true): Value =
inline fun <reified Value : Any> JSONCodingParser<*>.parseValueOfType(source: JSONReader, withTermination: Boolean = true): Value =
parseValueOfType(source, valueType = jsonCodingType(), withTermination = withTermination)


inline fun <reified Value : Any> JSONCodingParser.parseValueOfType(source: Reader, withTermination: Boolean = true): Value =
inline fun <reified Value : Any> JSONCodingParser<*>.parseValueOfType(source: Reader, withTermination: Boolean = true): Value =
parseValueOfType(JSONReader.build(source), withTermination = withTermination)


inline fun <reified Value : Any> JSONCodingParser.parseValueOfType(source: String): Value =
inline fun <reified Value : Any> JSONCodingParser<*>.parseValueOfType(source: String): Value =
parseValueOfType(JSONReader.build(source))


fun <Value : Any> JSONCodingParser.parseValueOfType(source: JSONReader, valueType: JSONCodingType<Value>, withTermination: Boolean = true) =
parseValueOfTypeOrNull(source, valueType = valueType, withTermination = withTermination)
?: throw JSONException.Schema(
message = "Unexpected null value at top-level",
offset = source.offset,
path = source.path
)


fun <Value : Any> JSONCodingParser.parseValueOfType(source: Reader, valueType: JSONCodingType<Value>, withTermination: Boolean = true) =
fun <Value : Any> JSONCodingParser<*>.parseValueOfType(source: Reader, valueType: JSONCodingType<Value>, withTermination: Boolean = true) =
parseValueOfType(JSONReader.build(source), valueType = valueType, withTermination = withTermination)


fun <Value : Any> JSONCodingParser.parseValueOfType(source: String, valueType: JSONCodingType<Value>): Value =
fun <Value : Any> JSONCodingParser<*>.parseValueOfType(source: String, valueType: JSONCodingType<Value>): Value =
parseValueOfType(JSONReader.build(source), valueType = valueType)


inline fun <reified Value : Any> JSONCodingParser.parseValueOfTypeOrNull(source: JSONReader, withTermination: Boolean = true): Value? =
inline fun <reified Value : Any> JSONCodingParser<*>.parseValueOfTypeOrNull(source: JSONReader, withTermination: Boolean = true): Value? =
parseValueOfTypeOrNull(source, valueType = jsonCodingType(), withTermination = withTermination)


inline fun <reified Value : Any> JSONCodingParser.parseValueOfTypeOrNull(source: Reader, withTermination: Boolean = true): Value? =
inline fun <reified Value : Any> JSONCodingParser<*>.parseValueOfTypeOrNull(source: Reader, withTermination: Boolean = true): Value? =
parseValueOfTypeOrNull(JSONReader.build(source), withTermination = withTermination)


inline fun <reified Value : Any> JSONCodingParser.parseValueOfTypeOrNull(source: String): Value? =
inline fun <reified Value : Any> JSONCodingParser<*>.parseValueOfTypeOrNull(source: String): Value? =
parseValueOfTypeOrNull(JSONReader.build(source))


fun <Value : Any> JSONCodingParser.parseValueOfTypeOrNull(source: Reader, valueType: JSONCodingType<Value>, withTermination: Boolean = true): Value? =
fun <Value : Any> JSONCodingParser<*>.parseValueOfTypeOrNull(source: Reader, valueType: JSONCodingType<Value>, withTermination: Boolean = true): Value? =
parseValueOfTypeOrNull(JSONReader.build(source), valueType = valueType, withTermination = withTermination)


fun <Value : Any> JSONCodingParser.parseValueOfTypeOrNull(source: String, valueType: JSONCodingType<Value>): Value? =
fun <Value : Any> JSONCodingParser<*>.parseValueOfTypeOrNull(source: String, valueType: JSONCodingType<Value>): Value? =
parseValueOfTypeOrNull(JSONReader.build(source), valueType = valueType)


fun JSONCodingParser.parseValueOrNull(source: Reader, withTermination: Boolean = true) =
fun JSONCodingParser<*>.parseValueOrNull(source: Reader, withTermination: Boolean = true) =
parseValueOrNull(JSONReader.build(source), withTermination = withTermination)


fun JSONCodingParser.parseValueOrNull(source: String) =
fun JSONCodingParser<*>.parseValueOrNull(source: String) =
parseValueOrNull(JSONReader.build(source))
2 changes: 1 addition & 1 deletion coding/sources/codecs/basic/AnyJSONDecoderCodec.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ object AnyJSONDecoderCodec : AbstractJSONDecoderCodec<Any, JSONCodingContext>()
JSONToken.mapStart -> readValueOfType<Map<*, *>>()
JSONToken.numberValue -> readValueOfType<Number>()
JSONToken.stringValue -> readValueOfType<String>()
else -> error("impossible token: $nextToken")
else -> invalidValueError("unexpected 'null'")
}
}
5 changes: 2 additions & 3 deletions coding/sources/implementations/StandardCodingParser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ package com.github.fluidsonic.fluid.json
internal class StandardCodingParser<out Context : JSONCodingContext>(
private val context: Context,
private val decoderFactory: (source: JSONReader, context: Context) -> JSONDecoder<Context>
) : JSONCodingParser {
) : JSONCodingParser<Context> {

override fun <Value : Any> parseValueOfTypeOrNull(source: JSONReader, valueType: JSONCodingType<Value>, withTermination: Boolean) =
override fun createDecoder(source: JSONReader) =
decoderFactory(source, context)
.withTermination(withTermination) { readValueOfTypeOrNull(valueType) }
}
16 changes: 14 additions & 2 deletions coding/tests/sources/JSONCodingParserTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,23 @@ internal object JSONCodingParserTest {

private inline fun <reified Value : Any> testParseMethod(
expectedValue: Value?,
testBody: JSONCodingParser.(type: JSONCodingType<Value>) -> Value?
testBody: JSONCodingParser<*>.(type: JSONCodingType<Value>) -> Value?
) {
val expectedType = jsonCodingType<Value>()

val parser = object : JSONCodingParser {
val parser = object : JSONCodingParser<JSONCodingContext> {

override fun createDecoder(source: JSONReader) =
error("not called")


override fun <Value : Any> parseValueOfType(source: JSONReader, valueType: JSONCodingType<Value>, withTermination: Boolean): Value {
assert(valueType as JSONCodingType<*>).toBe(expectedType)

@Suppress("UNCHECKED_CAST")
return expectedValue as Value
}


override fun <Value : Any> parseValueOfTypeOrNull(source: JSONReader, valueType: JSONCodingType<Value>, withTermination: Boolean): Value? {
assert(valueType as JSONCodingType<*>).toBe(expectedType)
Expand Down
2 changes: 1 addition & 1 deletion coding/tests/sources/JSONTestSuite.kt
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ internal object JSONTestSuite {

private class TestEnvironment(
val name: String,
val parser: JSONCodingParser,
val parser: JSONCodingParser<*>,
val parserIsRecursive: Boolean
)
}
2 changes: 1 addition & 1 deletion ktor-client/sources/FluidJsonSerializer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import io.ktor.http.content.OutgoingContent


class FluidJsonSerializer(
private val parser: JSONCodingParser = JSONCodingParser.nonRecursive,
private val parser: JSONCodingParser<*> = JSONCodingParser.nonRecursive,
private val serializer: JSONCodingSerializer = JSONCodingSerializer.nonRecursive
) : JsonSerializer {

Expand Down

0 comments on commit 757c98d

Please sign in to comment.