접속 속성을 가진 객체를 System.Text.Json으로 역직렬화 하기
이철우
객체지향 언어 C++의 헤더 파일이 중복이라는 생각도 C#을 시작하게 된 계기였다. 구현은 추상에 의존해야 한다는 의존성 역전의 원칙에 따라 프로그래밍하니, 접속(interface)을 많이 작성하게 된다. 한편으로 접속은 C++의 헤더 파일을 떠올리게 한다.
접속 속성을 가진 객체를 System.Text.Json으로 역직렬화 하면 예외가 발생한다. 이를 해결하는 방법을 [참고 1]에서 찾았고 이를 소개한다.
이름과 생일을 속성으로 가진 클래스 사람(Person)을 만들자. 속성 이름의 데이터 유형은 접속 IName이다. IName을 상속받아 클래스 PersonName을 만들자.
internal interface IName
{
string Name { get; }
}
internal class PersonName : IName
{
public PersonName(string name)
{
Name = name;
}
public string Name { get; init; }
public override string ToString()
{
return $"{Name}";
}
}
internal class Person
{
public Person() { }
public Person(IName name, DateOnly birthday)
{
Name = name;
Birthday = birthday;
}
public IName Name { get; init; }
public DateOnly Birthday { get; init; }
public override string ToString()
{
return $"{Name} {Birthday}";
}
}
이를 system.text.json을 이용하여 직열화, 역직열화 해보자.
var person = new Person { Name = new PersonName("Hong Gil Dong"), Birthday = new DateOnly(2024, 11, 24) };
var jsonString = JsonSerializer.Serialize(person);
Console.WriteLine(jsonString);
var jsonObject = JsonSerializer.Deserialize<Person>(jsonString);
Console.WriteLine($"{jsonObject}");
역직열화에서 다음과 같은 예외가 발생한다.
Deserialization of interface or abstract types is not supported.
이를 해결하기 위해 [참고 1]의 클래스를 추가하자.
public class TypeMappingConverter<TType, TImplementation> : JsonConverter<TType>
where TImplementation : TType
{
[return: MaybeNull]
public override TType Read(
ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) =>
JsonSerializer.Deserialize<TImplementation>(ref reader, options);
public override void Write(
Utf8JsonWriter writer, TType value, JsonSerializerOptions options) =>
JsonSerializer.Serialize(writer, (TImplementation)value!, options);
}
그리고 역직열화 부분을 아래와 같이 고치자.
var options = new JsonSerializerOptions
{
Converters =
{
new TypeMappingConverter<IName, PersonName>()
}
};
var jsonObject = JsonSerializer.Deserialize<Person>(jsonString, options);
Console.WriteLine($"{jsonObject}");
역직렬화가 잘 됨을 알 수 있다.
[참고 1] Serialize objects implementing interface with System.Text.Json