4

This is a question about serialization in general, but in particular I am using ServiceStack's excellent serializers in my .NET code.

Should the deserializers set null references on properties? It seems like currently it ignores null references and just allows such fields to be set according the class's defaults. For example, this test fails:

[TestMethod]
public void Deserialize_WithNullCollection_CollectionIsNull() {
    var serializer = new ServiceStack.Text.TypeSerializer<Foo>();
    Foo item = new Foo() { Strings = null };
    Foo result = serializer.DeserializeFromString(serializer.SerializeToString(item));
    Assert.IsNull(result.Strings);
}
public class Foo {
    public Foo() {
        Strings = new List<string>();
    }
    public List<string> Strings { get; set; }
}

I believe this perhaps this test ought to succeed, but it does not--item.Foo is an empty list rather than a null reference. It seems to me that null references are part of an object's state just like any actual reference is. Am I right or wrong?

Patrick Szalapski
  • 8,738
  • 11
  • 67
  • 129

1 Answers1

4

This is by design.

By default (to save bandwidth) ServiceStack's text serializers don't emit null value on the wire. If there is no null in the generated JSON then the property doesn't get set when its deserialized, which is why it takes the default value given in the constructor.

You can enable null values with:

JsConfig.IncludeNullValues = true;

This is a static (Shared) property, so setting it once should apply globally in the process.

This test passes when using the JsonSerilaizer:

    [Test]
    public void Deserialize_WithNullCollection_CollectionIsNull()
    {
        JsConfig.IncludeNullValues = true;
        var item = new Foo { Strings = null };
        var json = JsonSerializer.SerializeToString(item);
        var result = JsonSerializer.DeserializeFromString<Foo>(json);
        Assert.IsNull(result.Strings);
    }

    public class Foo
    {
        public Foo()
        {
            Strings = new List<string>();
        }
        public List<string> Strings { get; set; }
    }

It doesn't work in JSV-Format (i.e. TypeSerializer) which doesn't support null values, since it can't distinguish it from a "null" string literal. So if you want to use the JSV TypeSerializer you should assume null means the default property values of the type (i.e. as specified in the default constructor).

mythz
  • 141,670
  • 29
  • 246
  • 390
  • Sounds great, but I tried that config setting in the test above, and I get a collection of one string with the value "null"! Seems like a bug in the ServiceStack DeserializeFromString code--or am I missing something? – Patrick Szalapski Aug 02 '12 at 19:04
  • Thanks. Any plans for the TypeSerializer to be able to distinguish null from the string null? – Patrick Szalapski Aug 02 '12 at 20:14
  • Nope, not possible since null without quotes is the "null" string literal on the wire. I've just added a commit to ignore this property for JSV: https://github.com/ServiceStack/ServiceStack.Text/commit/fa46723fe0ea93f04c676aab33d4edc16944193a Personal recommendation is to not rely on the difference, so it's not an artificial complexity you have to remember. – mythz Aug 02 '12 at 20:20
  • I don't think its an artificial complexity--null has a very different meaning than the defaults I define on my classes. Null means "don't know" or "don't care", whereas the default/initialized values usually have a very specific meaning. – Patrick Szalapski Aug 02 '12 at 20:24
  • I'm not saying `null` is not important. You should not be relying on the differences between null and default value populated in the default constructor. IMO the `absence of value` on the wire should be the same as null/default. Note: that's just my personal view on software dev in general, I avoid any possibility for nuances like these to trip-up the future me :) – mythz Aug 02 '12 at 20:27
  • "You should not be relying on the differences between null and default value populated in the default constructor." I think I disagree with that--"null reference" and "default value" represent two very different concepts. But I'd like to hear from other developers. Anyone know of any articles or other questions on the topic? – Patrick Szalapski Aug 02 '12 at 21:08
  • Most schema-less NoSQL data stores operate on that assumption, i.e. an operation on a non-existent collection is equivalent to operating on an empty collection. See http://redis.io for an example. – mythz Aug 02 '12 at 21:09