我一直试图写一个JSON反序列化器一段时间了,但一直无法找到我的错误.为什么牛顿软件告诉我Unexpected token when deserializing object: StartObject,在反序列化后呢?
type ThisFails =
{ a : string * string
m : Map<string, string> }
type ThisWorks =
{ y : Map<string, string>
z : string * string }
testCase "failing test - array before object" <| fun _ ->
let res = deserialise<ThisFails> Serialisation.converters
"""{"a":["xyz","zyx"],"m":{}}"""
Assert.Equal("should be eq to res", { a = "xyz", "zyx"; m = Map.empty }, res)
testCase "passing test - array after object" <| fun _ ->
let res = deserialise<ThisWorks> Serialisation.converters
"""{"y":{},"z":["xyz","zyx"]}"""
Assert.Equal("should be eq to res", { y = Map.empty; z = "xyz", "zyx" }, res)
Run Code Online (Sandbox Code Playgroud)
该转换器的痕迹是:
reading json [Newtonsoft.Json.FSharp.TupleArrayConverter]
type => System.Tuple`2[System.String,System.String]
value token, pre-deserialise [Newtonsoft.Json.FSharp.TupleArrayConverter]
path => "a[0]"
token_type => String
value token, post-deserialise [Newtonsoft.Json.FSharp.TupleArrayConverter]
path => "a[1]"
token_type => String
value token, pre-deserialise [Newtonsoft.Json.FSharp.TupleArrayConverter]
path => "a[1]"
token_type => String
value token, post-deserialise [Newtonsoft.Json.FSharp.TupleArrayConverter]
path => "a"
token_type => EndArray
after EndArray token, returning [Newtonsoft.Json.FSharp.TupleArrayConverter]
path => "m"
token_type => PropertyName
Run Code Online (Sandbox Code Playgroud)
在转换器中,我正在使用最后一个令牌,即结束数组,正如您在终止案例中看到的那样:
match reader.TokenType with
| JsonToken.EndArray ->
read JsonToken.EndArray |> req |> ignore
acc
Run Code Online (Sandbox Code Playgroud)
而我在开始时正在使用StartArray令牌......
那么:为什么这段代码不起作用?(Newtonsoft.Json 6.0.8)
这是错误:
map tests/failing test - array before object: Exception: Newtonsoft.Json.JsonSerializationException: Unexpected token when deserializing object: StartObject. Path 'm', line 1, position 24.
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndCreatorValues (Newtonsoft.Json.Serialization.JsonObjectContract contract, Newtonsoft.Json.Serialization.JsonProperty containerProperty, Newtonsoft.Json.JsonReader reader, System.Type objectType, IDictionary`2& extensionData) [0x00000] in <filename unknown>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters (Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonObjectContract contract, Newtonsoft.Json.Serialization.JsonProperty containerProperty, Newtonsoft.Json.Serialization.ObjectConstructor`1 creator, System.String id) [0x00000] in <filename unknown>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject (Newtonsoft.Json.JsonReader reader, Newtonsoft.Json.Serialization.JsonObjectContract objectContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, Newtonsoft.Json.Serialization.JsonProperty containerProperty, System.String id, System.Boolean& createdFromNonDefaultCreator) [0x00000] in <filename unknown>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x00000] in <filename unknown>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal (Newtonsoft.Json.JsonReader reader, System.Type objectType, Newtonsoft.Json.Serialization.JsonContract contract, Newtonsoft.Json.Serialization.JsonProperty member, Newtonsoft.Json.Serialization.JsonContainerContract containerContract, Newtonsoft.Json.Serialization.JsonProperty containerMember, System.Object existingValue) [0x00000] in <filename unknown>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize (Newtonsoft.Json.JsonReader reader, System.Type objectType, Boolean checkAdditionalContent) [0x00000] in <filename unknown>:0 (00:00:00.1500996)
1 tests run: 0 passed, 0 ignored, 0 failed, 1 errored (00:00:00.2482623)
Run Code Online (Sandbox Code Playgroud)
一直在与 JSON.Net 一起调试您的代码。
事实证明,在您EndArray在失败的情况下消耗了令牌后,读者会指向一个PropertyName令牌,这一切都很好。
然后,在转换器完成执行后,JSON.Net 会执行此操作。
} while (!exit && reader.Read());
Run Code Online (Sandbox Code Playgroud)
Read()然后将读取器移至下一个令牌,在失败的情况下,该令牌会StartObject导致解串器失败。
因此,我不是 JSON.Net 的专家,但考虑在 JSON.Net 中提供字符串值的提供程序,我可能不会在转换后推进读者,这意味着读者仍然指向字符串值。沿着同样的思路,在使用数组时将数组值的最后一个标记(即标记)留给读者是有意义的EndArray。
所以我的建议只是这样:
match reader.TokenType with
| JsonToken.EndArray ->
// read JsonToken.EndArray |> req |> ignore
Logger.debug logger <| fun _ ->
LogLine.sprintf
[ "path", reader.Path |> box
"token_type", reader.TokenType |> box ]
"after EndArray token, returning"
acc
Run Code Online (Sandbox Code Playgroud)
这使得我的测试程序:
[<EntryPoint>]
let main argv =
let works = deserialize<ThisWorks> """{"y":{},"z":["xyz","zyx"]}"""
printfn "%A" works
let fails = deserialize<ThisFails> """{"a":["xyz","zyx"],"m":{}}"""
printfn "%A" fails
0
Run Code Online (Sandbox Code Playgroud)
打印
{y = map [];
z = ("xyz", "zyx");}
{a = ("xyz", "zyx");
m = map [];}
Run Code Online (Sandbox Code Playgroud)
希望这可以帮助您解决此错误(您可能已经这样做了)
| 归档时间: |
|
| 查看次数: |
838 次 |
| 最近记录: |