Handle changes in the serialization APIs

This commit is contained in:
Zahary Karadjov 2019-07-08 10:57:05 +03:00
parent 7922a83c4d
commit 73d9e0d458
No known key found for this signature in database
GPG Key ID: C8936F8A3073D609
3 changed files with 30 additions and 23 deletions

View File

@ -17,10 +17,6 @@ type
encounteredField*: cstring encounteredField*: cstring
deserializedType*: cstring deserializedType*: cstring
CustomSerializationError* = object of JsonReaderError
deserializedField*: string
innerException*: ref CatchableError
ExpectedTokenCategory* = enum ExpectedTokenCategory* = enum
etBool = "bool literal" etBool = "bool literal"
etInt = "integer" etInt = "integer"
@ -33,6 +29,10 @@ type
etCurrlyLe = "object start bracket" etCurrlyLe = "object start bracket"
etCurrlyRi = "object end bracket" etCurrlyRi = "object end bracket"
GenericJsonReaderError* = object of JsonReaderError
deserializedField*: string
innerException*: ref CatchableError
UnexpectedToken* = object of JsonReaderError UnexpectedToken* = object of JsonReaderError
encountedToken*: TokKind encountedToken*: TokKind
expectedToken*: ExpectedTokenCategory expectedToken*: ExpectedTokenCategory
@ -46,8 +46,8 @@ method formatMsg*(err: ref UnexpectedField, filename: string): string =
method formatMsg*(err: ref UnexpectedToken, filename: string): string = method formatMsg*(err: ref UnexpectedToken, filename: string): string =
fmt"{filename}({err.line}, {err.col}) Unexpected token '{err.encountedToken}' in place of '{err.expectedToken}'" fmt"{filename}({err.line}, {err.col}) Unexpected token '{err.encountedToken}' in place of '{err.expectedToken}'"
method formatMsg*(err: ref CustomSerializationError, filename: string): string = method formatMsg*(err: ref GenericJsonReaderError, filename: string): string =
fmt"{filename}({err.line}, {err.col}) Custom serialization exception while deserializing '{err.deserializedField}': [{err.innerException.name}] {err.innerException.msg}" fmt"{filename}({err.line}, {err.col}) Exception encountered while deserializing '{err.deserializedField}': [{err.innerException.name}] {err.innerException.msg}"
template init*(T: type JsonReader, stream: ByteStreamVar, mode = defaultJsonMode): auto = template init*(T: type JsonReader, stream: ByteStreamVar, mode = defaultJsonMode): auto =
init JsonReader, AsciiStreamVar(stream), mode init JsonReader, AsciiStreamVar(stream), mode
@ -70,10 +70,12 @@ proc raiseUnexpectedField(r: JsonReader, fieldName, deserializedType: cstring) =
ex.deserializedType = deserializedType ex.deserializedType = deserializedType
raise ex raise ex
proc readValueFailed*(r: JsonReader, proc handleReadException*(r: JsonReader,
Record: type, fieldName: string, field: var auto, Record: type,
err: ref CatchableError) = fieldName: string,
var ex = new CustomSerializationError field: var auto,
err: ref CatchableError) =
var ex = new GenericJsonReaderError
ex.assignLineNumber(r) ex.assignLineNumber(r)
ex.deserializedField = fieldName ex.deserializedField = fieldName
ex.innerException = err ex.innerException = err

View File

