FirelyTeam / firely-net-sdk

The official Firely .NET SDK for HL7 FHIR
Other
827 stars 344 forks source link

Custom Resource Serialization #2863

Closed Narnian12 closed 1 month ago

Narnian12 commented 1 month ago

Describe the bug When creating custom resources, I can deserialize them properly using a customized ModelInspector, but when I try to serialize it back to a string, it does not seem to serialize any nested custom objects.

To Reproduce Steps to reproduce the behavior:

I created these two custom resources, CustomClaimResponse and CustomPatient

using Hl7.Fhir.Introspection;
using Hl7.Fhir.Model;
using System;
using System.Runtime.Serialization;

namespace CustomResources
{
   [Serializable]
   [DataContract]
   [FhirType( "CustomClaimResponse", "http://hl7.org/fhir/StructureDefinition/CustomClaimResponse", IsResource = true )]
   public class CustomClaimResponse : DomainResource
   {
      public override string TypeName => nameof( CustomClaimResponse );

      [FhirElement( "patient" )]
      [DataMember]
      public CustomPatient? Patient
      {
         get => _Patient;
         set => _Patient = value;
      }
      private CustomPatient? _Patient;

      public override IDeepCopyable DeepCopy() => throw new NotImplementedException();
   }
}
using Hl7.Fhir.Introspection;
using Hl7.Fhir.Model;
using System;
using System.Runtime.Serialization;

namespace CustomResources
{
   [Serializable]
   [DataContract]
   [FhirType( "CustomPatient", "http://hl7.org/fhir/StructureDefinition/CustomPatient", IsResource = true )]
   public class CustomPatient : Patient
   {
      public override string TypeName => nameof( CustomPatient );
   }
}

I then created a simple test to try out deserialization and serialization. The deserialization has both the CustomClaimResponse and CustomPatient populated, but when I serialize back to a string, serializing only the CustomClaimResponse just has an empty CustomClaimResponse object, and I have to serialize the CustomClaimResponse.Patient in order to get the CustomPatient string.

[Fact]
public void TryCustomSerialization()
{
   var modelInspector = new ModelInspector( Hl7.Fhir.Specification.FhirRelease.R4 );
   modelInspector.ImportType( typeof( CustomClaimResponse ) );
   modelInspector.ImportType( typeof( CustomPatient ) );

   var options = new JsonSerializerOptions().ForFhir( modelInspector );

   var customClaimResponseStr = "{\"resourceType\": \"CustomClaimResponse\", \"patient\": { \"resourceType\": \"CustomPatient\", \"name\": [ { \"given\": [ \"Hello\" ] } ] } }";

   // This has everything, including the Patient
   var claimResponse = JsonSerializer.Deserialize<CustomClaimResponse>( customClaimResponseStr, options );

   // {"resourceType":"CustomClaimResponse"}
   var claimResponseStr = JsonSerializer.Serialize( claimResponse, options );
   // {"resourceType":"CustomPatient","name":[{"given":["Hello"]}]}
   var patientStr = JsonSerializer.Serialize( claimResponse.Patient, options );
}

Expected behavior I expected that executing JsonSerializer.Serialize( claimResponse, options); would give me the CustomClaimResponse with the CustomPatient resource nested inside.

I wonder if there is some kind of functionality I will have to support in order to get serialization back to work?

Version used:

Additional context Add any other context about the problem here.

Narnian12 commented 1 month ago

I figured it out! You will need to implement bool TryGetValue(string key, out object value) and IEnumerable<KeyValuePair<string, object>> GetElementPairs() to get the serialization to work :)