Skip to content

Commit

Permalink
Merge pull request #2981 from FirelyTeam/6.0/2967-better-reflect-shar…
Browse files Browse the repository at this point in the history
…ed-properties

Generalize handling of Base/Conformance properties that changed type
  • Loading branch information
mmsmits authored Dec 3, 2024
2 parents ce56375 + afd7d12 commit 69aa6cc
Show file tree
Hide file tree
Showing 648 changed files with 18,752 additions and 18,270 deletions.
35 changes: 35 additions & 0 deletions src/Hl7.Fhir.Base/CompatibilitySuppressions.xml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,20 @@
<Right>lib/net8.0/Hl7.Fhir.Base.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Hl7.Fhir.Serialization.FhirJsonException.PRIMITIVE_ARRAYS_INCOMPAT_SIZE_CODE</Target>
<Left>lib/net8.0/Hl7.Fhir.Base.dll</Left>
<Right>lib/net8.0/Hl7.Fhir.Base.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Hl7.Fhir.Serialization.FhirJsonException.RESOURCETYPE_UNEXPECTED_CODE</Target>
<Left>lib/net8.0/Hl7.Fhir.Base.dll</Left>
<Right>lib/net8.0/Hl7.Fhir.Base.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>F:Hl7.FhirPath.Functions.EqualityOperators.TypedElementEqualityComparer</Target>
Expand Down Expand Up @@ -246,6 +260,13 @@
<Right>lib/net8.0/Hl7.Fhir.Base.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Hl7.Fhir.Model.Attachment.get_SizeElement</Target>
<Left>lib/net8.0/Hl7.Fhir.Base.dll</Left>
<Right>lib/net8.0/Hl7.Fhir.Base.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Hl7.Fhir.Model.Attachment.get_UrlElement</Target>
Expand Down Expand Up @@ -274,6 +295,20 @@
<Right>lib/net8.0/Hl7.Fhir.Base.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Hl7.Fhir.Model.Bundle.LinkComponent.get_RelationElement</Target>
<Left>lib/net8.0/Hl7.Fhir.Base.dll</Left>
<Right>lib/net8.0/Hl7.Fhir.Base.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Hl7.Fhir.Model.Meta.get_ProfileElement</Target>
<Left>lib/net8.0/Hl7.Fhir.Base.dll</Left>
<Right>lib/net8.0/Hl7.Fhir.Base.dll</Right>
<IsBaselineSuppression>true</IsBaselineSuppression>
</Suppression>
<Suppression>
<DiagnosticId>CP0002</DiagnosticId>
<Target>M:Hl7.Fhir.Model.Parameters.get_Item(System.String)</Target>
Expand Down
147 changes: 73 additions & 74 deletions src/Hl7.Fhir.Base/Introspection/FhirElementAttribute.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,95 +38,94 @@ POSSIBILITY OF SUCH DAMAGE.

#nullable enable

namespace Hl7.Fhir.Introspection
namespace Hl7.Fhir.Introspection;

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public sealed class FhirElementAttribute : VersionedValidationAttribute
{
[AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
public sealed class FhirElementAttribute : VersionedValidationAttribute, IFhirVersionDependent
public FhirElementAttribute(string name)
{
public FhirElementAttribute(string name)
{
Name = name ?? throw new ArgumentNullException(nameof(name));
}
Name = name ?? throw new ArgumentNullException(nameof(name));
}

public FhirElementAttribute(string name, ChoiceType choice, XmlRepresentation representation)
{
Name = name;
Choice = choice;
XmlSerialization = representation;
}
public FhirElementAttribute(string name, ChoiceType choice, XmlRepresentation representation)
{
Name = name;
Choice = choice;
XmlSerialization = representation;
}

/// <summary>
/// Whether this element allows instances of more than one type.
/// </summary>
public ChoiceType Choice { get; set; } = ChoiceType.None;

/// <summary>
/// The name of the element in FHIR this property represents.
/// </summary>
public string Name { get; private set; }

/// <summary>
/// The element represents the primitive `value` attribute/property in the FHIR serialization
/// </summary>
public bool IsPrimitiveValue { get; set; }

/// <summary>
/// How this value is represented in XML.
/// </summary>
public XmlRepresentation XmlSerialization { get; set; } = XmlRepresentation.None;

public int Order { get; set; }

/// <summary>
/// The order of the element in the Xml representation.
/// </summary>
public bool InSummary { get; set; }

/// <summary>
/// If this modifies the meaning of other elements
/// </summary>
public bool IsModifier { get; set; }

public string FiveWs { get; set; } = string.Empty;

// This attribute is a subclass of ValidationAttribute so that IsValid() is called on every
// FhirElement while validating. This allows us to extend validation into each FhirElement,
// while normally, the .NET validation will only validate one level, but will not recurse
// into each element. This is controllable by the SetValidateRecursively extension of the
// ValidationContext
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
if (validationContext is null) throw new ArgumentNullException(nameof(validationContext));
/// <summary>
/// Whether this element allows instances of more than one type.
/// </summary>
public ChoiceType Choice { get; set; } = ChoiceType.None;

/// <summary>
/// The name of the element in FHIR this property represents.
/// </summary>
public string Name { get; private set; }

/// <summary>
/// The element represents the primitive `value` attribute/property in the FHIR serialization
/// </summary>
public bool IsPrimitiveValue { get; set; }

/// <summary>
/// How this value is represented in XML.
/// </summary>
public XmlRepresentation XmlSerialization { get; set; } = XmlRepresentation.None;

public int Order { get; set; }

/// <summary>
/// The order of the element in the Xml representation.
/// </summary>
public bool InSummary { get; set; }

/// <summary>
/// If this modifies the meaning of other elements
/// </summary>
public bool IsModifier { get; set; }

public string FiveWs { get; set; } = string.Empty;

// This attribute is a subclass of ValidationAttribute so that IsValid() is called on every
// FhirElement while validating. This allows us to extend validation into each FhirElement,
// while normally, the .NET validation will only validate one level, but will not recurse
// into each element. This is controllable by the SetValidateRecursively extension of the
// ValidationContext
protected override ValidationResult? IsValid(object? value, ValidationContext validationContext)
{
if (validationContext is null) throw new ArgumentNullException(nameof(validationContext));

if (value is null) return ValidationResult.Success;
if (value is null) return ValidationResult.Success;

// If we should not validate 'value's elements, return immediately
if (!validationContext.ValidateRecursively()) return ValidationResult.Success;
// If we should not validate 'value's elements, return immediately
if (!validationContext.ValidateRecursively()) return ValidationResult.Success;

var result = new List<ValidationResult>();
var result = new List<ValidationResult>();

if (ReflectionHelper.IsRepeatingElement(value, out var list))
if (ReflectionHelper.IsRepeatingElement(value, out var list))
{
foreach (var element in list)
{
foreach (var element in list)
if (element != null)
{
if (element != null)
{
validateElement(element, validationContext, result);
}
validateElement(element, validationContext, result);
}
}
else
{
validateElement(value, validationContext, result);
}

return result.FirstOrDefault();
}

private void validateElement(object value, ValidationContext validationContext, List<ValidationResult> result)
else
{
DotNetAttributeValidation.TryValidate(value, validationContext.IntoPath(value, validationContext.MemberName ?? Name), result);
validateElement(value, validationContext, result);
}

return result.FirstOrDefault();
}

private void validateElement(object value, ValidationContext validationContext, List<ValidationResult> result)
{
DotNetAttributeValidation.TryValidate(value, validationContext.IntoPath(value, validationContext.MemberName ?? Name), result);
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/Hl7.Fhir.Base/Introspection/PropertyMapping.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public static bool TryCreate(PropertyInfo prop, [NotNullWhen(true)] out Property
var allowedTypes = elementAttr.Choice != ChoiceType.None ? ClassMapping.GetAttribute<AllowedTypesAttribute>(prop, release) : null;

var fhirTypes = allowedTypes?.Types?.Any() == true ?
allowedTypes.Types : new[] { fhirType };
allowedTypes.Types : [fhirType];

var isPrimitive = isAllowedNativeTypeForDataTypeValue(implementingType);

Expand Down
Loading

0 comments on commit 69aa6cc

Please sign in to comment.