Skip to content

Commit df54cd4

Browse files
committed
fix: incorrect oneof / anyof deserialization logic
1 parent ac150e1 commit df54cd4

File tree

10 files changed

+518
-398
lines changed

10 files changed

+518
-398
lines changed

modules/openapi-generator/src/main/resources/dart-next/lib/src/serialization/container_reflection.mustache

Lines changed: 209 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,55 @@
11
import 'package:{{pubName}}/_internal.dart'hide e;
2+
23
import 'package:collection/collection.dart';
34

45
const $FreeFormObjectReflection =
56
MapReflection(NullableReflection(ObjectReflection()));
67

8+
extension SerializationReflectionExtensions<T> on SerializationReflection<T> {
9+
ModelReflection? getNearestModelReflection({
10+
bool Function(ContainerReflection reflection) shouldVisitChildOf =
11+
defaultShouldVisitChildOf,
12+
}) {
13+
return getNearestReflectionOfType<ModelReflection>(shouldVisitChildOf: shouldVisitChildOf);
14+
}
15+
/// searches serialization reflection tree to find a reflection that matches a given type.
16+
TReflection? getNearestReflectionOfType<
17+
TReflection extends SerializationReflection<Object?>>({
18+
bool Function(ContainerReflection reflection) shouldVisitChildOf =
19+
defaultShouldVisitChildOf,
20+
}) {
21+
return getNearestReflectionWhere(
22+
(reflection) => reflection is TReflection,
23+
shouldVisitChildOf: shouldVisitChildOf,
24+
) as TReflection?;
25+
}
26+
27+
static bool defaultShouldVisitChildOf(
28+
ContainerReflection containerReflection) {
29+
return containerReflection is! ListReflection &&
30+
containerReflection is! SetReflection &&
31+
containerReflection is! MapReflection;
32+
}
33+
34+
SerializationReflection<Object?>? getNearestReflectionWhere(
35+
bool Function(SerializationReflection<Object?> reflection) predicate, {
36+
bool Function(ContainerReflection reflection) shouldVisitChildOf =
37+
defaultShouldVisitChildOf,
38+
}) {
39+
SerializationReflection<Object?> current = this;
40+
while (true) {
41+
if (predicate(current)) {
42+
return current;
43+
}
44+
if (current is ContainerReflection && shouldVisitChildOf(current)) {
45+
current = current.subReflection;
46+
continue;
47+
}
48+
return null;
49+
}
50+
}
51+
}
52+
753
abstract class ContainerReflection<T, TItem> extends PrimitiveReflection<T> {
854
const ContainerReflection(this.subReflection);
955
@@ -29,7 +75,7 @@ class MapReflection<T> extends ContainerReflection<Map<String, T>, T> {
2975
src is Map<String, Object?> &&
3076
src.values
3177
.every((v) => subReflection.canDeserializeFunction(v, context)),
32-
onXml: (context) {
78+
onXml: (context) {
3379
if (src is! XmlNode) {
3480
return false;
3581
}
@@ -448,4 +494,165 @@ class UndefinedWrapperReflection<T>
448494
(src) => subReflection.cloneFunction(src),
449495
);
450496
}
451-
}
497+
}
498+
499+
class XmlReflectionWrapper<T> extends ContainerReflection<T, T>
500+
with HasXmlReflection {
501+
const XmlReflectionWrapper(
502+
super.subReflection, {
503+
required this.xml,
504+
});
505+
506+
final XmlReflection xml;
507+
508+
@override
509+
bool canDeserialize(
510+
Object? src, [
511+
SerializationContext context = const SerializationContext.json(),
512+
]) {
513+
return context.split(
514+
onJson: (context) => subReflection.canDeserializeFunction(src, context),
515+
onXml: (context) {
516+
if (src is MapEntry<XmlReflection, Object?>) {
517+
return subReflection.canDeserializeFunction(
518+
src.value,
519+
context.withXmlContainer(this),
520+
);
521+
}
522+
return subReflection.canDeserializeFunction(
523+
src,
524+
context.withXmlContainer(this),
525+
);
526+
},
527+
);
528+
}
529+
530+
@override
531+
T deserialize(
532+
Object? src, [
533+
SerializationContext context = const SerializationContext.json(),
534+
]) {
535+
return context.split(
536+
onJson: (context) {
537+
return subReflection.deserializeFunction(src, context);
538+
},
539+
onXml: (context) {
540+
if (src is MapEntry<XmlReflection, Object?>) {
541+
return subReflection.deserializeFunction(
542+
src.value,
543+
context.withXmlContainer(this),
544+
);
545+
}
546+
return subReflection.deserializeFunction(
547+
src,
548+
context.withXmlContainer(this),
549+
);
550+
},
551+
);
552+
}
553+
554+
@override
555+
Object? serialize(
556+
T src, [
557+
SerializationContext context = const SerializationContext.json(),
558+
]) {
559+
return context.split(
560+
onJson: (context) => subReflection.serializeFunction(src, context),
561+
onXml: (context) {
562+
return MapEntry(
563+
xml,
564+
subReflection.serializeFunction(
565+
src,
566+
context.withXmlContainer(this),
567+
),
568+
);
569+
},
570+
);
571+
}
572+
573+
@override
574+
T empty() {
575+
return subReflection.emptyFunction();
576+
}
577+
578+
@override
579+
T example([ExampleContext? context]) {
580+
return subReflection.exampleFunction(context);
581+
}
582+
583+
@override
584+
T clone(T src) {
585+
return subReflection.cloneFunction(src);
586+
}
587+
588+
@override
589+
Equality<T> get equality => subReflection.equality;
590+
}
591+
592+
class EnumReflection<T extends Object, TDataType extends Object>
593+
extends ContainerReflection<T, TDataType> {
594+
const EnumReflection(
595+
super.subReflection, {
596+
required this.members,
597+
});
598+
599+
final List<EnumMemberReflection<T, TDataType>> members;
600+
601+
@override
602+
T deserialize(Object? value,
603+
[SerializationContext context = const SerializationContext.json()]) {
604+
final deserialized = subReflection.deserializeFunction(value);
605+
final res = members
606+
.where((element) => element.oasValue == deserialized)
607+
.firstOrNull;
608+
if (res == null) {
609+
throw 'Invalid enum value $value';
610+
}
611+
return res.value;
612+
}
613+
614+
@override
615+
bool canDeserialize(Object? value,
616+
[SerializationContext context = const SerializationContext.json()]) {
617+
if (!subReflection.canDeserializeFunction(value, context)) {
618+
return false;
619+
}
620+
final deserialized = subReflection.deserializeFunction(value, context);
621+
return members.any((element) => element.oasValue == deserialized);
622+
}
623+
624+
@override
625+
Object? serialize(T value,
626+
[SerializationContext context = const SerializationContext.json()]) {
627+
return subReflection.serializeFunction(value as TDataType, context);
628+
}
629+
630+
@override
631+
T empty() {
632+
return subReflection.emptyFunction() as T;
633+
}
634+
635+
@override
636+
T example([ExampleContext? context]) {
637+
context ??= ExampleContext();
638+
final member = members.elementAt(context.random.nextInt(members.length));
639+
return member.value;
640+
}
641+
642+
@override
643+
T clone(T src) {
644+
return subReflection.cloneFunction(src as TDataType) as T;
645+
}
646+
}
647+
648+
class EnumMemberReflection<T, TDataType> {
649+
const EnumMemberReflection({
650+
required this.dartName,
651+
required this.oasValue,
652+
required this.value,
653+
});
654+
655+
final String dartName;
656+
final TDataType oasValue;
657+
final T value;
658+
}

