Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fallback to dynamic/guessed types on unknown data #3080

Open
wants to merge 3 commits into
base: spike/overflow-errors-on-pocos
Choose a base branch
from

Conversation

andrzejskowronski
Copy link

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(!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.

But this could also be a DynamicPrimitive - which we could heuristically determine from the fact that there is a _ or a primitive value. But we don't know at this point, so maybe we need a method ToDynamicPrimitive() that switches to a primitive if we discover that later on.

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.

@@ -236,8 +241,10 @@ private void deserializeObjectInto<T>(
{
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.

@@ -342,7 +485,7 @@ FhirJsonPocoDeserializerState state

// 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?

@@ -305,7 +312,7 @@ private void deserializeObjectInto<T>(

try
{
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.

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.

2 participants