Skip to content

Conversation

@andrzejskowronski
Copy link
Contributor

Description

Targets poco branch for ease of viewing just the relevant changes, and will require the other pr.

Related issues

Closes #3050

@ewoutkramer ewoutkramer marked this pull request as ready for review March 19, 2025 13:59
if(choiceMapping is not null)
return (choiceMapping, null);

return (null, ERR.CHOICE_ELEMENT_HAS_UNKOWN_TYPE(ref r, path.GetInstancePath(), propertyMapping.Name, typeSuffix));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should never happen. In fact, the NewPocoBuilder has constants for the classmappings for DynamicDataType, and this will never be null when we use those.

FhirJsonPocoDeserializerState state,
bool stayOnLastToken = false) where T : Base
{
if (reader.TokenType != JsonTokenType.StartObject)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should be more flexible in our thinking: we will only call this function IF we are at an object. I know at this moment we are doing it if we are expecting an object (because of classmappings etc), but since those are just hints now, we should probably never end up in this function if we don't actually see an object on the wire.

}
}

private object? deserializeUnexpectedJsonValue(string propertyName, ref Utf8JsonReader reader, FhirJsonPocoDeserializerState state, bool stayOnLastToken, ClassMapping? propertySuggestion = null)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, I think this is going to be the main workhorse, in fact we could call this straight from the main TryDeserializeResouirce and TryDeserializeObject functions - we're only expecting something, but we're no longer bound to it, so this dynamic function is really nice.

// There might be an existing value, since FhirPrimitives may be spread out over two properties
// (one with, and one without the '_')
var existingValue = propertyMapping.GetValue(target);
target.TryGetValue(propertyMapping.Name, out var existingValue);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that we've moved from using IL (in GetValue) to our generated function now, which might be a bit slower.

…into feature/parsers-overflow-unknown-data

# Conflicts:
#	src/Hl7.Fhir.Base/Serialization/BaseFhirXmlPocoDeserializer.cs
{
state.Path.EnterElement(name, null, choiceType.IsPrimitive);

result = DeserializeFhirPrimitive(value as PrimitiveType, name, choiceType, null, ref reader, new(), state);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not need to be a primitive, right? Choice types can be non-primitives too,

{
state.Path.EnterElement(name, null, choiceType.IsPrimitive);

result = DeserializeFhirPrimitive(value as PrimitiveType, name, choiceType, null, ref reader, new(), state);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What if it is a list?

{
state.Path.EnterElement(propMapping!.Name, !propMapping.IsCollection ? null : 0, propMapping.IsPrimitive);
state.Path.EnterElement(propMapping!.Name, isEnteringJsonArray(ref reader) ? 0 : null, propMapping.IsPrimitive);
deserializePropertyValueInto(target, currentPropertyName, propMapping, propValueMapping!, ref reader, objectParsingState, state);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should try to merge deserializeUnknownPropertiesInto and deserializePropertyValueInto into a single function? (it needs to do the same thing, with "the only difference" that we don't have type information)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe by making sure we always have metadata, but then the metadata for DynamicPrimitive/DynamicType/DynaimcResource etc.

Base automatically changed from spike/overflow-errors-on-pocos to develop-6.0 March 25, 2025 17:11
writer.WritePropertyName(elementName);
SerializePrimitiveValue(value.ObjectValue, writer, requiredType);
}
// Since the object is not null, try overflow, but only if no extension data defined
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dont really understand whats going on, but it looks like we're serializing the contents of the overflow into the primitive element. This is invalid fhir json, so I'd like to understand better which problem we are solving here. It seems the overflow should be put under the _element?

if(!string.IsNullOrEmpty(typeSuffix))
choiceMapping = inspector.FindClassMapping(typeSuffix);

choiceMapping ??= inspector.FindClassMapping(nameof(DynamicDataType));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should introduce a non-null ClassMapping.DynamicDataType property (and use that in the NewPocoBuilder too), so the last line of this function (which will and should never be reached) can be removed.

if(!string.IsNullOrEmpty(typeSuffix))
choiceMapping = inspector.FindClassMapping(typeSuffix);

choiceMapping ??= inspector.FindClassMapping(nameof(DynamicDataType));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should introduce a non-null ClassMapping.DynamicDataType property (and use that in the NewPocoBuilder too), so the last line of this function (which will and should never be reached) can be removed.

}
else if (reader.TokenType == JsonTokenType.StartArray)
{
var peeked = peekTypeNested(ref reader);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to avoid these peeks (since they do cost a bit of time) for the case where we do have a mapping?

[
new { resourceType = nameof(OperationOutcome), crap = 5 }, JsonTokenType.EndObject,
ERR.UNKNOWN_PROPERTY_FOUND_CODE
COVE.INCORRECT_CARDINALITY_MIN_CODE
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will be different again when we integrate Kas's changes.

new { name = "Ewout", _telecom = new object[] { new { system = "phone" }, new { systemX = "b" } } },
checkData, ERR.USE_OF_UNDERSCORE_ILLEGAL_CODE, ERR.UNKNOWN_PROPERTY_FOUND_CODE);
yield return data<ContactDetail>(new { name = new[] { "Ewout" } }, ERR.EXPECTED_PRIMITIVE_NOT_ARRAY_CODE);
checkData);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this use of underscore illegal gone?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed!

Console.WriteLine(recoveredActual);

assertErrors(dfe.Exceptions, [
COVE.LITERAL_INVALID_CODE,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should review this test after Kas's work has been merged, then we can verify the original tests versus the completed one with both your PRs

[DataRow(PERMISSIVEXML, null, POCO_EMPTY_VALUE, POCO_EMPTY_VALUE, DisplayName = "Permissive XML")]
[DataRow(BWCOMPATIBLEXML, POCO_UNKNOWN_ELEMENT, POCO_UNKNOWN_ELEMENT, null, DisplayName = "Backwards-compatible XML")]
[DataRow(POCO_WRONGXML, POCO_EXPECTED_OBJECT, POCO_EXPECTED_OBJECT, POCO_EXPECTED_OBJECT, DisplayName = "Wrong XML")]
[DataRow(BWCOMPATIBLEXML, null, null, null, DisplayName = "Backwards-compatible XML")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't testing much anymore, it was supposed to test the differences between CORREECt/permissive/bw compat etc, but it no longer functions as a good test, we will need to write another one. I will take this up as part of #2878

@@ -1,16 +1,87 @@
{
"resourceType": "Patient",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should manually review the new output (recovered + dumped errors) to verify this after pulling the PR.

Copy link
Member

@ewoutkramer ewoutkramer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're working on this already....

@ewoutkramer
Copy link
Member

Superceded by #3094.

@ewoutkramer ewoutkramer closed this Apr 7, 2025
@ewoutkramer ewoutkramer deleted the feature/parsers-overflow-unknown-data branch April 23, 2025 21:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants