Skip to content

OneOf with enum string and object variants incorrectly handled #184

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

Open
SolidTux opened this issue Mar 26, 2025 · 0 comments
Open

OneOf with enum string and object variants incorrectly handled #184

SolidTux opened this issue Mar 26, 2025 · 0 comments
Labels
bug Something isn't working

Comments

@SolidTux
Copy link

SolidTux commented Mar 26, 2025

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),
}
@SolidTux SolidTux added the bug Something isn't working label Mar 26, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant