question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Empty string is treated as null

See original GitHub issue

Source/destination types

namespace QuickType
{
    using System;
    using System.Collections.Generic;

    using System.Globalization;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Converters;

    public partial class TopLevel
    {
        [JsonProperty("bar", Required = Required.DisallowNull, NullValueHandling = NullValueHandling.Ignore)]
        public Bar? Bar { get; set; }
    }

    public enum Bar { Foo, Empty };

    public partial class TopLevel
    {
        public static TopLevel FromJson(string json) => JsonConvert.DeserializeObject<TopLevel>(json, QuickType.Converter.Settings);
    }

    static class BarExtensions
    {
        public static Bar? ValueForString(string str)
        {
	    Console.WriteLine("value for string");
            switch (str)
            {
                case "": Console.WriteLine("empty"); return Bar.Empty;
                case "foo": return Bar.Foo;
                default: return null;
            }
        }

        public static Bar ReadJson(JsonReader reader, JsonSerializer serializer)
        {
            var str = serializer.Deserialize<string>(reader);
            var maybeValue = ValueForString(str);
            if (maybeValue.HasValue) return maybeValue.Value;
            throw new Exception("Unknown enum case " + str);
        }

        public static void WriteJson(this Bar value, JsonWriter writer, JsonSerializer serializer)
        {
            switch (value)
            {
                case Bar.Empty: serializer.Serialize(writer, ""); break;
                case Bar.Foo: serializer.Serialize(writer, "foo"); break;
            }
        }
    }

    public static class Serialize
    {
        public static string ToJson(this TopLevel self) => JsonConvert.SerializeObject(self, QuickType.Converter.Settings);
    }

    internal class Converter: JsonConverter
    {
        public override bool CanConvert(Type t) => t == typeof(Bar) || t == typeof(Bar?);

        public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
        {
            if (t == typeof(Bar))
                return BarExtensions.ReadJson(reader, serializer);
            if (t == typeof(Bar?))
            {
                if (reader.TokenType == JsonToken.Null) return null;
                return BarExtensions.ReadJson(reader, serializer);
            }
            throw new Exception("Unknown type");
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            var t = value.GetType();
            if (t == typeof(Bar))
            {
                ((Bar)value).WriteJson(writer, serializer);
                return;
            }
            throw new Exception("Unknown type");
        }

        public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
        {
            MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
            DateParseHandling = DateParseHandling.None,
            Converters = { 
                new Converter()
            }
        };
    }

    class Program
    {
        static void Main(string[] args)
        {
            var path = args[0];
            var json = System.IO.File.ReadAllText(path);
	    var data = TopLevel.FromJson(json);
	    Console.WriteLine("have data");
            var output = data.ToJson();
            Console.WriteLine("{0}", output);
        }
    }
}

Source/destination JSON

{
        "bar": ""
}

Expected behavior

value for string
empty
have data
{"bar":""}

Actual behavior

value for string
empty

Unhandled Exception: Newtonsoft.Json.JsonSerializationException: Required property 'bar' expects a non-null value. Path '', line 3, position 1.
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.EndProcessProperty(Object newObject, JsonReader reader, JsonObjectContract contract, Int32 initialDepth, JsonProperty property, PropertyPresence presence, Boolean setDefaultValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonConvert.DeserializeObject(String value, Type type, JsonSerializerSettings settings)
   at Newtonsoft.Json.JsonConvert.DeserializeObject[T](String value, JsonSerializerSettings settings)
   at QuickType.TopLevel.FromJson(String json) in /private/tmp/csharp-071760/Program.cs:line 20
   at QuickType.Program.Main(String[] args) in /private/tmp/csharp-071760/Program.cs:line 102

Remarks

It works for {"bar":"foo"}, so the problem seems to be that the string is empty.

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:1
  • Comments:12

github_iconTop GitHub Comments

12reactions
schanicommented, May 11, 2018

Is there any reason this couldn’t be settable in the JsonSerializerSettings?

3reactions
erliscommented, Sep 30, 2019

This is creating a problem for my integration. In the Database we have a field that doesn’t support NULL, and I just noticed the end users are adding empty strings there. When I’m transferring this data to another database, using a service that converts this data into JSON, I got failures on the target table because the column doesn’t accept NULL.

I was thinking that if I have a JSON with a empty string when I deserialize I should get the same value, an empty string.

This looks like a bug on the implementation to me and not in the specification as mentioned before.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Difference between null and empty string [duplicate]
Null means nothing. Its just a literal. Null is the value of reference variable. But empty string is blank.It gives the length=0 ....
Read more >
When to Use NULL and When to Use Empty String
A string refers to a character's sequence. Sometimes strings can be empty or NULL. The difference is that NULL is used to refer...
Read more >
When to use NULL and when to use an empty string?
NULL means absence of value (i.e. there is no value), while empty string means there is a string value of zero length. For...
Read more >
Understanding Null Versus the Empty String
The value null represents the absence of any object, while the empty string is an object of type String with zero characters. If...
Read more >
Empty String Considered Harmful - Sam Jarman
The use of empty strings when used to indicate a null value or lack of value, when the language you're using has a...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found