Closed
Description
Description of the bug
When using "one of" fields where some variants are string enums and some are objects, the string enums are never deserialized.
Steps to reproduce
Use oneOf with differntly typed enums. Then the generated code only handles maps in the JSON and not strings.
/// Returns a new [QueueResult] instance and imports its values from
/// [value] if it's a [Map], null otherwise.
// ignore: prefer_constructors_over_static_methods
static QueueResult? fromJson(dynamic value) {
if (value is Map) {
final json = value.cast<String, dynamic>();
// Ensure that the map contains the required keys.
// Note 1: the values aren't checked for validity beyond being non-null.
// Note 2: this code is stripped in release mode!
assert(() {
requiredKeys.forEach((key) {
assert(json.containsKey(key),
'Required key "QueueResult[$key]" is missing from JSON.');
assert(json[key] != null,
'Required key "QueueResult[$key]" has a null value in JSON.');
});
return true;
}());
return QueueResult(
error: mapValueOfType<String>(json, r'error')!,
);
}
return null;
}
Additionally, it has the object variants required fields as non-nullable members:
class QueueResult {
/// Returns a new [QueueResult] instance.
QueueResult({
required this.error,
});
/// Error occurred
String error;
...
}
Minimal openapi specification
{
"openapi": "3.1.0",
"info": {
"title": "test",
"version": "1.0.0"
},
"paths": {
"/status": {
"get": {
"tags": [],
"summary": "Get user status",
"operationId": "get_status",
"responses": {
"200": {
"description": "User status",
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/UserStatus"
}
}
}
}
}
}
}
},
"components": {
"schemas": {
"QueueResult": {
"oneOf": [
{
"type": "string",
"description": "Service not enabled for user",
"enum": [
"not_enabled"
]
},
{
"type": "string",
"description": "Successfully queued",
"enum": [
"success"
]
},
{
"type": "object",
"description": "Error occurred",
"required": [
"error"
],
"properties": {
"error": {
"type": "string",
"description": "Error occurred"
}
}
}
],
"description": "Queue attempt result"
},
"UserStatus": {
"type": "object",
"description": "Status",
"required": [
"server_version",
"enabled"
],
"properties": {
"enabled": {
"type": "boolean",
"description": "Service enabled"
},
"last_result": {
"oneOf": [
{
"type": "null"
},
{
"$ref": "#/components/schemas/QueueResult",
"description": "Result of last queue attempt"
}
]
}
}
}
}
}
}
Annotation used
import 'package:openapi_generator_annotations/openapi_generator_annotations.dart';
@Openapi(
additionalProperties: AdditionalProperties(
pubName: 'test_api',
pubAuthor: 'Daniel Hauck',
),
inputSpec: InputSpec(path: 'openapi.json'),
generatorName: Generator.dart,
outputDirectory: 'api',
)
class TestApi {}
Expected behavior
All variants are correctly deserialized.
Logs
Screenshots
No response
Platform
Linux
Library version
6.1.0
Flutter version
3.23.2
Flutter channel
stable
Additional context
The spec is generated using utoipa from a Rust code similar to the following:
/// Status
#[derive(Debug, Serialize, Deserialize, Clone, ToSchema)]
pub struct UserStatus {
/// Result of last queue attempt
pub last_result: Option<QueueResult>,
/// Service enabled
pub enabled: bool,
}
/// Queue attempt result
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, ToSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueueResult {
/// Service not enabled for user
NotEnabled,
/// Successfully queued
Success,
Error(String),
}