2016-10-09 2 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

Update

Вопрос 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 - ОК, я пошел вперед и сообщил о проблеме, [Deserializing unclosed object успешно, когда объект имеет параметризованный конструктор. # Одна тысяча тридцать восемь] (https://github.com/JamesNK/Newtonsoft.Json/issues/1038). – dbc

+1

О, я был в процессе, но тогда я остановлюсь. Спасибо за помощь –

Смежные вопросы