Skip to content

Commit fa80500

Browse files
committed
fix(UnionJsonConverter): Fix fallback logic when deserialization fails
When deserializing a union type, if parsing of the preferred type fails, it should fall back to the alternative type. Added the TryDeserialize method for safe parsing attempts, and adjusted the priority judgment between enum and string types in ShouldChooseFirst to ensure correct execution of the fallback logic.
1 parent efb03a6 commit fa80500

File tree

1 file changed

+49
-5
lines changed

1 file changed

+49
-5
lines changed

src/Utils/Union.cs

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -148,16 +148,29 @@ public override Union<T1, T2> Read(ref Utf8JsonReader reader, Type typeToConvert
148148
return new(null);
149149
}
150150

151+
Utf8JsonReader originalReader = reader;
151152
bool preferFirst = TryChooseFirstAdvanced(typeof(T1), typeof(T2), ref reader, options)
152153
?? ShouldChooseFirst(typeof(T1), typeof(T2), reader.TokenType);
153154
if (preferFirst)
154155
{
155-
T1? first = JsonSerializer.Deserialize<T1>(ref reader, options);
156-
return new(first);
156+
if (TryDeserialize(ref reader, options, out T1? first))
157+
{
158+
return new(first);
159+
}
160+
161+
reader = originalReader;
162+
T2? secondFallback = JsonSerializer.Deserialize<T2>(ref reader, options);
163+
return new(secondFallback);
164+
}
165+
166+
if (TryDeserialize(ref reader, options, out T2? second))
167+
{
168+
return new(second);
157169
}
158170

159-
T2? second = JsonSerializer.Deserialize<T2>(ref reader, options);
160-
return new(second);
171+
reader = originalReader;
172+
T1? firstFallback = JsonSerializer.Deserialize<T1>(ref reader, options);
173+
return new(firstFallback);
161174
}
162175

163176
public override void Write(Utf8JsonWriter writer, Union<T1, T2> value, JsonSerializerOptions options)
@@ -322,8 +335,18 @@ private static bool ShouldChooseFirst(Type t1, Type t2, JsonTokenType kind)
322335
{
323336
case JsonTokenType.String:
324337
{
325-
bool t1Match = IsStringLike(t1);
326338
bool t2Match = IsStringLike(t2);
339+
if (t1.IsEnum && t2Match)
340+
{
341+
return true;
342+
}
343+
344+
bool t1Match = IsStringLike(t1);
345+
if (t2.IsEnum && t1Match)
346+
{
347+
return false;
348+
}
349+
327350
return t1Match switch
328351
{
329352
true when !t2Match => true,
@@ -387,6 +410,27 @@ private static bool ShouldChooseFirst(Type t1, Type t2, JsonTokenType kind)
387410
}
388411
}
389412

413+
private static bool TryDeserialize<T>(ref Utf8JsonReader reader, JsonSerializerOptions options, out T? value)
414+
{
415+
Utf8JsonReader copy = reader;
416+
try
417+
{
418+
value = JsonSerializer.Deserialize<T>(ref copy, options);
419+
reader = copy;
420+
return true;
421+
}
422+
catch (JsonException)
423+
{
424+
value = default;
425+
return false;
426+
}
427+
catch (NotSupportedException)
428+
{
429+
value = default;
430+
return false;
431+
}
432+
}
433+
390434
private static Type UnwrapNullable(Type t) => Nullable.GetUnderlyingType(t) ?? t;
391435

392436
private static bool IsDictionaryLike(Type t)

0 commit comments

Comments
 (0)