2

I´m using the new System.Text.Json library trying to deserialize some json directly into immutable classes.

using System.Collections.Immutable;

public sealed class Book
{
    public int Id { get; }
    public string Name { get; }

    public Book(int id, string name)
    {
        Id = id;
        Name = name;
    }
}

public sealed class Author
{
    public int Id { get; }
    public string Firstname { get; }
    public string Lastname { get; }
    public ImmutableArray<Book> Books { get; }

    public Author(int id, string firstname, string lastname, ImmutableArray<Book> books)
    {
        Id = id;
        Firstname = firstname;
        Lastname = lastname;
        Books = books;
    }
}

By default that objects can´t be constructed by System.Text.Json because they don´t have an empty/default constructor and they don´t have any public setters.

So I started to build custom JsonDecoder<T>s to tell the library how to deserialize.

public class BookConverter : JsonConverter<Book>
{
    public override bool CanConvert(Type typeToConvert)
        => typeToConvert == typeof(Book);

    public override Book Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var rootElement = JsonDocument
            .ParseValue(ref reader)
            .RootElement;

        var id = rootElement.GetProperty(nameof(Book.Id).FirstToLower()).GetInt32();
        var name = rootElement.GetProperty(nameof(Book.Name).FirstToLower()).GetString();

        return new Book(id, name);
    }

    public override void Write(Utf8JsonWriter writer, Book value, JsonSerializerOptions options)
        => throw new NotImplementedException();
}

public class AuthorConverter : JsonConverter<Author>
{
    public override bool CanConvert(Type typeToConvert)
        => typeToConvert == typeof(Author);

    public override Author Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var rootElement = JsonDocument
            .ParseValue(ref reader)
            .RootElement;

        var id = rootElement.GetProperty(nameof(Author.Id).FirstToLower()).GetInt32();
        var firstname = rootElement.GetProperty(nameof(Author.Firstname).FirstToLower()).GetString();
        var lastname = rootElement.GetProperty(nameof(Author.Lastname).FirstToLower()).GetString();
        var books = rootElement.GetProperty(nameof(Author.Books).FirstToLower()).EnumerateArray().Select(e => ~~ ??? ~~).ToImmutableArray();

        return new Author(id, firstname, lastname);
    }

    public override void Write(Utf8JsonWriter writer, Author value, JsonSerializerOptions options)
        => throw new NotImplementedException();
}

But here I got stucked. At the end of deserializing the Author´s books.
How can I reuse that existing JsonDecoder<Book> to deserialize that array of books?
Thank you for your help! :)

dbc
  • 104,963
  • 20
  • 228
  • 340
JakobFerdinand
  • 1,087
  • 7
  • 20

1 Answers1

1

I think I found the answer while reviewing the question. :D

I just extracted the logic into a static function that I can call from the other Converter.

public class BookConverter : JsonConverter<Book>
{
    public override bool CanConvert(Type typeToConvert)
        => typeToConvert == typeof(Book);

    public override Book Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var rootElement = JsonDocument
            .ParseValue(ref reader)
            .RootElement;
        return GetBook(rootElement);
    }

    public static Book GetBook(JsonElement jsonElement)
    {
        var id = jsonElement.GetProperty(nameof(Book.Id).FirstToLower()).GetInt32();
        var name = jsonElement.GetProperty(nameof(Book.Name).FirstToLower()).GetString();

        return new Book(id, name);
    }

    public override void Write(Utf8JsonWriter writer, Book value, JsonSerializerOptions options)
        => throw new NotImplementedException();
}

public class AuthorConverter : JsonConverter<Author>
{
    public override bool CanConvert(Type typeToConvert)
        => typeToConvert == typeof(Author);

    public override Author Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        var rootElement = JsonDocument
            .ParseValue(ref reader)
            .RootElement;

        var id = rootElement.GetProperty(nameof(Author.Id).FirstToLower()).GetInt32();
        var firstname = rootElement.GetProperty(nameof(Author.Firstname).FirstToLower()).GetString();
        var lastname = rootElement.GetProperty(nameof(Author.Lastname).FirstToLower()).GetString();
        var books = rootElement.GetProperty(nameof(Author.Books).FirstToLower()).EnumerateArray().Select(BookConverter.GetBook).ToImmutableArray();

        return new Author(id, firstname, lastname);
    }

    public override void Write(Utf8JsonWriter writer, Author value, JsonSerializerOptions options)
        => throw new NotImplementedException();
}
JakobFerdinand
  • 1,087
  • 7
  • 20