@ -125,6 +125,8 @@ proc writeArray[T](w: var JsonWriter, elements: openarray[T]) =
writeIterable(w, elements) writeIterable(w, elements)
proc writeValue*(w: var JsonWriter, value: auto) = proc writeValue*(w: var JsonWriter, value: auto) =
mixin enumInstanceSerializedFields
template addChar(c) = template addChar(c) =
append c append c
@ -161,7 +163,6 @@ proc writeValue*(w: var JsonWriter, value: auto) =
# TODO: Should this really use a decimal representation? # TODO: Should this really use a decimal representation?
# Or perhaps $ord(c) returns hex? # Or perhaps $ord(c) returns hex?
# This is potentially a bug in Nim's json module. # This is potentially a bug in Nim's json module.
# In any case, we can call appendNumber here.
append $ord(c) append $ord(c)
of '\\': addPrefixSlash '\\' of '\\': addPrefixSlash '\\'
else: addChar c else: addChar c
@ -170,16 +171,16 @@ proc writeValue*(w: var JsonWriter, value: auto) =
elif value is bool: elif value is bool:
append if value: "true" else: "false" append if value: "true" else: "false"
elif value is enum: elif value is enum:
w.stream.appendNumber ord(value) w.stream.append $ord(value)
elif value is SomeInteger: elif value is SomeInteger:
w.stream.appendNumber value w.stream.append $value
elif value is SomeFloat: elif value is SomeFloat:
append $value append $value
elif value is (seq or array): elif value is (seq or array):
w.writeArray(value) w.writeArray(value)
elif value is (object or tuple): elif value is (object or tuple):
w.beginRecord(type(value)) w.beginRecord(type(value))
value.serializeFields(k, v): value.enumInstanceSerializedFields(k, v):
w.writeField k, v w.writeField k, v
w.endRecord() w.endRecord()
else: else:

View File

@ -1,5 +1,6 @@
import import
strutils, unittest, strutils, unittest,
serialization/object_serialization,
serialization/testing/generic_suite, serialization/testing/generic_suite,
../json_serialization, ./utils, ../json_serialization, ./utils,
../json_serialization/std/[options, sets] ../json_serialization/std/[options, sets]
@ -12,10 +13,11 @@ type
x: int x: int
y: string y: string
distance: Meter distance: Meter
ignored: int
Foo = object Foo = object
i: int i: int
b: Bar b {.dontSerialize.}: Bar
s: string s: string
Bar = object Bar = object
@ -41,6 +43,8 @@ template reject(code) =
borrowSerialization(Meter, int) borrowSerialization(Meter, int)
Simple.setSerializedFields distance, x, y
proc `==`(lhs, rhs: Meter): bool = proc `==`(lhs, rhs: Meter): bool =
int(lhs) == int(rhs) int(lhs) == int(rhs)
@ -74,21 +78,21 @@ suite "toJson tests":
var s = Simple(x: 10, y: "test", distance: Meter(20)) var s = Simple(x: 10, y: "test", distance: Meter(20))
check: check:
s.toJson == """{"x":10,"y":"test","distance":20}""" s.toJson == """{"distance":20,"x":10,"y":"test"}"""
s.toJson(typeAnnotations = true) == """{"$type":"Simple","x":10,"y":"test","distance":20}""" s.toJson(typeAnnotations = true) == """{"$type":"Simple","distance":20,"x":10,"y":"test"}"""
s.toJson(pretty = true) == dedent""" s.toJson(pretty = true) == dedent"""
{ {
"distance": 20,
"x": 10, "x": 10,
"y": "test", "y": "test"
"distance": 20
} }
""" """
test "handle missing fields": test "handle missing fields":
let json = dedent""" let json = dedent"""
{ {
"y": "test", "distance": 20,
"distance": 20 "y": "test"
} }
""" """
@ -135,8 +139,8 @@ suite "toJson tests":
h1 = HoldsOption(o: some Simple(x: 1, y: "2", distance: Meter(3))) h1 = HoldsOption(o: some Simple(x: 1, y: "2", distance: Meter(3)))
h2 = HoldsOption(r: newSimple(1, "2", Meter(3))) h2 = HoldsOption(r: newSimple(1, "2", Meter(3)))
Json.roundtripTest h1, """{"r":null,"o":{"x":1,"y":"2","distance":3}}""" Json.roundtripTest h1, """{"r":null,"o":{"distance":3,"x":1,"y":"2"}}"""
Json.roundtripTest h2, """{"r":{"x":1,"y":"2","distance":3},"o":null}""" Json.roundtripTest h2, """{"r":{"distance":3,"x":1,"y":"2"},"o":null}"""
test "Set types": test "Set types":
type HoldsSet = object type HoldsSet = object