modules/openapi-generator/src/main/resources/dart-next/lib/src/serialization/model_reflection.mustache

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,20 @@ abstract class ModelReflection<T extends Object>
7373
for (final OneOfReflection(
7474
reflection: UndefinedWrapperReflection(subReflection: classReflection)
7575
) in reflection.oneOfs) {
76-
//TODO: this logic is WRONG, classReflection can be UndefinedWrapperReflection
77-
if (classReflection is! ModelReflection) {
76+
final modelReflection = classReflection.getNearestModelReflection();
77+
if (modelReflection == null) {
7878
continue;
7979
}
80-
_aggregatedDiscriminators(classReflection, result);
80+
_aggregatedDiscriminators(modelReflection, result);
8181
}
8282
for (final AnyOfReflection(
8383
reflection: UndefinedWrapperReflection(subReflection: classReflection)
8484
) in reflection.anyOfs) {
85-
//TODO: this logic is WRONG, classReflection can be UndefinedWrapperReflection
86-
if (classReflection is! ModelReflection) {
85+
final modelReflection = classReflection.getNearestModelReflection();
86+
if (modelReflection == null) {
8787
continue;
8888
}
89-
_aggregatedDiscriminators(reflection, result);
89+
_aggregatedDiscriminators(modelReflection, result);
9090
}
9191
}
9292

@@ -113,17 +113,19 @@ abstract class ModelReflection<T extends Object>
113113
for (var element in reflection.properties) {
114114
result[element.oasName] = element;
115115
}
116-
for (var element in reflection.oneOfs) {
117-
final subReflection = element.reflection.subReflection;
118-
if (subReflection is ModelReflection) {
119-
_aggregateProperties(subReflection, result);
116+
for (var oneOf in reflection.oneOfs) {
117+
final modelReflection = oneOf.reflection.getNearestModelReflection();
118+
if (modelReflection == null) {
119+
continue;
120120
}
121+
_aggregateProperties(modelReflection, result);
121122
}
122-
for (var element in reflection.anyOfs) {
123-
final subReflection = element.reflection.subReflection;
124-
if (subReflection is ModelReflection) {
125-
_aggregateProperties(subReflection, result);
123+
for (var anyOf in reflection.anyOfs) {
124+
final modelReflection = anyOf.reflection.getNearestModelReflection();
125+
if (modelReflection == null) {
126+
continue;
126127
}
128+
_aggregateProperties(modelReflection, result);
127129
}
128130
}
129131

modules/openapi-generator/src/main/resources/dart-next/lib/src/serialization/reflection.mustache

Lines changed: 1 addition & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,6 @@ mixin SerializationReflection<T> {
4444
}
4545

4646
mixin InheritanceBasedSerializationReflection<T> on SerializationReflection<T> {
47-
48-
49-
5047
@override
5148
SerializationFunction<bool, Object?> get canDeserializeFunction =>
5249
SerializationFunction(canDeserialize);
@@ -194,65 +191,4 @@ extension type const FunctionWrapper3<TOut, TIn1, TIn2, TIn3>.unsafe(
194191
TOut call(TIn1 value1, TIn2 value2, TIn3 value3) {
195192
return fn(value1, value2, value3) as TOut;
196193
}
197-
}
198-
199-
class EnumReflection<T extends Object, TDataType extends Object> extends ContainerReflection<T, TDataType> {
200-
const EnumReflection(super.subReflection, {
201-
required this.members,
202-
});
203-
204-
final List<EnumMemberReflection<T, TDataType>> members;
205-
206-
@override
207-
T deserialize(Object? value, [SerializationContext context = const SerializationContext.json()]) {
208-
final deserialized = subReflection.deserializeFunction(value);
209-
final res = members.where((element) => element.oasValue == deserialized).firstOrNull;
210-
if (res == null) {
211-
throw 'Invalid enum value $value';
212-
}
213-
return res.value;
214-
}
215-
216-
@override
217-
bool canDeserialize(Object? value, [SerializationContext context = const SerializationContext.json()]) {
218-
if (!subReflection.canDeserializeFunction(value, context)) {
219-
return false;
220-
}
221-
final deserialized = subReflection.deserializeFunction(value, context);
222-
return members.any((element) => element.oasValue == deserialized);
223-
}
224-
225-
@override
226-
Object? serialize(T value, [SerializationContext context = const SerializationContext.json()]) {
227-
return subReflection.serializeFunction(value as TDataType, context);
228-
}
229-
230-
@override
231-
T empty() {
232-
return subReflection.emptyFunction() as T;
233-
}
234-
235-
@override
236-
T example([ExampleContext? context]) {
237-
context ??= ExampleContext();
238-
final member = members.elementAt(context.random.nextInt(members.length));
239-
return member.value;
240-
}
241-
242-
@override
243-
T clone(T src) {
244-
return subReflection.cloneFunction(src as TDataType) as T;
245-
}
246-
}
247-
248-
class EnumMemberReflection<T, TDataType> {
249-
const EnumMemberReflection({
250-
required this.dartName,
251-
required this.oasValue,
252-
required this.value,
253-
});
254-
255-
final String dartName;
256-
final TDataType oasValue;
257-
final T value;
258-
}
194+
}

0 commit comments

Comments
 (0)