using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Collections.ObjectModel;
using System.Text.Json.Serialization;
public abstract class BookmarkElement
public BookmarkElement() {}
[JsonPropertyName("date_added")]
public string DateAdded { get; set; }
[JsonPropertyName("date_last_used")]
public string DateLastUsed { get; set; }
[JsonPropertyName("guid")]
public string Guid { get; set; }
public string Id { get; set; }
[JsonPropertyName("name")]
public string Name { get; set; }
[JsonPropertyName("type")]
public string Type { get; set; }
public class Bookmark : BookmarkElement
[JsonPropertyName("url")]
public string Url {get; set;}
public class Folder : BookmarkElement
[JsonPropertyName("date_modified")]
public string DateModified { get; set; }
[JsonPropertyName("children")]
public List<BookmarkElement> FolderElements {get; set;}
public class Root : BookmarkElement
[JsonPropertyName("date_modified")]
public string DateModified { get; set; }
[JsonPropertyName("children")]
public List<BookmarkElement> RootFolder { get; set; }
public class BookmarkModel
public BookmarkModel() {}
[JsonPropertyName("checksum")]
public string Checksum { get; set; }
[JsonPropertyName("roots")]
public Dictionary<string, Root> Roots { get; set; }
[JsonPropertyName("version")]
public int Version { get; set; }
public class BookmarkElementConverter : JsonConverter<BookmarkElement>
public override BookmarkElement? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
if(reader.TokenType != JsonTokenType.StartObject)
throw new JsonException();
using (var jsonDocument = JsonDocument.ParseValue(ref reader))
if(!jsonDocument.RootElement.TryGetProperty("type", out var typeProperty))
throw new JsonException();
return typeProperty.GetString() switch
"url" => jsonDocument.RootElement.Deserialize<Bookmark>(options),
"folder" => jsonDocument.RootElement.Deserialize<Folder>(options),
_ => throw new JsonException(),
public override void Write(Utf8JsonWriter writer, BookmarkElement value, JsonSerializerOptions options) =>
JsonSerializer.Serialize(writer, value, value.GetType(), options);
public static void Test()
var options = new JsonSerializerOptions
Converters = { new BookmarkElementConverter() },
var model = JsonSerializer.Deserialize<BookmarkModel>(json, options);
var json2 = JsonSerializer.Serialize(model, options);
Console.WriteLine("Re-serialized {0}", model);
Console.WriteLine(json2);
static string GetJson() =>
"checksum": "cc1f5c62ec7814f7928e2befab26c311",
"date_added": "13335767383821356",
"date_modified": "13335767383821356",
"guid": "efeb5549-612d-4656-8982-a17069075213",
"date_added": "13335767548044529",
"guid": "df7a482b-c1c5-4aa2-af8e-8cee539513d9",
"name": "DuckDuckGo — Privacy, simplified.",
"url": "https://duckduckgo.com/"
"date_added": "13335764354355200",
"date_modified": "13335767548044529",
"guid": "0bc5d13f-2cba-5d74-951f-3f233fe6c908",
"date_added": "13335764354355201",
"guid": "82b081ec-3dd3-529c-8475-ab6c344590dd",
"name": "Other bookmarks",
"date_added": "13335764354355202",
"guid": "4cf2e351-0e85-532b-bb37-df045d8f8d0f",
"name": "Mobile bookmarks",
public static void Main()
Console.WriteLine("Environment version: {0} ({1}), {2}", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription , Environment.Version, Environment.OSVersion);
Console.WriteLine("System.Text.Json version: " + typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");