2016-10-09 94 views
5

我遇到了一個奇怪的問題:給出這樣的字符串{"text":"s","cursorPosition":189,"dataSource":"json_northwind",這不是一個正確的json,它仍然得到了成功解析。Newtonsoft.Json解析不正確的json

這是類:

public class CompletionDataRequest 
{ 
    public CompletionDataRequest(string text, int cursorPosition, string dataSource, string project) 
    { 
     Text = text; 
     CursorPosition = cursorPosition; 
     DataSource = dataSource; 
     Project = project; 
    } 

    public string Text { get; } 
    public int CursorPosition { get; } 
    public string DataSource { get; } 
    public string Project { get; } 
} 

下面是測試出奇成功:

var s = @"{""text"":""s"",""cursorPosition"":189,""dataSource"":""json_northwind"","; 
var request = JsonConvert.DeserializeObject<CompletionDataRequest>(s); 
request.Text.Should().Be("s"); 
request.CursorPosition.Should().Be(189); 
request.DataSource.Should().Be("json_northwind"); 
request.Project.Should().BeNull(); 

圖書館有一些鬆動解析規則或也許這是一個錯誤?我庫版本9.0.1

回答

5

更新

一個問題Deserializing unclosed object succeeds when the object has a parameterized constructor. #1038打開了這個問題。它被修改在Json.NET release 10.0.1的變更集0721bd4中。

原來的答案

你發現了Json.NET的錯誤。它只有在你的對象用參數化構造函數構造時纔會出現。如果我修改你的對象有一個非參數的構造函數:

public class CompletionDataRequest 
{ 
    public CompletionDataRequest(string text, int cursorPosition, string dataSource, string project) 
    { 
     Text = text; 
     CursorPosition = cursorPosition; 
     DataSource = dataSource; 
     Project = project; 
    } 

    [JsonConstructor] 
    private CompletionDataRequest() 
    { 
    } 

    [JsonProperty] 
    public string Text { get; private set; } 
    [JsonProperty] 
    public int CursorPosition { get; private set; } 
    [JsonProperty] 
    public string DataSource { get; private set; } 
    [JsonProperty] 
    public string Project { get; private set; } 
} 

然後Json.NET將正確地拋出一個JsonSerializationException

錯誤的原因如下。當使用無參數構造函數創建對象時,Json.NET首先構造該對象,然後用JsonSerializerInternalReader.PopulateObject()填充它。此方法具有以下的(簡化的)邏輯:

private object PopulateObject(object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, string id) 
    { 
     bool finished = false; 
     do 
     { 
      switch (reader.TokenType) 
      { 
       case JsonToken.PropertyName: 
       { 
        // Read and process the property. 
       } 
       case JsonToken.EndObject: 
        finished = true; 
        break; 
       case JsonToken.Comment: 
        // ignore 
        break; 
       default: 
        throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType); 
      } 
     } while (!finished && reader.Read()); 

     if (!finished) 
     { 
      ThrowUnexpectedEndException(reader, contract, newObject, "Unexpected end when deserializing object."); 
     } 

     return newObject; 
    } 

正如你可以看到,有邏輯if (!finished)驗證對象實際上被關閉。

然而,創建一個帶有參數的構造函數的對象時,該屬性是隻讀在構造對象之前,使用JsonSerializerInternalReader.ResolvePropertyAndCreatorValues()

private List<CreatorPropertyContext> ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType) 
    { 
     List<CreatorPropertyContext> propertyValues = new List<CreatorPropertyContext>(); 
     bool exit = false; 
     do 
     { 
      switch (reader.TokenType) 
      { 
       case JsonToken.PropertyName: 
        // Read and process the property. 
        break; 
       case JsonToken.Comment: 
        break; 
       case JsonToken.EndObject: 
        exit = true; 
        break; 
       default: 
        throw JsonSerializationException.Create(reader, "Unexpected token when deserializing object: " + reader.TokenType); 
      } 
     } while (!exit && reader.Read()); 

     return propertyValues; 
    } 

正如你可以看到有對exit沒有等效檢查爲真。

爲此打開了一個問題Deserializing unclosed object succeeds when the object has a parameterized constructor. #1038

+0

@Łukasz - 好的,我繼續並報告了這個問題,[當對象具有參數化構造函數時,反序列化unclosed對象成功。 #1038](https://github.com/JamesNK/Newtonsoft.Json/issues/1038)。 – dbc

+1

哦,我正在進行,但我會停止。感謝幫助 –