Open andreykud opened 1 day ago
Hi, I just ran the generator on the spec you provided and there are no compile-time errors in the generated code.
is the error you are getting a runtime error?
if so, could you post the generated code and the modified code? This will help in understanding what the issue is.
I also don't have any errors on compile, but i have an error on deserialization.
Example string is:
{"type": "a", "optionA1":"optionA1"}
//
// AUTO-GENERATED FILE, DO NOT MODIFY!
//
// ignore_for_file: unused_element
import 'package:test_deserialize_api/src/model/a.dart';
import 'package:test_deserialize_api/src/model/b.dart';
import 'package:test_deserialize_api/src/model/test_type.dart';
import 'package:built_value/built_value.dart';
import 'package:built_value/serializer.dart';
import 'package:one_of/one_of.dart';
part 'test_deserialize.g.dart';
/// TestDeserialize
///
/// Properties:
/// * [type]
/// * [optionA1]
/// * [optionB1]
@BuiltValue()
abstract class TestDeserialize
implements Built<TestDeserialize, TestDeserializeBuilder> {
@BuiltValueField(wireName: r'type')
TestType get type;
// enum typeEnum { a, b, };
/// One Of [A], [B]
OneOf get oneOf;
static const String discriminatorFieldName = r'type';
static const Map<String, Type> discriminatorMapping = {
r'a': A,
r'b': B,
};
TestDeserialize._();
factory TestDeserialize([void updates(TestDeserializeBuilder b)]) =
_$TestDeserialize;
@BuiltValueHook(initializeBuilder: true)
static void _defaults(TestDeserializeBuilder b) => b;
@BuiltValueSerializer(custom: true)
static Serializer<TestDeserialize> get serializer =>
_$TestDeserializeSerializer();
}
extension TestDeserializeDiscriminatorExt on TestDeserialize {
String? get discriminatorValue {
if (this is A) {
return r'a';
}
if (this is B) {
return r'b';
}
return null;
}
}
extension TestDeserializeBuilderDiscriminatorExt on TestDeserializeBuilder {
String? get discriminatorValue {
if (this is ABuilder) {
return r'a';
}
if (this is BBuilder) {
return r'b';
}
return null;
}
}
class _$TestDeserializeSerializer
implements PrimitiveSerializer<TestDeserialize> {
@override
final Iterable<Type> types = const [TestDeserialize, _$TestDeserialize];
@override
final String wireName = r'TestDeserialize';
Iterable<Object?> _serializeProperties(
Serializers serializers,
TestDeserialize object, {
FullType specifiedType = FullType.unspecified,
}) sync* {
yield r'type';
yield serializers.serialize(
object.type,
specifiedType: const FullType(TestType),
);
}
@override
Object serialize(
Serializers serializers,
TestDeserialize object, {
FullType specifiedType = FullType.unspecified,
}) {
final oneOf = object.oneOf;
final result =
_serializeProperties(serializers, object, specifiedType: specifiedType)
.toList();
result.addAll(serializers.serialize(oneOf.value,
specifiedType: FullType(oneOf.valueType)) as Iterable<Object?>);
return result;
}
void _deserializeProperties(
Serializers serializers,
Object serialized, {
FullType specifiedType = FullType.unspecified,
required List<Object?> serializedList,
required TestDeserializeBuilder result,
required List<Object?> unhandled,
}) {
for (var i = 0; i < serializedList.length; i += 2) {
final key = serializedList[i] as String;
final value = serializedList[i + 1];
switch (key) {
case r'type':
final valueDes = serializers.deserialize(
value,
specifiedType: const FullType(TestType),
) as TestType;
result.type = valueDes;
break;
default:
unhandled.add(key);
unhandled.add(value);
break;
}
}
}
@override
TestDeserialize deserialize(
Serializers serializers,
Object serialized, {
FullType specifiedType = FullType.unspecified,
}) {
final result = TestDeserializeBuilder();
Object? oneOfDataSrc;
final serializedList = (serialized as Iterable<Object?>).toList();
final discIndex =
serializedList.indexOf(TestDeserialize.discriminatorFieldName) + 1;
final discValue = serializers.deserialize(serializedList[discIndex],
specifiedType: FullType(String)) as String;
oneOfDataSrc = serialized;
final oneOfTypes = [
A,
B,
];
Object oneOfResult;
Type oneOfType;
switch (discValue) {
case r'a':
oneOfResult = serializers.deserialize(
oneOfDataSrc,
specifiedType: FullType(A),
) as A;
oneOfType = A;
break;
case r'b':
oneOfResult = serializers.deserialize(
oneOfDataSrc,
specifiedType: FullType(B),
) as B;
oneOfType = B;
break;
default:
throw UnsupportedError(
"Couldn't deserialize oneOf for the discriminator value: ${discValue}");
}
result.oneOf = OneOfDynamic(
typeIndex: oneOfTypes.indexOf(oneOfType),
types: oneOfTypes,
value: oneOfResult);
return result.build();
}
}
Code, fixes issue is just adding call '_deserializeProperties' to the deserialize method:
final unhandled = <Object?>[];
_deserializeProperties(
serializers,
serialized,
specifiedType: specifiedType,
serializedList: serializedList,
unhandled: unhandled,
result: result,
);
Hi, I also have one follow up question.
What is correct way to create object Test from example above?
Now I can create TestBuilder class and fill field type. But how correctly fill inherited objects parameters (for example parameter optionA1 for Inherited object A)? TestBuilder has field oneOf. How it should be filled?
Description of the bug
When discriminator used in api specification it seems common fields for inherited objects not filled in dart generator implementation.
It seems generated dart code does not calls method named '_deserializeProperties' in method 'deserialize' (in test.dart). So in generated test.g.dart when _build calls it throws an Exception, because type was not parsed and it is null.
Manual adding call this method to generated code fixes issue
Steps to reproduce
Generate code by specification below
Minimal openapi specification
test-contract.yml
test.yml:
testType.yml:
a.yml:
b.yml:
Annotation used
@Openapi( additionalProperties: AdditionalProperties( pubName: 'test_api', ), inputSpec: InputSpec(path: '../../../common/contract/test-contract.yml'), generatorName: Generator.dio, runSourceGenOnOutput: true, outputDirectory: '../generated/test_api')
Expected behavior
Generator should generate without errors
Logs
No response
Screenshots
No response
Platform
Windows
Library version
6.0.0
Flutter version
3.24.3
Flutter channel
stable
Additional context
No response