Polymorphic lists in RavenDB / JSON

Recently I'm doing a lot of playing around with RavenDB, a pure .Net Document database.

By default RavenDB can't handle documents containing lists of different types. That's not exactly RavenDB's fault, as the documents are stored as JSON. One way to solve this, is by providing a custom JsonContractResolver, as Ayende already pointed out.

While using JsonContractResolver definitly works, I think, I would prefer to do this using an attribute. Fortunately Newtonsoft.Json already allows this, so I can do:

public interface IBar
{
}

public class Foo
{
    public string Id { get; set; }

    [JsonConverter(typeof(PolymorphicListConverter))]
    public List<IBar> Bars { get; set; }

    [JsonConverter(typeof(PolymorphicListConverter<List<IBar>>))]
    public IList<IBar> NonConcreteBars { get; set; }

    [JsonConverter(typeof(PolymorphicListConverter))]
    public ArrayList NonGenericBars { get; set; }
}

public class BarMaid: IBar
{
    public string Something { get; set;}
}

public class BarTender: IBar
{
    public string SomethingElse { get; set;}
}

Note that PolymorphicListConverter can take a generic type argument, because it might need to know, what type of list to create on deserialization, if the property doesn't use a concrete type.

The PolymorphicListConvert will now take care of the serialization/deserialization:

public class PolymorphicListConverter<TListType> 
  : PolymorphicListConverter where TListType : class, IList
{
    public PolymorphicListConverter()
        : base(typeof (TListType))
    {
    }
}

public class PolymorphicListConverter : JsonConverter
{
    private readonly Type _explicitListType;

    public PolymorphicListConverter()
    {
    }

    protected PolymorphicListConverter(Type type)
    {
        _explicitListType = type;
    }

    public override void WriteJson(JsonWriter writer, object value,
      JsonSerializer serializer)
    {
        writer.WriteStartArray();
        foreach (var item in (IEnumerable) value)
        {
            writer.WriteStartObject();

            writer.WritePropertyName("CrlType");
            writer.WriteValue(item.GetType().AssemblyQualifiedName);

            writer.WritePropertyName("Value");
            serializer.Serialize(writer, item);

            writer.WriteEndObject();
        }
        writer.WriteEndArray();
    }

    public override object ReadJson(JsonReader reader, 
        Type objectType, object existingValue,
        JsonSerializer serializer)
    {
        var list = (IList) Activator.CreateInstance(
          _explicitListType ?? objectType);

        while (reader.Read())
        {
            if (reader.TokenType == JsonToken.EndArray)
                break;

            reader.Read(); //CrlType prop name
            reader.Read(); //actual type
            var type = Type.GetType((string) reader.Value);
            reader.Read(); // value property
            reader.Read(); // actual value
            list.Add(serializer.Deserialize(reader, type));
            reader.Read(); // end object
        }
        return list;
    }

    public override bool CanConvert(Type objectType)
    {
        var deserializationType = (_explicitListType ?? objectType);
        return typeof (IEnumerable).IsAssignableFrom(objectType) &&
               deserializationType.IsClass && 
               !deserializationType.IsAbstract;
    }
}

Tags , ,

Posted in | Posted on 08 Jun 2010 17:23by Tobi | no comments

XmlTextReader for Delphi

Originally I intended to reimplement some old Delphi 6 projects at work to C#, but finally decided to rather give Delphi 2010 a try. Unfortunately the brain-dead decision of Codegear/Embarcadero to make string/PChar be Unicode types by default made the update a little bit more complicated as expected.

But anyways - while updating the old Delphi code I stumbled upon a small project, which I intended to release as Open Source years ago. Better late then never, here it is:

XmlTextReader for Delphi

XmlTextReader for Delphi is a wrapper around the XmlTextReader interface of the libxml2 library. I very much like the XmlTextReader in .Net for processing large XML files, and the libxml2 XmlTextReader is a very similar kind of beast.

Hope someone finds this useful. Feel free to post bugs and feature requests to the GitHub site!

Tags , ,

Posted in | Posted on 14 Apr 2010 18:11by Tobi | no comments

Keine Patente auf Saatgut und Nutztiere!

Software-Patente sind schon ziemlich übel, aber richtig krank wird es eigentlich erst bei der Patentierung von Leben.

Daher an dieser Stelle mal zwei Links:

www.no-patents-on-seeds.org

www.arche-noah.at

Wer sich in Zukunft nicht ausschließlich von gentechnisch manipulierten Grundnahrungsmitteln aus der Hand weniger Großkonzerne ernähren will, ist herzlich eingeladen, sich an den dortigen Unterschriftendsammlungen zu beteiligen!

Tags ,

| Posted on 15 Mar 2010 15:56by Tobi | no comments

Ruby / Mechanize Cheat Sheet

For a recent article, I've created a Cheat Sheet for Ruby / Mechanize.

You can download it here:

  • Version 2010-01-30 - svg pdf

Creative Commons License
This work is licensed under a Creative Commons Attribution 3.0 Unported License.

Tags ,

Posted in | Posted on 05 Feb 2010 00:00by Tobi | 1 comment

DKB-VISA-READ Version 2010-01-30

Eigentlich brauche ich das Skript zum Auslesen der VISA-Karten-Umsätze der DKB nicht mehr, seit Moneyplex diese Funktion unterstützt, aber für einen Artikel in Ausgabe 4/2010 der c't habe ich das Skript nochmal aus der Versenkung geholt und etwas überarbeitet.

Das ganze ist jetzt hier zu finden : DKB-VISA-READ

Tags ,

Posted in | Posted on 02 Feb 2010 08:00by Tobi | 6 comments